Better solutions on Bouncing Ball bugging through platform?

Hi :slight_smile:

I want the code below to create a ball that bounces on the bottom of the screen as well as on platforms. The bottom isn’t really the issue here, its just easier to create the problem when including it.

Problem: The ball tends to being slowly suck through the platforms when bouncing against them from below. Only happens occasionally and when Platforms move().

What i found out: I know this problem is rather common. Found an article on the former forum that is about a ball bouncing in a canvas https://forum.processing.org/two/discussion/19877/why-does-the-ball-get-stuck-on-canvas. But either i do not get the solutions or they don’t work out due to the platforms moving.
I think i get why it happens(please confirm if i am right). Due to how the velocity of the ball is created by adding gravity every time to it, the speed varies.
It can happen that it first bounces against the Platform. The next time draw()is executed the Platform moves down as far or further or just a little less than the ball. That way, the bounce() condition is true again, the velocity is reversed and it goes up.

The code so far(fat part is where problem is):

Ball ball = new Ball();
int size = 7;
Platform[] platforms = new Platform[size];
void setup()
{
  size(300, 400);

  for (int i=0; i<size; i++) {
    platforms[i] = new Platform();
  }
}

void draw()
{
  background(23);
  if(keyPressed) {
  ball.move();
  }  
  for (int i=0; i<size; i++) {
    platforms[i].move();
    ball.bounce(platforms[i]);
    platforms[i].display();
  }
  ball.display();
}

class Ball
{
  PVector xy;//current position
  PVector velocity;
  float d;//diameter
  color col;
  float gravity = 9.81/60*d;

  Ball()
  {
    xy = new PVector (100, 150);
    velocity = new PVector (0, 0);
    d = 14;
    col = color(20, 490, 430 );
    gravity = 9.81/60/30;
  }

  void display()
  {
    fill(col);
    ellipse(xy.x, xy.y, d, d);
  }

  void move()
  {
    if (key == 'd') {
      xy.x+=2;
      background(0, 200, 0);
    }
    if (key == 'a')
      xy.x-=2;
  }

  **void bounce(Platform other)**
**  {**
**      if (xy.y >= height||**
**        (((xy.y+d/2 >= other.xy.y) && (xy.y -d/2 <= other.xy.y )) &&//if platform**
**        ((xy.x >= other.xy.x) && (xy.x <= other.xy.x+other.w)))) {**
**        velocity.y = -velocity.y;**
**      } else {**
**        velocity.y += gravity;**
**      }**
**    xy.add(velocity);**
**  }**
}

class Platform
{
  PVector xy;
  color col;
  float w, h;
  float yspeed = 0.6;
  Platform()
  {
    xy = new PVector(random(width), random(height));
    col = color(20, 490, 430 );
    w = 50;
    h = 4;
  }
  void display()
  {
    fill(col);
    rect(xy.x, xy.y, w, h, 2);
  }

  void move()
  {
    xy.y += yspeed;
    if (xy.y >= 400)
      xy.y = 0;
  }
}

What i tried in order to prevent this:
I tried to introduce a variable called check to notice whether the ball bounced the last time draw was called. In that case it should just ignore the bounce. I am still trying around with that solution but it gets kind of difficult because i have to store the check values in some array as i got an array of platforms…
I replaced the fat code(bounce) by this

if ((((xy.y+d/2 >= other.xy.y) && (xy.y -d/2 <= other.xy.y + other.h ))) &&//if platform
      ((xy.x >= other.xy.x) && (xy.x <= other.xy.x+other.w)) &&
      velocity.y<0) {//and velocity smaller zero
      velocity.y = abs(velocity.y);//make speed positive
      xy.y = other.xy.y + other.h + d/2;//set ball position below platform
    } 
    else if ((((xy.y+d/2 >= other.xy.y) && (xy.y -d/2 <= other.xy.y + other.h ))) &&//if platform
      ((xy.x >= other.xy.x) && (xy.x <= other.xy.x+other.w)) &&
      velocity.y>0) {//and velocity positive
      velocity.y = -abs(velocity.y);//make speed negative
      xy.y = other.xy.y - other.h - d/2;//set ball position above platform
    } 
    else if (xy.y >= height) {
      velocity.y = -abs(velocity.y);
    } 
    else {
      velocity.y += gravity;//if speed isnt reversed add gravity
    }
xy.add(velocity);

Problem here: As the position of the ball is changed the maximum height of the ball changes. I also can’t just leave out the position change because if the platforms moves faster than the ball at a specific point, the ball will first hit it with negative velocity, velocity will get positive, the ball will go down and hit the platform that overtook him with positive speed.
Of course i could set the speed and therefore maximum height new every time the ball hits the floor.
But can someone tell me if there is another solution?

Thx

1 Like

Wow! The game feels great so far. I see what you mean with the velocity of the platforms and the ball going up.

So, I know this sounds janky, but in this part of the bounce loop:

if (xy.y >= height ||
        (((xy.y+d / 2 >= other.xy.y) && (xy.y -d / 2 <= other.xy.y )) && //if platform
        ((xy.x >= other.xy.x) && (xy.x <= other.xy.x+other.w)))) {
        velocity.y = -velocity.y;
}

Where you re-change the velocity, I would suggest also resetting the position. The ball, when you reset the velocity at that point, still doesn’t really “know” the platform exists until the next loop. So the frame before, the velocity very likely carried it past the platform.

In the real-world, a ball would compress against the platform and “reverse” it’s velocity, but due to the nature of this more simple bounce, we have to approximate that property by literally saying, “If I’m inside the platform, move me right outside so that I’m not stuck”

2 Likes

This general idea – that you must enforce a hard-stop on the surface to prevent drift, or even at some speeds to prevent the ball from becoming trapped – is (I believe) walked through in these videos:

3 Likes

I need to read through this again to get itxd But Thank you so much for saying that it makes me really happy.

Thank you very much. I knew the coding train already the guy is great i have watched the video and the other one as well…However if you could explain hard stop in the context of my question? When i google it i get to stuff like why do people stop programming…

So i dont get your

…doesn’t it “know” it when the loop is executed and therefore changes direction? feeling like i got a logic error here…or rather what do you mean by going past the platform? being in it or when coming from below already above it¿

So i should maybe previous position(and then velocity as well) store in a variable and set position and velocity back to them in case platform hit. Ill try tomorrow, its what i tried doing in the second code part.

[quote=“tony, post:2, topic:4755, full:true”] n the real-world, a ball would compress against the platform and “reverse” it’s velocity
[/quote] i maybe do that when the rest works

Take a look at this excellent explanation by @quark. He made a simple and straightforward explanation on why this phenomenon happen, and present 3 solutions that you can take to solve the problem. :wink:

2 Likes

This is what i referred to when saying that

I found a solution for myself. They both lead to the maximum height not being changed. Not sure if someone else will have a use of this but code:
Using the height of the ball to determine speed

    //if platform and speed positive
    check = false;
    //if floor
    check = false;

    if(check) {
      //change velocity dependent on height
      velocity.y = +(xy.y-96)/( height/2);
    } else {
      velocity.y = -(xy.y-96)/( height/2);
    }

Change speed proportional to height

//if ball hitting platform from above
if (((xy.y+r/2 >= other.xy.y) && (xy.y -r/2 <= other.xy.y + other.h )) &&
      ((xy.x >= other.xy.x) && (xy.x <= other.xy.x+other.w)) &&
      velocity.y<0) {
      velocity.y = abs(velocity.y);
//The while loops make the move function happen without condition until the ball reaches the position outside of the platform
      while(xy.y >= other.xy.y - other.h - d/2) {
        velocity.y += gravity;
        xy.add(velocity);
    }
    } 
//if ball hitting platform from below
    else if (((xy.y+r/2 >= other.xy.y) && (xy.y -r/2 <= other.xy.y + other.h )) &&
      ((xy.x >= other.xy.x) && (xy.x <= other.xy.x+other.w)) &&
      velocity.y>0) {
      velocity.y = -abs(velocity.y);
     while(xy.y >= other.xy.y - other.h - d/2) {
        velocity.y += gravity;
        xy.add(velocity);
}
    } 

When you move a ball, check for bounds (edge of screen or platform) if needed perform a bounce before the move.

When you move a bound (platform or edge of screen) check for balls and perform a push the balls out of the forbidden area. Don’t bounce the ball, just shove it outside the bound. Now next turn the ball will keep traveling away if that is which way it was already going. This general approach works for changing the bounding box, or moving platforms, teleporting platforms, etc. etc.

1 Like