|
Collision detection is one of the essential issues in game programming. For now we want the ball to bounce of the walls, and on the next page I'll show how to handle sprite-on-sprite collisions.
Basicly, what we want to do is keep the ball inside a "box", which is equal to our screen.
We want the ball to stay within the area where ballX is higher than 0 and ballY is higher than 0. At the same time, we want ballX to be lower than getWidth() and ballY to be lower than getHeight().
To make things a bit easier for ourselves, we do not have to check for all possible collisions all the time. The ball is actually limited to 4 possible directions as shown here.
What we need to add to our code is: 1) A variable that keeps track of the direction of the ball 2) Checks that make sure our ball stays within the box 3) Functionality that make the ball change direction when it hits the box.
We achieve this with the following code.
package dk.koderko.games.pong;
import java.io.IOException;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
public class PongCanvas extends GameCanvas implements Runnable {
public PongCanvas() {
super(false);
}
public void run() {
while(true) {
updateScreen(getGraphics());
try {
Thread.sleep(sleepTime);
} catch (Exception e) {
}
}
}
public void start() {
try {
ballImg = Image.createImage("/ball.png");
} catch (IOException ioex) {
System.out.println(ioex);
}
ballSprite = new Sprite(ballImg, 3, 3);
ballSprite.defineReferencePixel(2, 2);
ballSprite.setRefPixelPosition(ballX, ballY);
Thread runner = new Thread(this);
runner.start();
}
private void createBackground(Graphics g) {
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
}
private void updateScreen(Graphics g) {
createBackground(g);
moveBall();
ballSprite.setRefPixelPosition(ballX, ballY);
ballSprite.paint(g);
flushGraphics();
}
private void moveBall() {
// NOTE: I have deleted the two lines previously present here
if (ballDirection == 0) { // Added: All of the lines below
ballX -= ballXVel;
ballY -= ballYVel;
} else if (ballDirection == 1) {
ballX += ballXVel;
ballY -= ballYVel;
} else if (ballDirection == 2) {
ballX += ballXVel;
ballY += ballYVel;
} else if (ballDirection == 3) {
ballX -= ballXVel;
ballY += ballYVel;
}
if (ballDirection == 0 && ballX < 0) {
ballDirection = 1;
} else if (ballDirection == 0 && ballY < 0) {
ballDirection = 3;
} else if (ballDirection == 1 && ballY < 0) {
ballDirection = 2;
} else if (ballDirection == 1 && ballX > getWidth()) {
ballDirection = 0;
if (sleepTime > 5) sleepTime--;
} else if (ballDirection == 2 && ballY > getHeight()) {
ballDirection = 1;
} else if (ballDirection == 2 && ballX > getWidth()) {
ballDirection = 3;
if (sleepTime > 5) sleepTime--;
} else if (ballDirection == 3 && ballY > getHeight()) {
ballDirection = 0;
} else if (ballDirection == 3 && ballX < 0) {
ballDirection = 2;
} // Added: All of the lines above
}
private int sleepTime = 30;
private Image ballImg;
private Sprite ballSprite;
private int ballX = getWidth() / 2;
private int ballY = getHeight() / 2;
private final static int ballXVel = 3;
private final static int ballYVel = 1;
private int ballDirection = 1; // Added
}
Please note that the two lines that was used to increment the ballX and ballY position was removed. The additions are described here.
if (ballDirection == 0) {
ballX -= ballXVel;
ballY -= ballYVel;
} else if (ballDirection == 1) {
ballX += ballXVel;
ballY -= ballYVel;
} else if (ballDirection == 2) {
ballX += ballXVel;
ballY += ballYVel;
} else if (ballDirection == 3) {
ballX -= ballXVel;
ballY += ballYVel;
}
if (ballDirection == 0 && ballX < 0) {
ballDirection = 1;
} else if (ballDirection == 0 && ballY < 0) {
ballDirection = 3;
} else if (ballDirection == 1 && ballY < 0) {
ballDirection = 2;
} else if (ballDirection == 1 && ballX > getWidth()) {
ballDirection = 0;
if (sleepTime > 5) sleepTime--;
} else if (ballDirection == 2 && ballY > getHeight()) {
ballDirection = 1;
} else if (ballDirection == 2 && ballX > getWidth()) {
ballDirection = 3;
if (sleepTime > 5) sleepTime--;
} else if (ballDirection == 3 && ballY > getHeight()) {
ballDirection = 0;
} else if (ballDirection == 3 && ballX < 0) {
ballDirection = 2;
}
This code might seem intimidating at first, but there's no need to fret; it is pretty straight-forward. The first if-block moves the ball depending on the direction it currently has. If the ballDirection is set to 0, the ball moves towards the top and towards the left (see the drawing above). The block takes care of the 4 possible directions the ball can have, and moves the ball depending on the ballDirection.
The second block takes care of the collision detection. For each possible direction it checks to see if the ball has exceeded the boundaries (either on the x- or y-axis), and changes the direction if necessary. It is not overly complex, if you read it carefully. Ie. if the ball has a ballDirection of 0, it will only be able to reach 0 on the x-axis or 0 on the y-axis, it will never be able to reach the right or bottom of the screen, since ballDirection 0 moves the ball towards the top-left. I suggest you view this block with the image from above showing the 4 different directions, until you understand the system.
private int ballDirection = 1;
This is the variable used for storing the current direction of the ball.
If you run this in an emulator you will see the ball bouncing around on the screen. You can play with the sleepTime variable, if you want to speed up (or slow down) things a bit.
Next Page: When a user is involved
|