Game Programming Crash Course (for J2ME): Sprites

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

J2ME Tutorial
 

We now get to the part where our game begins to resemble... a game. We are going to add our first sprite to the game: The ball.

A sprite is a moveable piece of graphic, that doesn't "destroy" the background when it is moving. WhatIs defines a sprite as: 'A sprite is a fairy or an elf. Derived from the Latin spiritus or spirit, it also once meant "soul" or "ghost." ... Sprites are frequently part of game technology and some games basically consist of a sprite and its rules for moving within a graphic background (think of a ball in a pin-ball machine).'

A sprite is normally based on an existing piece of art (image file), and this also goes for the sprites used in this course. When dealing with images in J2ME be aware that the specification states that .png files MUST be supported, whereas all other are optional (which in turn means that support differs from device to device). I always use .png files.

Importing Image File

The ball in our game is going to be a small square measuring 3x3 pixels. You can use whatever size you want and be as creative as you want within the size. But be aware that I expect the ball sprite to be 3x3 px for the rest of this course, so you'll have to adjust the code if you use a different size.

 
  Tip!

If you don't feel creative, feel free to grab the image I used for the sprite here: (it might be a bit difficult to hit, so here is a link you can right-click and "Save As...").
 
 

We must import this file into our project in Eclipse, but there is a subtle catch here: It must be imported to a folder named "res" to be located from the MIDlet (this often cause some confusion, since a lot of tutorials simply state "it must be present in the Resources folder" and similar).

In Eclipse, right-click the "res" folder located under the "Pong" project in the Package Explorer. Select "Import...". In the new window expand the "General" folder and choose "File System". Press the "Browse..." button and browse to the directory where the ball.png file is located. Open the directory. When you return to the Import window again, check "ball.png" in the list on the right and press the "Finish" button.

The image is now present in our project, but we still need to make the code use it.

Using Sprites

To utilize sprites we must do the following: 1) Import the Sprite class 2) Load the image 3) "Configure" the sprite 4) Find a way to keep track of the sprite.

Here is the code that completes all these tasks. I walk through each change below.

package dk.koderko.games.pong; import java.io.IOException; // Added import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.lcdui.game.Sprite; // Added import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; // Added 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 { // Added ballImg = Image.createImage("/ball.png"); // Added } catch (IOException ioex) { // Added System.out.println(ioex); // Added } // Added ballSprite = new Sprite(ballImg, 3, 3); // Added ballSprite.defineReferencePixel(2, 2); // Added ballSprite.setRefPixelPosition(ballX, ballY); // Added 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); ballSprite.setRefPixelPosition(ballX, ballY); // Added ballSprite.paint(g); // Added flushGraphics(); } private int sleepTime = 30; private Image ballImg; // Added private Sprite ballSprite; // Added private int ballX = getWidth() / 2; // Added private int ballY = getHeight() / 2; // Added }

Quite a lot of code, huh? No need to worry, here's the lowdown on the additions.

import java.io.IOException; import javax.microedition.lcdui.game.Sprite; import javax.microedition.lcdui.Image;

We import the IOException class, since it is needed when we try to load the image. We import the Sprite class because, well, we are going to use sprites. Finally we import the Image class to be able to load images.

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);

In the start() method we add this code. The first part is quite straight-forward, we create a new image objet based on our .png file. Please note that we simply specify "/ball.png" and it automatically goes to the "res" folder previously mentioned. If anything goes wrong the error is catched and written to the console.

Then we create a new sprite object. The parameters are Sprite(image object, width, height). So we create a new sprite that use the ballImg object as Image, with a width of 3px and a height of 3px. The defineReferencePixel is used to specify which pixel of the sprite is used, when ie. we want to place the sprite. On a small sprite like this, it doesn't matter much, but on larger sprites it is very important. See the following drawing for further explanation. Finally we call setRefPixelPosition to specify where on the screen we want to place the sprite when starting out. The variables ballX and ballY are specified further below.

 
  More Information

defineReferencePixel() specifies which pixel of the sprite we want to use as "the reference". Our ball sprite is 3x3 pixels big, so when we specify the reference pixel to be (2, 2) we get the center of the ball as reference, as illustrated here:

SetRefPixel Ball
 
 

 

ballSprite.setRefPixelPosition(ballX, ballY); ballSprite.paint(g);

This code is present in the updateScreen() method. As you might recall this method is called continously, and we use the setRefPixelPosition() to change the position of the sprite during the game. We must call paint() to paint the sprite on the canvas. It refers to the same "Graphics g" as previously described.

private Image ballImg; private Sprite ballSprite; private int ballX = getWidth() / 2; private int ballY = getHeight() / 2;

This is the newly added objects and variables. We initialize an Image called ballImg and a Sprite call ballSprite. The ballX and ballY variables are used to keep track of where the sprite is on the screen. When we use getWidth() we get the width of the canvas, and when we divide by 2 we get the center of the x-axis. We then do the same with the height. The result is that the ball is placed in the center of the screen.

The Result

If you run this code in the emulator, you will see something like this.

Emulator Sprite

Okay, I admit it. I promised some kind of moving graphics. Fortunately it is quite easy to move the graphics after we have done all of the code above. All we need to do is 1) Add variables that handle the velocity of the ball 2) Add a method that moves the ball 3) Add a call to that method from updateScreen(). We accomplish 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(); // Added ballSprite.setRefPixelPosition(ballX, ballY); ballSprite.paint(g); flushGraphics(); } private void moveBall() { // Added ballX += ballXVel; // Added ballY += ballYVel; // Added } // Added 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; // Added private final static int ballYVel = 1; // Added }

The new code works as follows:

moveBall();

This is simply a call to the newly added method. As you can see it is placed in the updateScreen() method, which is called continuosly.

private void moveBall() { ballX += ballXVel; ballY += ballYVel; }

This method is quite self-explanatory. It takes the current ball position (x and y coordinates) and move it to a new position, with the velocity specified in the two velocity variables.

private final static int ballXVel = 3; private final static int ballYVel = 1;

The two velocity variables. These variables defines how many pixels the ball move left/right and up/down each time the moveBall() method is called.

The Bad Result

If you run the game as it is right now, you'll see that the ball start in the middle of the screen, and then continues out of the screen. It does not "know" that it really should bounce of the border of the screen. We will have to fix that.

Next Page: When a sprite collides

 
 
 

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

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