Bouncing ball losing height without drag force?

Hello world!

I'm currently going through the 9 chapters of Nature of Code and I have an issue with one exercise. In the "2.4 Intro to friction forces" video, I did everything properly, understood the script and changed it to a single dropping ball with constant gravity being the only factor changing the ball PVector acceleration. Strangely, in both my and Daniel Shiffman sketch, the bouncing ball lose max height at each 2 rebound. He does not adress this issue.

This is very weird and should not happen?!? since there is nothing that should make the ball lose velocity on each 2 rebounds. My guess is that there is something I don't know about the edgeBounce() I made and how it interact with the window borders, maybe chipping away a pixel of height in the process of reverting the ball velocity when it touches the ground.

The code below work properly, but I think the fault reside somewhere in it or in how it interact with the ball.

void edgeBounce() {
  if (location.x > width) {
    location.x = width;
    velocity.x *= -1;
  }
  if (location.x < 0) {
    location.x = 0;
    velocity.x *= -1;
  }
  if (location.y > height) {
    location.y = height;
    velocity.y *= -1;
  }
  if (location.y < 0) {
    location.y = 0;
    velocity.y *= -1;
  }

Can anyone help me on this? Why is the ball losing velocity at each secound bounce? Google drive link to my sketch, you can visualise the problem yourself!

https://drive.google.com/open?id=1yrXe4HzpJoNk_WAZoUy24jcRY_TjHli4

Any help very appreciated!

Tagged:

Answers

  • edited February 2018

    there is a lot going on:

    updateBall() is changing velocity: velocity.add(acceleration);

    acceleration is changed in applyForce

    and applyForce is called with gravity in draw()

    so gravity still has big influence in your code

    full sketch:

    // Felix Desrosiers-Dorval
    // Vector Lesson 10
    // Friction
    
    // Felix Desrosiers-Dorval
    // Vector Lesson 10
    // Friction
    
    /** Friction and drag are almost the same thing, but we talk about friction when two solids slow each other and drag when a
     solid is slowed by either a gas or a liquid. The formula for friction is the following : 
     Friction Force = (-1 * friction coeff * ||N|| * velocity vector normalized magnitude).
    
     The friction coefficient is how strong the friction is between the two objects. Is it ice on ice? Or sand paper and 
     a leather book? ||N|| is the magnitude of the normal force vector. The normal force is the force pushing back up against
     the object that is affected by friction. Finally, -1 and velocity vector normalized magnitude goes together, it gives us
     a direction, which is simply the opposite of the velocity vector direction.
    
     If (-1 * vel vector norm mag) give us friction direction, then (friction coeff * normal force mag) give us the friction
     magnitude. We will control the friction coeff by giving it a value for how strong it is and we will consider the
     "normal" value as being equal to 1 since a bouncing ball is just about pushing back up at 90 degree against gravity. 
     See code in ball tab*/
    
    Mover m;
    
    void setup() {
      size(640, 360);
      m = new Mover();
    }
    
    void draw() {
      background(255);
    
      PVector gravity = new PVector(0, 0.3);
      gravity.mult(m.mass);
      m.applyForce(gravity);
    
      if (mousePressed) {
        PVector friction = m.velocity.copy();  // Get velocity vector
        friction.normalize();                  // Normalize friction vector
        friction.mult(-1);                     // Reverse it
        float c = 0.1;                         // Decide a friction degree of strenght
        friction.mult(c);                      // Mult friction vector by coeff,
        m.applyForce(friction);                // Finally, add the friction force, always of opposite sign of the object vel
      }
      /**Friction slows the object. Also, since the bouncing ball almost never experience friction by sharply bouncing off a 
       flat surface, we do not really have a trigger that tells when to apply friction to the ball. So, in our example, we 
       will pretend that the ball is bouncing inside a tube and that the retract around the bouncing ball when we press the 
       mouse. The ball, still bouncing, experience some friction rubbing up and down the tube, slowing it down.*/
    
      m.updateBall();
      m.edgeBounce();
      m.display();
    }
    
    // ================================================================
    
    class Mover {
    
      PVector location;
      PVector velocity;
      PVector acceleration;
    
      float mass;
    
      Mover() {
        location = new PVector(width / 2, 0);
        velocity = new PVector(0, 0);
        acceleration = new PVector(0, 0);
        mass = 5;
      }
    
      void applyForce(PVector force) {
        PVector f = PVector.div(force, mass);
        acceleration.add(f);
      }
    
      void updateBall() {    
        velocity.add(acceleration);
        location.add(velocity);
        acceleration.mult(0);                // Acceleration is the net forces applied to velocity each frame and should always be reset to 0.
      }
    
      void edgeBounce() {
        if (location.x > width) {
          location.x = width;
          velocity.x *= -1;
        }
        if (location.x < 0) {
          location.x = 0;
          velocity.x *= -1;
        }
        if (location.y > height) {
          location.y = height;
          velocity.y *= -1;
        }
        if (location.y < 0) {
          location.y = 0;
          velocity.y *= -1;
        }
      }
    
      void display() {
        stroke(0);
        strokeWeight(2);
        fill(127);
        ellipse(location.x, location.y, 48, 48);
      }
    }
    
  • Comming back on my old post and still haven't found an answer to it. I forgot to mention that friction is only applied when mouse is pressed, so the loss heppening each 2 bouces is unrelated to friction since I'm not activating it.

  • edited February 2018

    I think (this is a quick guess) your problem might be a combination of a distance round-off during bounds checking and a magic number combination:

    1. In order to prevent the ball from becoming trapped and re-bouncingoutside the boundary, you move the ball back inside a barrier before it bounces, potentially changing the distance traveled:

        location.y = height;
      
    2. Thise means that, for certain initial starting points and math/acceleration combinations that tend to overshoot the boundary, the ball gets a little acceleration "boost" by being relocated up at the bottom of bounce. For a particular magic combination of gravity and mass with your particular starting point -- e.g. gravity 0.30 -- this creates a ball location outside the frame and a corresponding boost every second bounce.

    3. If you change gravity to 0.35, then you will eventually get a boost every frame -- the ball will find a stable height and bounce there forever. Same code, slightly different values, different result, all due to how far offsets happen to make the ball travel outside the frame when it bounces.

    4. if you disable the line location.y = height; then your ball will get no boost -- the offsets outside the frame are lost, and it will gradually bounce lower and lower.

    Eventually it will be moving slowly enough that its bounce distance won't bring it back into the frame, and it will become trapped outside the wall (which is what the location reassignment is supposed to prevent).

    Mover m;
    PVector gravity;
    
    void setup() {
      size(640, 360);
      m = new Mover();
      gravity = new PVector(0, 0.35);   // 0.35 stable, vs 0.30 unstable
      gravity.mult(m.mass);
    }
    
    void draw() {
      background(255);
      m.applyForce(gravity);
      m.updateBall();
      m.edgeBounce();
      m.display();
    }
    
    class Mover { 
      PVector location;
      PVector velocity;
      PVector acceleration;
      float mass;
      Mover() {
        location = new PVector(width / 2, 0);
        velocity = new PVector(0, 0);
        acceleration = new PVector(0, 0);
        mass = 5;
      }
      void applyForce(PVector force) {
        PVector f = PVector.div(force, mass);
        acceleration.add(f);
      }
      void updateBall() {    
        velocity.add(acceleration);
        location.add(velocity);
        acceleration.mult(0);
      }
      void edgeBounce() {
        if (location.y > height) {
          location.y = height; // alternately, disable this line. test with gravity 0.30
          velocity.y *= -1;
        }
      }
      void display() {
        stroke(0);
        strokeWeight(2);
        fill(127);
        ellipse(location.x, location.y, 48, 48);
      }
    }
    
  • I can't see what you mean.

    Does it occur in this code too?

    Mover m;
    PVector gravity = new PVector(0, 0.3);
    
    void setup() {
      size(640, 360);
      m = new Mover();
    }
    
    void draw() {
      background(255);
    
      m.updateBall();
      m.edgeBounce();
      m.display();
    }
    
    // ================================================================
    
    class Mover {
    
      PVector location;
      PVector velocity;
      PVector acceleration;
    
      float mass;
    
      //constr
      Mover() {
        location = new PVector(width / 2, 0);
        velocity = new PVector(0, 0);
        acceleration = new PVector(0, 0);
        mass = 5.0;
        stroke(0);
        strokeWeight(2);
        fill(127);
        noStroke(); 
        noSmooth();
      } //constr
    
      void updateBall() {
        acceleration=gravity.copy();
        velocity.add(acceleration);
        location.add(velocity);
        // Acceleration is the net forces applied to velocity each frame and should always be reset to 0.
        acceleration=new PVector(0, 0);
      }
    
      void edgeBounce() {
        if (location.y > height-24) {
          location.y = height-24;
          velocity.y = -1*abs(velocity.y);
        }
      }
    
      void display() {
        ellipse(location.x, location.y, 48, 48);
      }
    }//class
    //
    
Sign In or Register to comment.