xzhang66
xzhang66

Reputation: 17

Java bouncing ball

I'm doing this bouncing ball problem and I have was given this formula: (velocity) vx = v0*cos(angle). and (x-position) x = v0*cos(angle)*t. However, I cannot get the ball to bounce properly. The problem is that after the ball hits the right vertical wall, it starts to bounce inside certain range on the right-hand-side of the window. (y and vy shouldn't matter in this case.) How can I fix this weird bouncing problem to make it bounce property in the x direction?

public class GamePanel2 extends JPanel implements KeyListener, ActionListener{
    Timer tm = new Timer(60, this);  //this refers to the ActionListener
    public int score = 0;
    public GamePanel2(){
    addKeyListener(this);
    setFocusable(true);
    setBackground(Color.BLACK);
    }
    public int getScore() {
        return score;
    }
    public double v0 = 100;
    public double t = 0;
    public double angle = Math.PI/2.5;
    public double  x = 0;
    public double  y = 0;
    public double  vx =0;
    public double  vy = 0;
    public int move = 0;
    public int paddlex =0;

    public void paintComponent(Graphics g){
        int h = getHeight();
        int w = getWidth();
        vx  = v0*Math.cos(angle);
        vy = v0*Math.sin(angle);    
        Graphics2D g2d = (Graphics2D)g;
        g2d.translate(0.0,h);
        g2d.scale(1.0, -1.0);
        //ball
        g2d.setColor(Color.GREEN);
        g2d.fillOval((int)Math.round(x), (int)Math.round(y+6), 20, 20);  
        //paddle
        g2d.setColor(Color.RED);
        g2d.fillRect(paddlex + move, 0, 60, 6);  
        repaint();
    }
    //KeyListener methods
    @Override
    public void keyPressed(KeyEvent arg0) {
        if(arg0.getKeyCode() == KeyEvent.VK_SPACE){
            tm.start();
        }
        else if(arg0.getKeyCode()==KeyEvent.VK_ESCAPE){
            tm.stop();
        }
        if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
            move += 30;
        }
        //if pressed right key
        if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
            move -= 30;
        }
        repaint();
}
    @Override
    public void keyReleased(KeyEvent arg0) {    
    }
    @Override
    public void keyTyped(KeyEvent arg0) {
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        t = 0.2;
        vy -= 9.8;
        x += vx;
        y += (vy)*t-(t*t*9.8)*0.5;

        if( x<= 0){
            vx = v0*Math.cos(angle);
        }

        if (x>=getWidth()-20){
            vx =-(v0*Math.cos(angle));
        }
        repaint();
    }
}

Upvotes: 0

Views: 609

Answers (2)

Gene
Gene

Reputation: 47020

You're not even close. The differential equations of motion for a ball with gravity supplying the only force are

d^2x/dt^2 = -9.8  and d^2x/dt^2 = 0 

You need to integrate these equations. For this purpose, you need to get rid of the second degree differentials by introducing a new variable:

dv_y/dt = -9.8      and dv_x/dt = 0
dy/dt = v_y               dx/dt = v_x

With Euler forward differences (the simplest possible integration method), this becomes:

 v_y[i+i] = v_y[i] + h * -9.8
 y[i+1]   = y[i] + h * v_y[i]
 v_x[i+1] = v_x[i] + h * 0    // x-velocity is constant!
 x[i+1]   = x[i] + h * v_x[i] 

When the ball encounters a vertical wall with a perfectly elastic collision, the x velocity instantly changes sign. When it hits the floor or ceiling, the y velocity changes sign.

Your formula provides only the initial values of v_x and v_y. All x and y values after are results of the above Euler equations. In pseudocode it will look something like this:

// Initialize the velocity components.
vx = v0 * cos(theta)
vy = v0 * sin(theta)
// Initialize the position of the ball.
x = R // in the corner of the first quadrant
y = R
// Choose a time increment.
h = < a very small number of seconds >
// Start the clock.
t = 0
while (t < END_OF_SIMULATION) {
  draw_ball(x,y)
  x = x + h * vx;
  y = y + h * vy;
  vy = vy - h * 9.8;
  // Check for bounces
  // Assumes box has corners (0,0), (W,H)
  if ((vx < 0 and x < r) or (vx > 0 && x > W-r)) x = -x;
  if ((vy < 0 and y < r) or (vy > 0 && y > H-r)) y = -y;
  t = t + h
}

Note that that 9.8 means that the units are meters and seconds. You need to scale pixels in the Java window and use a timer to get a realistic result.

To roughly simulate lossy collision, you can steal some velocity on every bounce:

x = -<a number a bit less than 1.0> * x  and
y = -<a number a bit less than 1.0> * y

With these, the ball will slow down a bit every time it hits a wall.

Upvotes: 1

David Ehrmann
David Ehrmann

Reputation: 7576

I can't find where you're changing the angle after detecting a bounce. I also don't see bounds checking for all four sides of the windows the ball is in.

There's a related bug you might run into where there's a double bounce in a corner that leaves the ball outside the window after all the calculations are done. Think about ways to handle that case.

Upvotes: 0

Related Questions