Moving objects in animation programs

Moving - constant speed

Assume that you either have an object Ball ball or a variable int ballx = 200
To move at a constant speed to the right, just add 4 pixels to ball.x or ballx.

ball.x = ball.x + 4; //moves ball 4 pixels to the right each time through the animation loop
ball.x += 4; //shortcut code

To move to the left, add a negative number. To be consistent, we're ALWAYS ADDING a number.

To make this more general, we'll use a variable for the speed. We need separate variables for x- and y- speeds so that they can be independant of each other.
Thus we now have:

ballx = ballx + xspeed
or more compactly, let vx be velocity in x direction ...
ball.x += ball.vx

You can do the same in the y-direction, just remember that positive y is downwards

Bouncing off walls

We're going to look at bouncing off the edges of the window, so that the ball never leaves the screen. Let's assume that the window is size WINW x WINH. (These would be constants set up at the beginning of your program.) So the left size of the screen is x=0 and the right is x=WINW.

To make the bounce happen, the simplest thing is just to change the sign of the speed. For example, consider a ball moving to the left, so the x-speed is negative: e.g. ball.vx = -5;

To bounce off the left side:
1.

if (ball.x < 0) ball.vx = -ball.vx;	//this could also be written as:  if (ball.x < 0) ball.vx *=-1;
Now, there are a couple of other things that can be done:
2. Sometimes the ball gets stuck on the side and just oscillates back and forth (I can't explain why this happens without a diagram).
To fix this we only change the speed if the ball is moving to the left.
if (ball.x < 0 && ball.vx < 0) ball.vx =-ball.vx;
3. We could also deliberately move the ball back onto the screen. Sometimes this is a really useful thing to do.
if (ball.x < 0 && ball.vx < 0) {
   ball.vx =-ball.vx;
   ball.x = 0;
}

To bounce off the right side:
Note that ball.x specifies the position of the LEFT side of the ball. We need to see if the RIGHT side of the ball goes off the right edge of the window.
The right side of the ball is calculated by adding the width (or diameter) of the ball to x : ball.x + ball.width

So we then have:

if (ball.y + ball.width > WINW) ball.vy =-ball.vy;
or
if (ball.y + ball.width > WINW && ball.vx > 0) ball.vy =-ball.vy;

Now do the same with the top and bottom.

Two moving objects hitting each other

If you have two balls colliding, the simplest way to make it realistic is for them to exchange their vx and vy
For example: b1.vx = 10, b1.vy=3; b2.vx=-6, b2.vy=1; So

if (b1.intersects(b2) {
   //exchange vx speeds here
   //exchange vy speeds here
}
After the collision the speeds are now: b1.vx = -6, b1.vy=1; b2.vx=10, b2.vy=3;

Bouncing off of an immovable object

To make an object bounce off something, you have find out if it intersects. If both of these things are rectangles than it's easy:

if (ball.intersects(box)) ...

The thing that still needs figuring out is do we change vx, vy, or both? It depends on where you hit the box: the top or a side or a corner.
Code that does this follows

package animationProgram;

import java.awt.Color;
import java.awt.Rectangle;
import hsa2.GraphicsConsole;


/* Note: the code to handle the collisions seems unnecessarily complex,
 * but I had to put it all in or else the ball would get stuck or 
 * not bounce properly. 
 * The code still won't work for the cases where the rectangle moves quickly
 * (eg. acts like a large paddle)
 */

public class BallCollision {
	
	public static void main(String[] args) {
		new BallCollision();
	}

	// set SLEEP to a high number so that we can check the collisions carefully 
	final static int SLEEP=35;
	
	final static int SCRW=800;
	final static int SCRH=600;
	
	GraphicsConsole gc = new GraphicsConsole(SCRW,SCRH);

	Ball ball;
	Rectangle rect = new Rectangle (100,200,80,200);

	BallCollision() {
		setup();

		while(gc.getKeyCode() != 'Q') {			
			moveBall();			
			ballHitRectangle(ball, rect);
			drawGraphics();
			gc.sleep(SLEEP);

			//DEBUG: move the rectangle by clicking (for testing collisions)
			if (gc.getMouseClick() > 0) {
				rect.x = gc.getMouseX();
				rect.y = gc.getMouseY();
			}
		}
	}

	void setup() {
		gc.setAntiAlias(true);
		gc.setLocationRelativeTo(null);
		gc.setTitle("Two Balls Collision");
		gc.setBackgroundColor(Color.BLACK);
		ball = new Ball(SCRW);		
		gc.enableMouse();

		//for testing
		ball.vx=-1;
		ball.vy=2;
		ball.x=210;
		ball.y=130;
	}

	void moveBall() {
		ball.x = ball.x + ball.vx;
		ball.y = ball.y + ball.vy;

		if (ball.x < 0 && ball.vx < 0) ball.vx = -ball.vx;
		if (ball.y < 0 && ball.vy < 0) ball.vy = -ball.vy;
		if (ball.x > SCRW-ball.width && ball.vx > 0) ball.vx = -ball.vx;
		if (ball.y > SCRH-ball.height && ball.vy > 0) ball.vy = -ball.vy;

		/* To make two balls bounce off each other 
		   just exchange their x-speeds like this:
		   
		if (b1.intersects(b2)) {
		   //undo the last movement.
		   b1.x -= b1.vx;	
		   b1.y -= b1.vy;

		   //exchange x- speeds
		   int temp = b1.vx;
		   b1.vx = b2.vx;
		   b2.vx = temp;
		}
		*/
	}

	/**************************************************
	   This method is used to bounce a ball off of a rectangle.
	   It assumes that the rectangle is stationary.
	   Since we have made our balls to be subclasses of rectangles, you could use this
	   to bounce two balls off of each other, but it won't look right.

	   Note: it doesn't take into account the circular nature of the ball. 
	   It pretends that the ball is a rectangle, so it's not exact.
	   
	   Call the program by doing something like this in your main animation loop:
		   ...
			ballHitRectangle(b1, r1);
			ballHitRectangle(b2, r1);
			gc.drawGraphics();
			gc.sleep(1);
		}
	*************************************************/

	void ballHitRectangle (Ball b, Rectangle r ) {
		//here we treat the ball as a rectangle 
		if (b.intersects(r)) {

			//top bounce

			/* this just sees if part of the ball touches the rect. 
			 The whole ball could be below, as when it is moving down and to the left and hits the middle of the left side	
			 */
			//if (b.y + b.height > r.y && b.vy > 0) {

			if (b.y + b.height > r.y && b.y < r.y && b.vy > 0) {
				//is the whole ball between the left and right sides of the box?
				if (b.x > r.x && b.x+b.width < r.x+r.width) {

					b.x -= b.vx;	//undo last move
					b.y -= b.vy;

					b.vy = -b.vy;					
					return;
				}
			}

			//hit from left (left side of block)
			if (b.x + b.width > r.x && b.vx > 0) {	//moving right 
				if (b.y > r.y && b.y + b.height < r.y + r.height) {
					b.x -= b.vx;	//undo last move
					b.y -= b.vy;					

					b.vx = -b.vx;					
					return;							
				}
			}
			//hit bottxom (moving upwards)
			if (b.y < r.y+r.height && b.vy < 0){ 				
				if (b.x > r.x && b.x+b.width < r.x+r.width) {
					b.x -= b.vx;	//undo last move
					b.y -= b.vy;					

					b.vy = -b.vy;					
					return;
				}
			}
			//hitting right side, moving from left
			if (b.x < r.x+r.width && b.vx < 0){
				if (b.y > r.y && b.y + b.height < r.y + r.height) {
					b.x -= b.vx;	//undo last move
					b.y -= b.vy;					

					b.vx = -b.vx;					
					return;
				}

			}

			
			/* ****************************
			 * Cases for hitting corners: *
			 ******************************/
			
			//undo last move
			b.x -= b.vx;	
			b.y -= b.vy;

			//Find centre of rect:
			int crX = r.x + r.width/2;
			int crY = r.y + r.height/2;
			
			// Find which corner ball is bouncing off of, then bounce the ball away from the corner 
			//top left corner
			if (b.x+b.width < crX && b.y + b.height < crY) {	
				b.vx = - Math.abs(b.vx);
				b.vy = - Math.abs(b.vy);
				return;
			}
			
			//top right corner
			if (b.x > crX && b.y + b.height < crY) {	
				b.vx = + Math.abs(b.vx);
				b.vy = - Math.abs(b.vy);
				return;
			}
			
			//bottom left corner
			if (b.x + b.width < crX && b.y > crY) {	
				b.vx = - Math.abs(b.vx);
				b.vy = + Math.abs(b.vy);
				return;
			}
			
			//bottom right corner
			if (b.x > crX && b.y > crY) {	
				b.vx = + Math.abs(b.vx);
				b.vy = + Math.abs(b.vy);
				return;
			}
		}
	}

	void drawGraphics() {
		synchronized(gc){
			gc.clear();
			gc.setColor(ball.clr);
			gc.fillOval(ball.x,ball.y,ball.width,ball.height);
			gc.setColor(Color.RED);
			gc.drawRect(rect.x, rect.y,rect.width, rect.height);
			
		}
	}

	// Put the ball class in here so that everything is in one file 
	class Ball extends Rectangle {		
		int vx = 2;
		int vy = 4;		
		Color clr = Color.YELLOW;
		
		Ball(int screenW) {
			x = (int)(Math.random() * (screenW - 100)) + 50;
			y = (int)(Math.random() * 100) + 1;
			width = height = 30;  //width and height are required for the "intersects()" method 
		}
	}
}

Gravity and Friction

Figure out these mysteries for yourself ... it's not too hard.