Basic Java ME Game Template Part 2
Jump to part: 1 | 2 | 3

We need to make a Java class based on the GameCanvas class. The canvas is where we draw all our stuff like images, sprites, maps, scores so it can be shown on the phone screen. It also let's us know which keys were pressed on the phone so we can respond to them.

A new Java Class file can be created the same way we created a MIDlet in the previous part of this tutorial. Create a new file now by pressing CTRL+N to invoke the "New File" wizard. Choose "Java" from the list of "Categories" and "Java Class" from the list of "File Types" then click on the "Next" button. Alternatively, you can right-click on the package name then choose "New" -> "Java Class".

New File wizard


On the "Name and Location" screen, type in "clsCanvas" for the "Class Name". Make sure to set the "Package" field to the package name we set earlier for our MIDlet in the first part of this tutorial. Click on the "Finish" button when you're done.

Name and Location screen


You should see the source code of class file we just created in the editor panel. If not, then navigate to the file from the project panel and double-click on the filename. Except for the author's name and the file/class/package name (if you chose your own), it should look similar to the code below.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package pkgGame;

/**
*
* @author Devlin
*/
public class clsCanvas {

}


It's now time to turn this class into a GameCanvas class. To do so we just have to modify the class declaration and add the keyword "extends" followed by "GameCanvas" after the class name "clsCanvas".


public class clsCanvas extends GameCanvas{
...
...


While we're doing that, let's also make the clsCanvas implement the Runnable interface. We do this by further adding the keyword "implements" followed by "Runnable" at the end of the class declaration.


public class clsCanvas extends GameCanvas implements Runnable{
...
...


Press CTRL+SHIFT+I (short cut for Fix Imports) to make sure that all the missing import statements required by the code are detected and added automatically. Do this perodically or whenever you add a new class to your code. The clsCanvas class should now look like this:

package pkgGame;

import javax.microedition.lcdui.game.GameCanvas;

public class clsCanvas extends GameCanvas implements Runnable {

}


Now it's time to get rid of those ugly red lines signifying errors in our code. We need to fulfill the requirements of the base class that we are extending and implement the functions of the interface. First, lets add a contructor to our class like so:

public class clsCanvas extends GameCanvas implements Runnable {

public clsCanvas() {
super(false);
}


}


The previous code fullfills the requirements of the GameCanvas class whos constructor takes in a boolean argument. The code inside our constructor means we're passing the value "false" to the constructor of our superclass GameCanvas. Next, the Runnable interface requires us to implement a "run()" method.

public class clsCanvas extends GameCanvas implements Runnable {

public clsCanvas() {
super(false);
}

public void run() {

}


}


Tada! No more errors!

The superclass GameCanvas requires us to implement it's constructor which has one boolean parameter - suppressKeyEvents. Passing the value true stops key events like keyPressed, keyRepeated and keyReleased from being called. But later on we will be rellying more on the function getKeyStates() to find out which keys were pressed whenever we need them. More on this later.

Our canvas class also implements the Runnable interface which allows our game to run on a separate thread. This requires us to implement the run() method which takes no arguments and has no return value. The run() method will contain our main loop and most game related code.

We will now create the main loop for the game. First let's define a private boolean variable which we will use to signal when the loop should end and exit the game. We will call it "isRunning" and place it right under the class declaration.

public class clsCanvas extends GameCanvas implements Runnable {
private boolean isRunning = true;
...
...


We will use a while-loop construct as the main loop for the game using the value of isRunning variable as the looping condition. As mentioned before, we will place it in the run() method.

    public void run() {
while(isRunning){

}
}


Since the initial value of isRunning is "true", the while loop will pretty much run indefinitly until isRunning changes to false. For now, let's make it so that the loop is terminated whenever the FIRE or 5 key is pressed on the phone. We do that by using the getKeyStates() function. We'll also make the thread sleep for a few milliseconds to make sure the game remains responsive to user input using the Thread.sleep() method.

    public void run() {
while(isRunning){
// get keys pressed
int iKey = getKeyStates();
// check if FIRE or 5 is pressed
if ((iKey & FIRE_PRESSED) != 0){
// signal an exit
isRunning = false;
}


try{
// make this thread sleep for 30 ms
Thread.sleep(30);
} catch(Exception e){

}

}
}


The thread sleeps or pauses for 30 milliseconds after each loop. This keeps the the thread from hogging the processing power of the phone and the game from being unresponsive. Without it, the game will not be able to respond to key presses at the moment it needs to. You can change duration of the delay to what you want as long as it works. We will be adding frame limiting at some point and that will dynamically adjust the sleep value and make the frame rate of the game somewhat stable on different phones.

There are two requirements for starting a thread. You need an instance of the Thread class and a object that implements the Runnable interface. We already have an object which implements the Runnable interface so all we just have to make an instance of the Thread class. We will add a start() method to our clsCanvas class that does exactly that. Placed it above the run() method.

    public void start(){
// creat a new instance of the Thread class
Thread thread = new Thread(this);
// launch the thread
thread.start();
}


public void run() {


Let's add some drawing code so we can see what we've done later when we run the application. First let's declare a global variable named "g" that will hold an instance of the Graphics object associated with the GameCanvas class. Place it under the class declaration. Don't forget to press CTRL+SHIFT+I afterwards to add any missing import statements.

public class clsCanvas extends GameCanvas implements Runnable {
private boolean isRunning = true;
private Graphics g;
...
...


We have to initialize it by retreiving the Graphics object from GameCanvas using the getGraphics() function. We will do this right before the while loop inside the run() method.

    public void run() {
g = getGraphics();
while(isRunning){
...
...


While java has a pretty solid garbage collector it still helps if u mark objects as garbage when u no longer need them by assigning a null value. So when we're done using the Graphics object, we'll just set it free ... right under the while loop. While we're at it, we'll just add the rest of the drawing code to the run() method.

    public void run() {
g = getGraphics();
while(isRunning){
// get key state
int iKey = getKeyStates();
// check if FIRE or 5 is pressed
if ((iKey & FIRE_PRESSED) != 0){
// signal an exit
isRunning = false;
}

//set drawing color to black
g.setColor(0x000000);
//fill the whole screen with black
g.fillRect(0, 0, getWidth(), getHeight());
// set drawing color to white
g.setColor(0xffffff);
//display a string
g.drawString("Basic Java ME Game Template", 2, 2, Graphics.TOP | Graphics.LEFT);
//display the key states in white
g.drawString(Integer.toString(iKey), 2, 22, Graphics.TOP | Graphics.LEFT);

// show everything we drew on the screen
flushGraphics();


try{
// make this thread sleep for 30 ms
Thread.sleep(30);
} catch(Exception e){

}
}
// mark as garbage
g = null;

}


One feature of the GameCanvas is an off-screen buffer where everything you draw is first rendered. The contents of this buffer is transferred to the screen after the flushGraphics() function is called. This eliminates flicker and makes your animations smoother. So flushGraphics() is called every time at the end of each loop after you have drawn what you want to be shown on the screen.

The Graphics object contains the methods we must use to draw stuff on the GameCanvas. Just take note that the color passed when setColor() is called will apply to succeeding calls to drawing methods until setColor() is called again with a different color.

Btw, you can find out more about using threads here : Using Threads in J2ME Applications

Before we go to the last part of this tutorial, we need to add a way for the clsCanvas class to tell the MIDlet that the game has ended and the MIDlet needs to close. First, we declare a global variable called "p" to hold a reference to the MIDlet.

public class clsCanvas extends GameCanvas implements Runnable {
private boolean isRunning = true;
private Graphics g;
private midMain p;


Then we modify the clsCanvas constructor so we can pass a reference to the MIDlet when the object is created and assign it to our variable.

    public clsCanvas(midMain parent) {
super(false);
p = parent;
}


Finally, we can call the destroyApp() method of the MIDlet when the main loop ends and close the MIDlet.

        ...
...
// mark as garbage
g = null;
// close the MIDlet
p.destroyApp(true);
p = null;

}


We can now go to the next step: Displaying the GameCanvas.