Professional Documents
Culture Documents
88 KB
Introduction
This article is the first part in my Mobile Game Programing for Beginners series. The
series start out with a super-simple game but will continue to show how to implement a
variety of different game types and the techniques used to code them.
The series is a four part series where I'll go through the following games:
• Basics
• BreakOut
• Top Down Scroller
• 3D Space Game
This part will show you how to implement a very simple game, which tools you'll need
and how to actually try it out on your handset.
In this game, the goal is to navigate your avatar to a target, no obstacles and the target
isn't even moving. There's no way to "die", no way to loose, but it's a good starting point
to show the basics of game programming. The areas I'll cover in this first part are:
• Tools of the Trade, the applications required (or at least the ones I like to use).
• Creating a MIDlet, an application that can run on your mobile phone.
• Basic Game Loop, the foundation of any game.
• Reading user input.
• Java 6 SDK
• NetBeans
• Paint.NET
Java 6 SDK
The Java SDK (or JDK, Java Development Kit) is a collection of class libaries, tools and
documentation used when developing Java applications. It is not to be confused with a
JRE, Java Runtime Environment, which is something that is used to run Java based
application. I downloaded my JDK from here. You'll need a JDK installed to use the next
tool on the list, NetBeans, so make sure this is the first thing you download.
NetBeans
Go here and download the Mobility pack and get that installed. The Mobility pack
includes the J2ME JDK (Java 2 Mobile Edition), which contains the class libraries
required to write a MIDlet (which is a java application that can run on a mobile device),
and the tools required (such as emulators for testing the game without having to install it
on an actual handset).
Paint.NET
Almost all games needs some sort of graphics to make them enjoyable, I prefer to use
Paint.NET to create the graphics for my games (when it's not generated by the game
itself, but more on that in the second part of the series). The reason I'm not using Paint
that comes bundles with windows is that it's simply not packed with all the nice features
that Paint.NET have, such as support for transparent png files.
Once you have these three tools installed you're almost ready to start coding.
Basic Game Loop
Almost all games rely on a central game loop, it is the loop that manages or control the
game. As the games you write become more and more complicated the methods called
from the game loop will have to contain more and more logic, but the actual game loop
will still be a fairly simple loop. In its simplest form it might look something like this:
Collapse
while(gameShouldStillBeRunning) {
// Capture input
readInput();
Reading Input
This method is responsible for reading or capturing the current state of the input. This
includes for example checking which keys are pressed and how far the mouse has moved
since last check. The method typically stores the input that is relevant to the game in a
place where the updateGameState method can access it.
Storing the game state can be as easy as setting a boolean value to true if a key is pressed
and to false it it's not pressed. The reason for checking the input and storing it first,
instead of checking it when you actually need it (i.e when updating the game state), is
because it is often quite expensive CPU wise to read the input and it is best to get all the
input required at once. Otherwise different parts of the code that updates the game state
might query the OS several times for the same key input, which would be unecessary.
Making the games run smooth and fast is a major part of game development and I will
discuss this in a later part of this series.
You'll notice that the game included in this article doesn't read the input state in the game
loop, that is because it's relying on a built in functionality of the
javax.microedition.lcdui.Canvas, more on this later.
Updating the game state include all the actual processing of the game logic, such as
moving the players character according to the input captured, moving enemies according
to their AI, updating the environment, checking for game over state and many more
things all depending on what kind of game is being developed.
In this first part, updating the game state includes only moving the avatar and checking if
the avatar has reached the goal.
When the game state is rendered the state of the game (i.e. location of the player, the map
and for example the current score) is drawn to the screen.
The Canvas class in the javax.microedition.lcdui package is used to render things to
the screen in kind of the same way as java.awt or javax.swing components, by
overriding the Canvas.paint(Graphics graphics).
Note that the Graphics parameter isn't the java.awt.Graphics object that you might
reconize from desktop development, it is a javax.microedition.lcdui.Graphics
object, which is like a cut down version of the AWT one.
This is where the game primarily detects if the player has lost or beaten the game, but it
will also detect and act on any major state changes. Such as completing a level and
moving into a game state where the level summary is shown before the next level is
started (yet another state).
Getting Started
Setting up the Project
In NetBeans, select File->New Project... and select project category Mobility and projec
MIDP Application, then click Next.
Give your project a name, in this example it is called Basics.GameLoop. Then make sure
to un-tick the Create Hello MIDlet as that will create a template designed to handle a
Control based UI (with buttons and lists), and for a game all rendering is custom so no
standard controls will be used. Then click Next.
The next screen shows configuration options, the settings picked here must match the
target device's capabilities. That means that a game written for MIDP-2.1 will not run on
a mobile phone that only supports MIDP-1.0 for example. For now leave this page with
it's default settings and click Finish.
In your new project's source package create a package (as keeping classes in the root
package is discouraged), you can call the package whatever you want, in the example
application it is called com.bornander.games.basics.
Create a class called BasicsMIDletin the package you just created, this will be the entry
point for the application. This is the class that the Java runtime on the mobile device will
instanciate when the the user selects your midlet. Make sure the BasicsMIDlet class
extends javax.microedition.midlet.MIDlet, as this class defines the interface used
by the runtime to control a midlet.
The javax.microedition.midlet.MIDlet is an abstract class and there are three
methods that must be overridden:
startApp()
This method is called by the runtime to start the midlet, either when a start is requested
by the user by selecting the midlet in some menu or when a the mobile device decides to
return control back to a previously paused midlet.
pauseApp()
This method is called by the runtime to indicate to an midlet that it will loose focus,
possibly due to an incomming call. It is entirely up to the midlet to actually pause
something, the example game included in this article will ignore this method which
means the game would continue to run when a call comes in.
If a midlet decides to pause itself is should, after taken steps to suspend itself in a
controled manner, call resumeRequest() method to notify the framework that it is
interested to know when it can resume processing.
destroyApp(boolean conditional)
This method is called when a midlet is being destroyed (closed), to allow it to clean up its
resources in a safe and controlled way.
Make sure your BasicsMIDlet implements these three, abstract methods, after which
your class should look something like this:
Collapse
package com.bornander.games.basics;
import javax.microedition.midlet.MIDlet;
public BasicsMIDlet() {
}
The next step is to add the the MIDlet to the Application Descriptor, which is a set of
meta data that holds information about the mobile application. One mobile application
can contain several MIDlets but for this example there's only going to be one.
And that's it! The mobile application is created, click Run Main Project to try it out on
the emulator, this will launch a mobile phone emulator from where the MIDlet just
created can be started. Note that since there's no actual implementation yet it won't do
anything. Add a System.out.println("Hello, world!"); to the
BasicMIDlet.startApp method and run the application again to see that it's actually
started. The text will be printed to NetBeans IDE so do not expect to see it on the screen
of the emulator.
Rendering to screen
When writing MIDlets there's a set of classes for labels, text fields, checkboxes and such
that are used in a similar way to the corresponding classes in Swing or AWT. As this
article is about game programming it won't discuss any of these controls as they're not
very well suited for graphical games.
Collapse
package com.bornander.games.basics;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
public MainCanvas() {
}
// Set the current color to blue (hex RGB value ) and draw a
filled
// rectangle the size of the screen
graphics.setColor(0x00007F);
graphics.fillRect(0, 0, w, h);
// Set the current color to red, the font to the default font
and
// draw a string to the center of the screen.
graphics.setColor(0xFF0000);
graphics.setFont(Font.getDefaultFont());
graphics.drawString("Hello, world!", w / 2, h / 2,
Graphics.BASELINE | Graphics.HCENTER);
}
}
In order to get the MIDlet to use this Canvas it has to be set as the current one for the
display. Modify BasicMIDlet.startApp to create a MainCanvas and set it to the default
Display:
Collapse
public void startApp() {
MainCanvas mainCanvas = new MainCanvas();
Display.getDisplay(this).setCurrent(mainCanvas);
}
Run the MIDlet again, this time is should look something like this:
Even though it would be possible to render all aspects of a game using the different draw
methods on the javax.microedition.lcdui.Graphics it is more common to use
images created in a image editing program (such as Paint.NET). This game will use two
different images, one for the player or avatar and one for the target.
Avatar:
Target:
When creating images it is important to make use of transparent pixels otherwise the
avatar image wouldn't appear to be round but square.
Collapse
package com.bornander.games.basics;
import java.io.IOException;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
int w = getWidth();
int h = getHeight();
graphics.setColor(0x00007F);
graphics.fillRect(0, 0, w, h);
graphics.setColor(0xFF0000);
graphics.setFont(Font.getDefaultFont());
graphics.drawString("Hello, world!", w / 2, h / 2,
Graphics.BASELINE | Graphics.HCENTER);
}
}
Collapse
public class MainCanvas extends Canvas implements Runnable {
...
}
Moving the avatar (i.e. updating it's X and Y coordinates according to the directon flags)
is delegated to a method that also does constraint checking. By constraint checking I
mean the process in which the position is constained to a valid one. In this example it is
invalid for the avatar to be outside the bounds of the screen.
Collapse
public class MainCanvas extends Canvas implements Runnable {
...
if (y < 0)
y = 0;
if (y > getHeight() - avatar.getHeight())
y = getHeight() - avatar.getHeight();
if (x < 0)
x = 0;
if (x > getWidth() - avatar.getWidth())
x = getWidth() - avatar.getWidth();
}
}
By extending Canvas it's easy to capture input by simply overriding some methods.
Canvas exposes three methods related to key input:
In this first example I'm only going to use the keyPressed and keyReleased, and to
control the Avatar the only thing the methods needs to is to set the up, down, left and
right according to which key was pressed or released.
The keyCode parameter passed to the key handling can be converted to key codes better
suited for game programming using the aptly named function Canvas.getGameAction,
this will convert the key code into one that can be checked for buttons such as up and
down.
Collapse
/**
* This gets called for us whenever a key is pressed.
* @param key The pressed key.
*/
protected void keyPressed(int key) {
int gameKey = getGameAction(key);
switch(gameKey) {
case Canvas.UP: up = true; break;
case Canvas.DOWN: down = true; break;
case Canvas.LEFT: left = true; break;
case Canvas.RIGHT: right = true; break;
case Canvas.FIRE: shouldRun = false; break;
}
}
/**
* This gets called for us whenever a key is released.
* @param key The released key.
*/
protected void keyReleased(int key) {
int gameKey = getGameAction(key);
switch(gameKey) {
case Canvas.UP: up = false; break;
case Canvas.DOWN: down = false; break;
case Canvas.LEFT: left = false; break;
case Canvas.RIGHT: right = false; break;
}
}
All games needs to check the Game Over state, this can occur either when the player
loses the game or when he beats it, in any case it has to be checked or the game can
neither be won or lost.
In this first example Game Over can only occur when the player has beaten the game,
yep, that's right; this is a game you can't fail at. You can choose not to win, but you can't
lose. This implementation calls a method called isGameCompleted to check if the game
is over, this method sets a member variable completed.
To change the behaviour of the game when the Game Over state is reached, the run
method looks at the completed flag set when the Avatar has reached the Goal and if it's
true then the Avatar isn't moved anymore, regardless of key presses. Also, the paint
message draws a Game Over message at the center of the screen.
Collapse
/**
* Detects if the game has been completed (i.e. the avatar has
navigated to the target).
* @return true if the game is completed.
*/
private boolean isGameCompleted() {
return x == targetX && y == targetY;
}
Collapse
protected void paint(Graphics graphics) {
...
if (completed) {
graphics.setColor(0xA0A0FF);
graphics.setFont(Font.getDefaultFont());
graphics.drawString("Game Over", w / 2, h / 2,
Graphics.BASELINE | Graphics.HCENTER);
}
}
if (!completed) {
moveAvatar();
}
repaint();
try {
Thread.sleep(20);
}
catch (InterruptedException ex) {
}
}
owner.exit();
}
And that's it! That's the whole game, it's not the most addictive game in the world but it is
enough to show how to set up a Netbeans project and the basics of a game.
Next Part
In the next part I'll cover menus, simple AI and basic collision detection as I demonstrate
how to write a BreakOut style game.
As always, any comments on the article or the code are most welcome.
The series is a four part series where I'll go through the following games:
• Basics
• Break Out style
• Top Down Scroller
• 3D Space Game
This part will show you how to implement a break out style game.
In this game, the goal is to bounce a ball off a paddle and have the ball collide with
"bricks", if the player fails to block the ball with the paddle the game is over. When the
ball collides with brick, the brick is removed. When all bricks are removed the player has
beaten the game. In this part I'll discuss the following topics:
This game, even though it's still a very simple game is far more complicated to write, and
that's why this example consists of 20 classes rather than 2 as in the previous part of this
series. Most of the classes, however, are generic and can be reused in other projects so it's
not as complicated as it looks. I won't show code extracts for all classes in this article but
I've commented the classes that are available for download so for classes or concepts that
I don't discuss in this article; please refer to the code comments instead.
Class Overview
The most important classes in this example are:
• MainCanvas
Initializes the game's screens and controls the updates, rendering and transitions
between the screens.
• BrickBreakerScreen
The class that contains the game logic.
• Ball
Controls the ball's movment, collision detection and rendering.
• Brick
Representation of a single brick.
• BrickField
Representation of all bricks in the game.
• Paddle
Representation paddle, note that this class relies on a PaddleController to
actually control the paddle.
• PaddleController
Interface that's implemented by ComputerPaddleController and
HumanPaddleController in order to allow either a human or a computer AI to
control the paddle.
• MenuScreen
Implementation of simple, generic game menu.
Menus
I love writing games but there's one thing I don't like about it and that's writing all the
little bits and pieces that aren't actually part of the game play, such as menus and in game
dialog boxes. It it, however, quite important to take the time to implement those parts as
well, otherwise the game won't feel polished and there's going to be no way for the user
to configure game settings.
That's why in this part I'll spend some time showing you how to implement a game menu
and how to handle transitions from rendering the menu to rendering the game. As the
game implemented in this part of the series is a simple break out style game, there aren't
really that many menu options but it's still important to have a menu in order to make the
game feel more complete.
Screen transitions
In order to go from rendering the menu to render the actual game, the game must be able
to handle different types of screens, the MIDlet could be used to swap between different
Canvases but I prefer to always use just one GameCanvas that maintains it's of set of
GameScreens.
GameScreen
The GameScreen class is an abstract class that exposes a few method required by my
main MIDlet class in order to control and update the GameScreen's state and request it to
render itself.
Collapse
package com.bornander.games.utils;
import javax.microedition.lcdui.Graphics;
By using a construct such as this GameScreen class, it's easy to write a quite simple
Canvas implementation (I call mine the main canvas) that can initialize the game's
required screens and then handle the transitions between them depending on the logic
local to the active screen.
The game starts up with the menu screen as active screen, and that screen can request the
main canvas to change screen to the actual game screen when the relevant menu option is
selected. That way, the actual implementation of the menu GameScreen can be made
completely generic and it can be re-used for other games. Something which I really like,
because as I said I don't like writing the menus very much.
In this example there's a utility class called MenuScreen that is a generic implementation
of a menu and I'll be reusing that for my other two parts in this series.
MenuScreen
The MenuScreen class is a fairly simple implementation of the GameScreen class, it
allows the programmer to define a set of menu options and then renders these based on
key presses. It handles both simple items and "multiple choice" items (such as Sound
on/off). The MenuScreen itself has no knowledge of the actual game so it can't directly
configure it, but it is possible for the game to retrive the settings from the previous screen
as that is passed as an argument when a screen transisition occurs.
In-game dialogs
Sometimes there's a need to interrupt the game and present the player with information
and/or options during the game. In these scenarios it's neater to present a in-game dialog
rather than taking the user back to a fully fledged menu screen. That means that the actual
game screen handles the transitions between playing the game and showing the dialog
and the main canvas has nothing to do with this type of transition.
One such situation is when the user pauses the game, which in this example is done by
clicking the Fire button. When the game enters the the paused state it stops updating the
paddle's and ball's position, it still renders them but it also renders a dialog box in the
foreground. The game state change from running to paused also changes how input is
handled; in running mode pressing Up or Down adjusts the sound volume, but in paused
state it resumes or returns to the main menu instead.
• Starting
When the game is starting up, this gives the player a bit of time to prepare.
• Running
When the game is in play.
• Stopped
The game enters this state when it's game over.
• Paused
The the user has paused the game.
Collapse
public class BrickBreakerScreen extends GameScreen {
...
...
}
AI
An important part of most games is computer opponents that behave intelligently, and
while a break out game probably isn't the first game that comes to mind when discussing
AI I think it's a good place to start as the actual AI is easy to implement (the paddle can
only move right or left). It will also allow me to show how using a well abstracted class
design not only makes it easy to create a computer controlled entity in the game, it can
also makes it easier to debug and to add network support.
The AI in this game is simply the computer trying to control the paddle, and like I said,
this is a fairly easy task as there are only a few things the paddle can do:
• Move left
• Move right
• Don't move at all
The information the AI uses to decide which these options to go for are:
Collapse
public interface PaddleController {
void initialize();
int getCommand();
}
Information about ball and paddle are provided to the controller using the
updatePaddleData and updateBall methods, information about key presses are
captured using keyPressed and keyReleased and the getCommand method return the
action.
The version of the controller used for a human player then looks like:
Collapse
public class HumanPaddleController implements PaddleController {
public HumanPaddleController() {
}
return PaddleController.COMMAND_NOTHING;
}
}
Collapse
public class ComputerPaddleController implements PaddleController {
One could argue that the key input method's shouldn't really be part of this interface, and
that the HumanPaddleController should read the input in some other way. While that
would make the interface cleaner and a better abstraction of a paddle's controller I've
gone with this approach for simplicity.
A neat thing with abstracting the controller in this way is that it allows for easy
debugging; the computer will always play in exactly the same way (provided that the
starting conditions are the same) and that means that the programmer won't have to play
the game manually to test things like the game over state that kicks in when the game has
been beaten. It's also possible to write a computer controller that plays according to a set
of instructions recorded when a human controller was used, this is a very good thing to
incorporate into simple games as it's convinient way to get back to a state where a bug
was found.
The abstraction also hints at a way of creating a network controller so that multiplayer
games can be created, the network controller would simply connect to a client controller
that would receive the input and provide the commands and it would be transparent to the
implementation that one player is a remote player (not that that example is very
applicable to a break out style game).
Collision Detection
Collision detection is an important part of a lot of different games, wether it is to find out
when a ball hits a paddle or when a character walks into a wall. Depending on the type of
game collision detection can be implemented in different ways, one approach is to check
if two objects has collided, and if they have move them apart. That's the approach I've
gone for in this example, but I've structured it so that from the Ball's point of view, the
movement is altered before the ball is actually inside one of the bricks or the paddle.
Bounding Box
The BoundingBox contains position and size of the rectangle, and using this information
it's easy to determine if a point lies outside or inside (collision) the box.
Collapse
public class BoundingBox {
...
private int x;
private int y;
private int width;
private int height;
...
}
But just determining if a collision has occured is not enough. In my experience (which
granted is quite limited in this area), it's often easy to figure out if a collision has occured,
what is difficult to compute is the Collision Response and the information required for
that. In this example game, the ball needs to bounce off walls, bricks and the paddle in a
correct way. It won't do to just reverse the direction of the ball because it's always coming
in at an angle. Therefore it's important to calulate which side of the paddle, wall or brick
the ball collided with.
In the case of a simple break out game, the collision response if fairly simple; if the ball
collides with a horizontal edge negate the vertical velocity and vice versa. The problem is
how to figure out with which edge the ball collided. I've used this method:
• 1. Check if the Ball's current position plus it's current velocity would place it
inside a BoundingBox
• 2. If a collision will occur, use the current velocity and position relative to the
BoundingBox's position to figure out which edge the Ball collided with.
• 3. Use the edge information to cap the movement of the Ball so that it only
travels to the edge of the BoundingBox.
• 4. Negate either the vertical or the horizontal velocity depending on the edge
collided with.
I came up with a system of regions, and based on which region the ball is in (the regions
relate to the edges of the BoundingBox) there's only two possible edges that the Ball
could have collided with.
Example
In this example the Ball is in region 8, and is moving with a horizontal velocity of 2
units per second and a vertical velocity of 1 unit per second. The only two edges the Ball
can collide with from region 8 is the bottom and right edge. But because the horizontal
velocity is greater than the vertical the colliding edge will be the bottom one.
It doesn't take a genius to see that this method has it's flaws and will in some cases pick
the wrong edge as the colliding one but it's close enough for this example. (To correct the
method you'd need to extend a vector out from the closes corner in the direction of the
negative velocity of the Ball and then determine which side of that vector that the Ball
is on, I haven't got the energy to implement that in this example though, I'm saving all the
vector maths to part 4 :).
Collapse
public class Ball {
...
Similar methods are used for the paddle and the walls.
Points of Interest
Generated resources
Graphics
In this example you'll notice that there are no images or sprites included, that's because
all the graphics in this game is generated on the fly. That's easy to do if the game has
simple graphics by using the different draw methods on the Graphics object. The bricks,
ball and paddle are all generated using the current width and height of the screen, that
means that the game will look Ok even if the aspect ractio or screen size changes.
This screen shot shows the game running under emulators with different screen sizes.
Sounds
The sounds in this game are also generated, check out the SoundManager class to see how
you can get the device to play simple notes. That class also knows how to render it's
volume state to the screen similar to what you'd see on the TV screen when changing
volume.
Next Part
In the next part I'll dicuss J2ME's TiledLayer when I demonstrate how to write a top
down scroller. I'll also cover how to load resources such as a game level and continue to
show how to use offsceens, menuscreens and AI controllers.
As always, any comments on the article or the code are most welcome.
License
This article, along with any associated source code and files, is licensed under The Code
Project Open License (CPOL)