Category: programming (beginners)


Scope of Article

This article is intended for J2ME beginners and steps through every process of developing a MIDP compatible MIDlet. It is assumed that the reader has sufficient knowledge of general Java development using J2SE.

Java’s Original Promise

In the beginning Java was intended as a programming language that would power devices ranging from toasters to servers. This did not happen at first, but nearly a decade later Java found its way onto the mobile phones of millions of people and proved for the most part its ability to allow developers to “Write Once Run Anywhere”.

With this solid footing Java continues attempting to make inroads into other problem domains.

About J2ME

Programmers who have worked with J2SE expect that J2ME is its easier, little brother. Nothing could be further from the truth. J2ME development involves overcoming the limitations of mobile devices which do not exist on modern desktop let alone servers. In other words, the types of wastes you could get away with in J2SE will not be tolerated in J2ME and you’ll need to be mindful of every object instantiated and every byte used. Most of this site is dedicated to the topic of overcoming mobile device limitations and you’ll find much of the content useful in your future endeavours. In the end you’ll be able to take what you learn in J2ME and apply it in your J2SE projects to make them faster and leaner.

Getting Started: “Hello World” in J2ME

Whereas you write applications for the desktop and Applets for web browsers you write MIDlets for mobile devices.

Just as J2SE applications have an entry point (any class with a main() method) MIDlets have a class which extends the abstract MIDlet class. This class offers the startApp() method which will serve as the entry point to your MIDlet.

In J2SE, Hello World consists of merely System.out.println()-ing the static String “Hello World”. Unlike J2SE many J2ME devices do not have the concept of an on-screen console and as such we cannot avail ourselves of the System.out.println() method to print “Hello World” for us.

We must instead draw “Hello World” to a graphical canvas which we will then assign to be the currently displayed screen. If you’ve dabbled in AWT or Swing you likely have seen the Graphics object which acts as our paintbrush when painting to the Canvas. For those not familiar, the Graphics object is state-object with a current color, line-thickness, font etc…

Drawing Hello World :: The Rendering Process (in plain English)

Below are the steps required to draw “Hello World” on screen.

1. Set the current color to black
2. Fill the entire screen (using the current color)
3. Set the current color to white
4. Print “Hello World!” (using the current color and font)

So that Hello World’s font’s color is different from that of the screen we explicitly set both prior to filling the screen and printing our text.

The canvas code

Translating the steps above to Java code gives us this…

HelloWorldCanvas.java

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

public class HelloWorldCanvas extends Canvas {

	protected void paint(Graphics g) {
		
		g.setColor(0, 0, 0);
		g.fillRect(0, 0, getWidth(), getHeight());
		g.setColor(255, 255, 255);
		g.drawString("Hello World!", 20, 20, Graphics.LEFT | Graphics.BOTTOM);
	}
}

Connecting the Canvas to the MIDlet.

Since the entry class of any MIDlet must extend the MIDlet class it cannot extend the Canvas class we just created (no multiple inheritence in Java).

We need a MIDlet implementor class like the one below…

HelloWorld.java

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class HelloWorld extends MIDlet {
	
	public HelloWorld() {
		
	}
	
	protected void destroyApp(boolean conditional)
			throws MIDletStateChangeException {
		
	}
	
	protected void pauseApp() {
		
	}
	
	public void startApp() throws MIDletStateChangeException {
		
		Display.getDisplay(this).setCurrent(new HelloWorldCanvas());
	}
}

To recap, our entry class HelloWorld has its start method executed which sets our Canvas class HelloWorldCanvas to the currently displayed canvas (a MIDlet can have more than one Canvas). It then tells the canvas to begin drawing itself.


Fast forward :: The structure of a Completed MIDlet

Besides java files there are a minimum of 3 files required to build a MIDlet.

1. The JAR file

Anyone who has created a WebStart application or a server-side web application in Java will have come into contact with JAR files. They are essentially the same as ZIP archives and in the J2ME world they serve to compress the MIDlet as best as possible. They include the classes that constitute the MIDlet, and any resources such as images and data files used.

2. The JAD file

A JAD file is a lightweight proprties file in the which is offered to the target device prior to commiting to the full JAR download. It informs the device of the size of the MIDlet and any expectations and requirements it has of the device.

As the JAR files size must be mentioned and since it always changes during development it is advised to use JammedUp to automate this process with each build.

HelloWorld.jad

MIDlet-Name: HelloWorld
MIDlet-Version: 1.0
MIDlet-Vendor: VENDOR-NAME-HERE
MIDlet-Jar-URL: HelloWorld.jar
MIDlet-Jar-Size: 1523
MIDlet-1: HelloWorld,,HelloWorld
MicroEdition-Profile: MIDP-2.0
MicroEdition-Configuration: CLDC-1.1
MIDlet-Data-Size: 0
build: 1
Last-Modified: 2007-04-09 08:17:25

3. The Manifest

All MIDP compatible MIDlets must include a MANIFEST.MF file residing in the META-INF directory of the JAR file. This file reasserts some of the basic settings found in the JAD file for validation purposes and is provided in the properties file format.

MANIFEST.MF

MIDlet-Name: HelloWorld
MIDlet-Version: 1.0
MIDlet-Vendor: VENDOR-NAME-HERE
MicroEdition-Profile: MIDP-2.0
MicroEdition-Configuration: CLDC-1.1
MIDlet-1: HelloWorld,,HelloWorld

At this point you don’t need to worry too much about the contents of the JAD and manifest files. I’ll be devoting an article to their maintenance in the near future. For the purposes of this article you need only know that they are essential files for running any MIDlet.

Directory Structure

If you are intending on using the ANT build script I provide below to automate your project’s build then all of these files must appear in a particular hierarchy. Below is an image of that hierarchy. Ensure that the files are placed in the proper directories.

The Directory Structure
helloworld-folder-layout.png

Although I discuss each of build steps in detail below I want to briefly explain the directory structure’s purpose.

The src directory is where the two java files are located.

When compiled the resulting class files will be placed in the build directory along with the MANIFEST.MF file which is copied from the META-INF directory.

The lib directory houses the two main J2ME library JAR files that are needed for our project.

Upon JARring the project, the files located in the build folder will be archived and the resulting JAR files will be placed in the dist folder where the JAD file is normally housed. It is here that preverify and JammedUp process the JAR file and update the JAD file.

This is by no means the only way to layout your project’s files but it’s a basic one that has worked well for me many times.

Rewind :: The Build Process

Compilation

Either performed automatically by an IDE or done by hand or automated via ANT. The end result is a set of class files. In this example there should be two files: HelloWorld.class, and HelloWorldCanvas.class.

JARing

The project classes, the manifest and resource files are bundled into one file: HelloWorld.jar.

Preverification

Unlike J2SE classes J2ME classes must have their contents preverified prior to execution on the device. This is compensation for the limited processing power of mobile devices. This stage includes checks for illegal bytecode or constructs not supported by J2ME.

The preverify tool comes with most emulators and for Mac users the MPowerPlayer offers an OS X compatible binary.

JAD Updating

The JAD file has its contents updated to reflect the properties of the JAR file.

To download JammedUp click here.
(Learn more about JammedUp…)

Automating the build process with ANT

ANT can be used to perform all of the build steps in sequence saving you much time and effort. The source code download also includes a sample ANT build script.

build.xml

<project name="helloworld" default="dist" basedir="." >
	<property name="app.name" value="helloworld" />
	<property name="app.path" value="/${app.name}"  />
	<property name="build.home" value="${basedir}/build" />
	<property name="lib.home" value="${basedir}/lib" />
	<property name="dist.home" value="${basedir}/dist" />
	<property name="src.home" value="${basedir}/src" />
	<property name="compile.debug" value="true" />
	<property name="compile.deprecation" value="false" />
	<property name="compile.optimize" value="true" />

	<target name="all" depends="dist" description="Clean build and dist directories, then compile" />
	
	<target name="clean" description="Delete old build directory">
		<delete dir="${build.home}" />
	</target>
	
	<target name="compile" description="Compile Java sources">
		<javac srcdir="${src.home}" destdir="${build.home}" debug="${compile.debug}" deprecation="${compile.deprecation}" optimize="${compile.optimize}">
			<classpath>
				<fileset dir="${lib.home}" includes="*.jar,*.zip" />
			</classpath>
			<include name="**/*.java"/>
		</javac>
	</target>
	
	<target name="bundle" depends="compile" description="Takes the built objects and makes a JAR file.">
		<mkdir dir="${build.home}/META-INF"/>
		<copy todir="${build.home}/META-INF">
			<fileset dir="META-INF" includes="**/*.MF" />
		</copy>
		<jar jarfile="${dist.home}/HelloWorld.jar" basedir="${build.home}" includes="**/*.class" />
	</target>
	
	<target	name="preverify" depends="bundle" description="Preverifies the JAR file.">
		<exec dir="${dist.home}" executable="<path-to-project>/dist/preverify">
			<arg line="-d ${dist.home} -classpath ${lib.home}/cldcapi11.jar:${lib.home}/midpapi20.jar ${dist.home}/HelloWorld.jar"/>
		</exec>
	</target>
	
	<target
		name="dist"
		depends="preverify"
		description="Create binary distribution">

		<exec dir="${dist.home}" executable="java">
			<arg line="-cp %CLASSPATH%;.;.. -jar JammedUp.jar HelloWorld.jad -b -d -s"/>
		</exec>
		
	</target>
	
</project>

Running HelloWorld

If the build worked perfectly you now have a HelloWorld.jar and a HelloWorld.jad file pair in your dist directory. Using your emulator, instruct it to open the JAD file and you should see something similar to the below image…

Image of Hello World running in MPowerPlayer
helloworld-emulator.png

In Closing

In this article you learned how to develop, deploy and test your first MIDlet. But this is just the beginning of your journey to become a great J2ME developer. This site continues to grow and provide tips and techniques for both beginners and experts alike and I also recommend the J2MEForums for finding quick answers from programmers of all calibres.

Scope of Article

A supporting feature for any serious game, collision detection provides tangibility and depth to your game world’s objects. This article explores in brief the common types of collision detection you can employ in your games to add a sense of realism and interactivity.

The 3 Approaches

1. Grid-based Detection

This is by far the simplest form of collision detection. Essentially a grid is setup whereby the player is only allowed to stand on certain tiles. This is similar to chess where each piece occupies only a single square.

To implement this form of collision detection you need only use an array to represent each tile. This array can be as simple as a collection of booleans (false = empty, true = solid) or you can repurpose a tiled graphics layer to also store this information. Such layers store integers as indices into a tile array and it is typical to use 0 as the no tile value which is also useful for saying there is nothing with which to collide.

This approach is useful for board games like chess and for simulation games.

2. Bounding Boxes

Bounding boxes are imaginary, invisible boxes that surround solid objects. In this case collision detection involves ensuring that no two bounding boxes intersect. In the case of 3D games boxes are replaced by 3D cubes.

While easy to process this technique is not accurate unless the objects in question are rectangular and the same size as their bounding boxes. A workaround to this problem is the use of smaller bounding boxes. Since bounding boxes are invisible their size has no impact on the display of objects. This is at best a workaround and not a full solution however. Even smaller bounding boxes will not provide perfect results and in the worst cases may exhibit situations where two objects which appear to be colliding visually are not detected as a true collision.

This approach is useful for games with a large quantity of objects which can collide with the player or each other.

One caveat regarding bounding box testing

When using this technique in 3D or 2.5D games avoid floating point comparisons as bounds values can become skewed and are generally slower to compare than integer values.

3. Pixel-level collision detection

Introduced in MIDP 2.0, the Sprite class’ doPixelCollision/collidesWith methods offers pixel-level collision detection which involves detecting overlap between two objects’ visible pixels. This method is only applicable to 2D games and is more costly as the pixels from masks of both images must be tested for overlap. The larger the images, the more costly this approach becomes. There are cases, however, where this approach is the only viable one. Good examples would include testing whether a spaceship with a non-rectangle shape were really hit by an enemy
missile or one ball hit another on a billiard board.

The Need for Collision Detection

Without effective collision detection there would be nothing preventing gravity from dragging you through the ground or from walking through walls. Games like golf, tennis, and pinball simply wouldn’t work with collision detection.

When to Apply Collision Detection: Preventative VS Corrective Collision Detection

Collision detection is either applied before or after an object moves. If applied before, the object’s soon to be occupied position is used in the test and should a collision be detected the move is denied. If the collision detection is applied after the object move and a detection occurs the object
is moved back to its prior position. Both methods incur the same performance costs and which one you employ will largely be based on the ease of integration with the rest of your game logic.

Performance Costs

The time it takes to test for object collision in a scene is proportionate to the number of objects in that scene. If only two objects exist only one test need occur. If three objects exist three tests must occur. In grid based collision detection a simple lookup to see if the slot is occupied or not will suffice. With free-range 3D games each object’s moves are in need of testing.

Results of a Position Collision

When a sprite collides with an object it typically stops moving and prevent further incursions in the interest of maintaining the illusion of solidity. This, however, is not the only possible result of collision.

Fighting games often cause the injured player to be pushed back upon being punched or kicked to impress upon the player the amount of force that was just used. Billiard balls that collide transfer a portion of the kinetic energy to each other while retaining some which is used to move in a refracted direction. In these cases stopping motion is not desirable. The take away here is that each game can have its own appropriate response to collision.

In Closing

Collision detection, while a must for most games if not all games comes at a cost and decisions during the design phase need to take into account this performance impact. There are various techniques for providing solidity in game environments and they can be used singularly or in tandem.

Follow

Get every new post delivered to your Inbox.