Bouncing Ball with Ease-in Motion

edited January 2015 in Hello Processing

Hi, I have been following the Processing tutorials and trying to make a simple bouncing ball sketch combined with an ease-in sketch (without using the mouseX and MouseY) to make a bouncing ball with ease-in motion when the ball approaches to both edges of heights but failed. The closest I got was a ball moves to one direction with ease but couldn't make it move back. I think I must miss some fundamental concept of this. Can anyone point me a direction? Thanks.

Bouncing ball sketch (from processing tutorial)

    float x;
    float y;
    float speed = 5;

    void setup() {
      size(640, 360); 
      noStroke();
    }
    void draw() { 
      background(51);
      y = y + speed;
      if ((y>=height)||(y<=0)) {
        speed =speed*-1;
      }
      ellipse(width/2, y, 66, 66);
    }

Ease in sketch (from processing tutorial)

    float x;
    float y;
    float easing = 0.05;

    void setup() {
      size(640, 360); 
      noStroke();  
    }

    void draw() { 
      background(51);
      float targetX = mouseX;
      float dx = targetX - x;
      if(abs(dx) > 1) {
        x += dx * easing;
      }

      float targetY = mouseY;
      float dy = targetY - y;
      if(abs(dy) > 1) {
        y += dy * easing;
      }  
      ellipse(x, y, 66, 66);
    }

Answers

  • My code

    float x;
    float y;
    float easing = 0.05;
    float velocity;
    
    void setup(){
    size (200,500);
    }
    
    void draw(){
      background(200);
      velocity = height-y;
      y = y + velocity * easing;
      noStroke();
      fill(100,0,0);
      ellipse(x,y,20,20);
      }
    
  • When do you detect when the ball reaches the top or bottom of the frame?

  • Thank you for the reply. I use checkEdge function like Bouncing Ball sketch above by -1. However, the behavior is still not right. 1. I make the easing-1, the ball does bounce back, but it doesn't ease in when it moves back to top. (I feel something is wrong with using easing*-1...) 2. When the ball is at the bottom and accelerating back to the top, it goes from slow to fast, it should be "fast and then slowly ease in.

    I cleaned up the code a little and here is the updated one, thanks

    float x;
    float y;
    float easing = 0.05;
    float velocity;
    
    void setup() {
      size (200, 500);
    }
    
    void draw() {
      background(200);
      update();
      checkEdge();
      display();
    }
    
    void update(){
      velocity = height-y;
      y = y + velocity * easing;
    }
    
    void checkEdge() {
      if ((y>=499)||(y<=0)) { // y never got to height, so I use 499
        easing*=-1;
      }
    }
    
    void display(){
      noStroke();
      fill(100, 0, 0);
      ellipse(width/2, y, 20, 20);
    }
    
  • Well, take a look at this line:

    velocity = height-y;
    

    You're always basing your velocity on the distance from the bottom of the frame: so the higher up the ball is, the faster it will go.

    If you want to slow the ball down when it's closer to the bottom or the top, then you'll have to change your logic. How you do this is up to you, but you might use the distance from the middle instead, or keep track of which way the ball is going and change your velocity accordingly.

  • edited January 2015

    here is another approach

    we have a target (bouncing line) and the ball that follows it. This following is with easing.

    This is bit more like in the example where we have also a target (mouse) and a ellipse / ball position.

    Best, Chrisir ;-)

    float x;
    float y_target=200;  // target 
    float y_toDrawReally;  // the ball really 
    float easing = 0.04;  // 0.04
    float velocity = 9;
    
    void setup() {
      size (200, 800);
    }
    
    void draw() {
      background(200);
      update();
      checkEdge();
      display();
    }
    
    void update() {
    
      y_target = y_target + velocity;
    
      float dy = y_target - y_toDrawReally;
      if (abs(dy) > 18) {
        y_toDrawReally += dy * easing;
      }
    }
    
    void checkEdge() {
      if (y_target>=height+40) { 
        velocity = -abs(velocity);
      }
      else if (y_target<=-40) {
        velocity = abs(velocity);
      }
    }
    
    void display() {
      noStroke();
      fill(100, 0, 0);
      ellipse(width/2, y_toDrawReally, 20, 20);
      stroke(2);
      line (width/2-6, y_target, width/2+6, y_target);
    }
    //
    
  • with 2 dimensions it flies curves

    float x_target=200;  // target
    float y_target=200;  // target
    
    float x_toDrawReally;  // the ball really
    float y_toDrawReally;  // the ball really 
    
    float easing = 0.04;  // 0.04
    
    float velocityX = random (3, 9);
    float velocityY = random (3, 9);
    
    float border = 40; 
    
    void setup() {
      size (700, 800);
    }
    
    void draw() {
      background(200);
      update();
      checkEdge();
      display();
    }
    
    //-----------------------------------------
    
    void update() {
    
      x_target = x_target + velocityX;
      y_target = y_target + velocityY;
    
      float dy = y_target - y_toDrawReally;
      if (abs(dy) > 18) {
        y_toDrawReally += dy * easing;
      }
    
      float dx = x_target - x_toDrawReally;
      if (abs(dx) > 18) {
        x_toDrawReally += dx * easing;
      }
    }
    
    void checkEdge() {
    
      // y_target
      if (y_target>=height+border) { 
        velocityY = -abs(velocityY);
        velocityY += random(.4, .8) * plusOrMinus();
      }
      else if (y_target<=-border) {
        velocityY = abs(velocityY);
        velocityY += random(.4, .8) * plusOrMinus();
      }
    
      // x_target
      if (x_target>=width+border) { 
        velocityX = -abs(velocityX);
        velocityX+=random(.4, .8) * plusOrMinus();
      }
      else if (x_target<=-border) {
        velocityX = abs(velocityX);
        velocityX+=random(.4, .8) * plusOrMinus();
      }
    }
    
    void display() {
      noStroke();
      fill(100, 0, 0);
      ellipse( x_toDrawReally, y_toDrawReally, 20, 20);
    
      stroke(2);
      line (x_target-3, y_target, x_target+3, y_target);
    }
    
    float plusOrMinus() {
      if (random(100)>50) return 1.0; 
      else return -1.0;
    }
    //
    
  • or in 3 dimensions

    float x_target=200;  // target
    float y_target=200;  // target
    float z_target=200;  // target
    
    float x_toDrawReally;  // the ball really
    float y_toDrawReally;  // the ball really 
    float z_toDrawReally;  // the ball really
    
    float easing = 0.04;  // 0.04
    
    float velocityX = random (3, 9);
    float velocityY = random (3, 9);
    float velocityZ = random (3, 9);
    
    float border = 40; 
    
    void setup() {
      size (700, 800, OPENGL);
    }
    
    void draw() {
      //  background(200);
      lights(); 
    
      update();
      checkEdge();
      display();
    }
    
    //-----------------------------------------
    
    void update() {
    
      x_target = x_target + velocityX;
      y_target = y_target + velocityY;
      z_target = z_target + velocityZ;
    
      float dx = x_target - x_toDrawReally;
      if (abs(dx) > 18) {
        x_toDrawReally += dx * easing;
      }
    
      float dy = y_target - y_toDrawReally;
      if (abs(dy) > 18) {
        y_toDrawReally += dy * easing;
      }
    
      float dz = z_target - z_toDrawReally;
      if (abs(dz) > 18) {
        z_toDrawReally += dz * easing;
      }
    }
    
    void checkEdge() {
    
      // y_target
      if (y_target>=height+border) { 
        velocityY = -abs(velocityY);
        velocityY += random(.4, .8) * plusOrMinus();
      }
      else if (y_target<=-border) {
        velocityY = abs(velocityY);
        velocityY += random(.4, .8) * plusOrMinus();
      }
    
      // x_target
      if (x_target>=width+border) { 
        velocityX = -abs(velocityX);
        velocityX+=random(.4, .8) * plusOrMinus();
      }
      else if (x_target<=-border) {
        velocityX = abs(velocityX);
        velocityX+=random(.4, .8) * plusOrMinus();
      }
    
      // z_target
      if (z_target>= 30) {  // in front  
        velocityZ = -abs(velocityZ);
        velocityZ+=random(.4, .8) * plusOrMinus();
      }
      else if (z_target<= -900) { // back 
        velocityZ = abs(velocityZ);
        velocityZ+=random(.4, .8) * plusOrMinus();
      }
    }
    
    void display() {
      noStroke();
      fill(100, 0, 0);
      pushMatrix();
      translate ( x_toDrawReally, y_toDrawReally, z_toDrawReally );
      sphere (29 );
      popMatrix(); 
    
      // stroke(2);
      // line (x_target-3, y_target, x_target+3, y_target);
    }
    
    float plusOrMinus() {
      if (random(100)>50) return 1.0; 
      else return -1.0;
    }
    //
    
  • Thank you KevinWorkman. Ok, keep track of which way the ball is going and change the velocity that I understand but I guess I didn't do it right . And thank you Chrisir, a moving target! YES! I think this is where my logic got stuck! Let me revise it and clear my logic again see if I fully understand this! And the plusOrMinus function which returns a positive or a negative value, learn something new today, great Friday for me! Thank you guys!

  • Hi, I studied for several days and figured what I wanted was more like the type of motion with a sudden acceleration (like someone pushes it while it's not moving). So, I revised my code into the following. I searched the tutorial and got this millis() code which I can give the ball a push every 6 seconds. And I set the target y to 0 and height every 6 seconds so the ball will turn the direction.

    int savedTime;
    int totalTime = 6000;
    float distance;
    float easing = .02;
    float x = 0;
    float y = 0;
    float ty =600;
    
    void setup() {
      size(300, 600);
    }
    
    void draw() {
      background(0);
      distance = ty-y;
      y = y + distance*easing;
      ellipse(width/2, y, 20, 20); 
    
      int passedTime = millis() - savedTime; 
      if (passedTime > totalTime) {
        ty= abs(ty-height);  // ty is at 0 or height 
        savedTime = millis(); 
      }
    }
    
Sign In or Register to comment.