Sam Chahine
Sam Chahine

Reputation: 620

Stop bouncing ball under gravity from disappearing

I want to simulate a ball bouncing, and in the future create more and make them rebound. This is my code (using p5.js, a processing library for javascript)

var xpos = 200;
var ypos = 450;
var vy = 0;
var gravity = 0.6;
var bounce = -1.00;
var diameter = 30;

function setup() {
    var myCanvas = createCanvas(windowWidth, windowHeight);

    stroke(255);
    noFill();
}

function draw() {
    background(0);

  ellipse(xpos, ypos, diameter, diameter);

  vy += gravity;
  ypos += vy;

  if(ypos > (windowHeight - diameter/2)) {
    vy *= bounce;
  }

}

It looks as if it's working fine, but when the bounce get's really small, it begins to glitch and disappears, here's a codepen. I don't know how to make it just stop and roll or something (obviously not roll if there is no x property, but just stop moving after the bouncing stops)

Any help is appreciated, thank you.

Upvotes: 0

Views: 1209

Answers (2)

Nolo
Nolo

Reputation: 886

You want to first apply acceleration, then do collision tests, then adjust position for collisions.

If you want restitution, apply that to vy after each collision, e.g.

Edit: also using checks to see if an object should be "resting" helps

var xpos = 200;
var ypos = 0;
var vy = 0;
var gravity = 10;
var bounce = 0.9;  // typically represented as a positive normalized value
var diameter = 30;
var sleepTolerance = gravity;  // this will provide a solid result

// KA variables
var windowHeight = height;
var windowWidth = width;

frameRate(30);
var draw = function() {
    background(0);

    ellipse(xpos, ypos, diameter, diameter);

    var asleep = false;

    if(!asleep){
        vy += gravity;
        ypos += vy;
    }

    var heightAboveGround = ypos - (windowHeight - diameter/2);
    if(heightAboveGround > 0) { // remember y is inverted
        // position adjusted for reflection after collision
        // including restitution (resulting from the bounce)
        ypos -= bounce * heightAboveGround;

        // apply restitution to subsequent velocity
        vy *= -bounce;

        if (heightAboveGround <= sleepTolerance && abs(vy) <= sleepTolerance){
            asleep = true;
            ypos = windowHeight - diameter/2;
        }
    }
};

Upvotes: 2

Calvin Belden
Calvin Belden

Reputation: 3104

I was able to more closely simulate a bouncing ball by making two adjustments:

  1. Do not apply gravity if the ball is touching the 'floor' and not moving
  2. Attenuate or decrease the velocity's magnitude during each bounce
  3. Set the velocity to 0 once the magnitude is small enough

Update the bounce:

// Attenuate velocity by making the magnitude of this value < 1
var bounce = -0.9;

// Give initial vy
var vy = 0.1;

And ensure we only add gravity when ball is "in the air" (prevents our ball from "sinking beneath the ground"):

function draw() {
    background(0);

    ellipse(xpos, ypos, diameter, diameter);

    var floor = windowHeight - diameter/2;
    var inAir = ypos <= floor;
    var moving = Math.abs(vy) > 0.01;

    if (inAir && moving) {
        vy += gravity;
    }

    ypos += vy;

    if(!inAir && vy > 0) {
        vy *= bounce;

        if (!moving) {
            vy = 0;
        }
    }
}

Upvotes: 0

Related Questions