Game Programming Crash Course (for J2ME): Collision Detection

Koder & Ko logo
 
 
Home | Tools Setup | MIDlet | Background | Sprites | Collision Detection | User Input | Artificial Intelligence | Optimization
 
 
Koder & Ko

J2ME Tutorial
 

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.

Collision Box

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.

Collision Direction

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

 
 
 

Call +45 2078 7221 or write ave at koderko.dk

Koder & Ko | Nordre Fasanvej 166 | 2000 Frederiksberg | Denmark