Home > Articles > Programming > Games

This chapter is from the book

Building the Skeleton Example Program

Although I'd love to lead you through the creation of a real-time 3D multiplayer game as your first MIDlet game, I don't think it would serve as a best first impression of how MIDlets are structured and coded because of the overwhelming complexity. Instead, you learn here how to build a very simple MIDlet called Skeleton that displays information about the mobile phone as lines of text onscreen. Because this information includes important device parameters such as the game screen size and color depth, you'll find it useful in double checking the parameters of real phones.

In building the Skeleton MIDlet, you go through the same sequence of steps outlined in the previous section. This process will be very similar for every MIDlet game that you develop. Following are the steps involved in creating the Skeleton MIDlet:

  1. Code the MIDlet.

  2. Compile the MIDlet.

  3. Preverify the MIDlet.

  4. Package the MIDlet.

  5. Test the MIDlet.

The next few sections tackle each of these steps in succession, culminating in the completion of your first J2ME MIDlet.

Writing the Program Code

In this section you assemble the code for the Skeleton MIDlet a section at a time, with the complete source code listing appearing at the end. The first code for your MIDlet is the code that imports a couple of important J2ME packages. Although you can certainly avoid importing any packages and reference every J2ME class and interface with its fully qualified name (javax.microedition.midlet.MIDlet, for example), this can be quite cumbersome and ultimately makes the code hard to read. So the first two lines of your MIDlet import the two primary packages associated with MIDlet development:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

NOTE

Most Java programmers frown on importing entire packages via the * wildcard because it doesn't reveal much about what specific classes you're importing. However, it is a quick and easy way to import all the classes in a package, and for the purposes of this book, I went the easy route to keep the code as simple as possible. Feel free to import classes one at a time in your own code to make your code more explicit.

The javax.microedition.midlet package includes support for the MIDlet class itself, whereas the javax.microedition.lcdui package includes support for the GUI classes and interfaces that are used to construct MIDlet GUIs, such as the Display class. With those two packages imported, you're ready to declare the SkeletonMIDlet class, which is derived from MIDlet:

public class SkeletonMIDlet extends MIDlet implements CommandListener {

The fact that SkeletonMIDlet extends MIDlet is no surprise, but the implementation of the CommandListener interface might seem a little strange. This interface is necessary to create an Exit command that allows the user to exit the MIDlet. More specifically, the CommandListener interface is implemented so that the MIDlet can respond to command events.

The only member variable in the SkeletonMIDlet class is an SCanvas object that represents the main screen:

private SCanvas canvas;

The SCanvas class type is a custom MIDlet-specific canvas class you see in a moment that is derived from Canvas. The canvas is initialized in the startApp() method, which follows:

public void startApp() {
 if (canvas == null) {
  canvas = new SCanvas(Display.getDisplay(this));
  Command exitCommand = new Command("Exit", Command.EXIT, 0);
  canvas.addCommand(exitCommand);
  canvas.setCommandListener(this);
 }

 // Start up the canvas
 canvas.start();
}

The Exit command is created and added to the canvas so that the canvas can respond to it.

The startApp() method is called whenever the MIDlet enters the Active state, and the first step in the method is to create a canvas. The Display object for the MIDlet is obtained and passed into the canvas as part of its creation. The Exit command is then created when you pass three arguments to the Command constructor that specify the name of the command, its type, and its priority. The name of the command is user defined and appears above one of a phone's soft buttons or on a menu, depending on its priority and how many buttons are available. The command type must be one of several built-in Command constants such as EXIT, OK, or CANCEL.

The command is added to the canvas so that it becomes active. It is still necessary to designate a command listener to receive and process command events. You accomplish this by calling the setCommandListener() method and passing this, which makes the MIDlet class (SkeletonMIDlet) the command listener. That's perfect because earlier you made the class implement the CommandListener interface.

NOTE

The priority of a command is used to determine the placement of the command for user access. This is necessary because most devices have limited buttons available for MIDlet-specific usage. Therefore, only the most important commands are mapped to these soft buttons. Other commands are still available, but only from menus within the MIDlet that aren't as easily accessible as a soft button. The priority value of a command decreases with the level of importance; that is, a value of 1 is assigned to a command with the highest priority. In the Skeleton example, the Exit command is given a priority of 2, which means that it has a high priority. Of course, priority values are entirely relative, and because no other commands are in this example the value doesn't matter.

The Exit command for the Skeleton MIDlet is handled in the commandAction() method, which follows:

public void commandAction(Command c, Displayable s) {
 if (c.getCommandType() == Command.EXIT) {
  destroyApp(true);
  notifyDestroyed();
 }
}

The two arguments passed into the commandAction() method are the command and the screen on which the command was generated. Only the command is of interest in this particular example. The Command object is compared with the Command.EXIT member constant to see whether the Exit command is indeed the command being handled. If so, the destroyApp() method is called to destroy the MIDlet. The true argument to this method indicates that the destruction is unconditional, which means that the MIDlet is destroyed even if some error or exception occurs during the destruction process. The notifyDestroyed() method is called afterward to notify the application manager that the MIDlet has entered the Destroyed state.

The Skeleton MIDlet doesn't have any use for the pauseApp() and destroyApp() methods, but you must provide empty implementations for them nonetheless:

public void pauseApp() {}
public void destroyApp(boolean unconditional) {}

Although you've seen the bits and pieces separately, the complete code for the SkeletonMIDlet.java source code file is shown in Listing 3.1.

Listing 3.1 The Source Code for the SkeletonMIDlet Class Is Located in SkeletonMIDlet.java

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class SkeletonMIDlet extends MIDlet implements CommandListener {
 private SCanvas canvas;
 
 public void startApp() {
  if (canvas == null) {
   canvas = new SCanvas(Display.getDisplay(this));
   Command exitCommand = new Command("Exit", Command.EXIT, 0);
   canvas.addCommand(exitCommand);
   canvas.setCommandListener(this);
  }
  
  // Start up the canvas
  canvas.start();
 }

 public void pauseApp() {}
 
 public void destroyApp(boolean unconditional) {}
 
 public void commandAction(Command c, Displayable s) {
  if (c.getCommandType() == Command.EXIT) {
   destroyApp(true);
   notifyDestroyed();
  }
 }
}

You don't use these methods for anything in this example, but you must provide empty implementations to satisfy the MIDlet class.

To be thorough, you need to call the destroyApp() method, although notifyDestroyed() is what is really ending the MIDlet.

The remaining code for the Skeleton MIDlet example is associated with the SCanvas class, which is shown in Listing 3.2.

Listing 3.2 The SCanvas Class Serves as a Customized Canvas for the Skeleton MIDlet

import javax.microedition.lcdui.*;

public class SCanvas extends Canvas {
 private Display display;
 
 public SCanvas(Display d) {
  super();
  display = d;
 }

 void start() {
  display.setCurrent(this);
  repaint();
 }

 public void paint(Graphics g) {
  // Clear the canvas
  g.setColor(0, 0, 0);    // black
  g.fillRect(0, 0, getWidth(), getHeight());
  g.setColor(255, 255, 255); // white

  // Draw the available screen size
  int y = 0;
  String screenSize = "Screen size: " + Integer.toString(getWidth())  + " x " +
   Integer.toString(getHeight());
  g.drawString(screenSize, 0, y, Graphics.TOP | Graphics.LEFT);

  // Draw the number of available colors
  y += Font.getDefaultFont().getHeight();
  String numColors = "# of colors: " + 
Integer.toString(display.numColors());
  g.drawString(numColors, 0, y, Graphics.TOP | Graphics.LEFT);

  // Draw the number of available alpha levels
  y += Font.getDefaultFont().getHeight();
  String numAlphas = "# of alphas: " +
   Integer.toString(display.numAlphaLevels());
  g.drawString(numAlphas, 0, y, Graphics.TOP | Graphics.LEFT);

  // Draw the amount of total and free memory
  Runtime runtime = Runtime.getRuntime();
  y += Font.getDefaultFont().getHeight();
  String totalMem = "Total memory: " +
   Long.toString(runtime.totalMemory() / 1024) + "KB";
  g.drawString(totalMem, 0, y, Graphics.TOP | Graphics.LEFT);
  y += Font.getDefaultFont().getHeight();
  String freeMem = "Free memory: " + Long.toString(runtime.freeMemory()
 / 1024) + "KB";
  g.drawString(freeMem, 0, y, Graphics.TOP | Graphics.LEFT);
 }
}

This line of code is extremely important because it sets this canvas as the current canvas for the MIDlet.

It's important to clear the background before you begin drawing content.

The SCanvas class is derived from the Canvas class, and accepts a Display object as the only parameter to its constructor. The constructor simply sets the display member variable so that the MIDlet display is accessible throughout the canvas code. The start() method calls the setCurrent() method on the Display object to set the canvas as the current screen. It's possible to have multiple screens in a MIDlet, in which case you can use the setCurrent() method to switch between them. The start() method calls repaint() to force a paint of the canvas so that it is initially painted properly.

NOTE

Although the SCanvas class in the Skeleton MIDlet is derived from Canvas, most of the examples throughout the book actually use canvas classes derived from GameCanvas, which provides game-specific features such as double-buffered graphics and efficient key handling. These features aren't necessary in the Skeleton example.

The painting of the canvas represents the majority of the code in the Skeleton MIDlet, and is handled by the paint() method. It isn't important for you to understand the details of this graphics code right now—the next chapter tackles mobile game graphics in detail. I will give you a quick summary, however, just in case you want to try and follow along as a look-ahead to the next chapter.

The method begins by clearing the canvas with a solid color fill in black. The paint color is then changed to white to draw the text. The screen size is obtained first, and then drawn, centered horizontally near the top of the screen. The number of available colors and alpha levels are obtained next and displayed below the screen size. Finally, the amounts of total and free memory are determined, and displayed last.

NOTE

The number of alpha levels supported by a phone determine how much control you have over transparent areas in graphical images. For example, all phones support at least two alpha levels, which correspond to a pixel being either fully opaque or fully transparent. Some phones support as many as 256 alpha levels, which allow you to create graphics with partial transparency, where you can see through an object in varying amounts.

Now that the source code is complete, you're almost ready to build and test the Skeleton MIDlet. But first you need to create a couple of important support files that are required for packaging the MIDlet for distribution.

Preparing the MIDlet for Distribution

Packaging a MIDlet game for distribution involves compressing the various files used by the MIDlet into an archive known as a JAR file. In addition to compressing the preverified class files for a MIDlet into a JAR file, you must also include in the JAR file any resources associated with the MIDlet, as well as a manifest file that describes the contents of the JAR file.

In the case of the Skeleton MIDlet, the only resource is an icon that is displayed next to the MIDlet name on a device. I explain about the icon in just a moment. For now, let's focus on the manifest file. The manifest file is a special text file that contains a listing of MIDlet properties and their respective values. This information is very important because it identifies the name, icon, and classname of each MIDlet in a JAR file, as well as the specific CLDC and MIDP version targeted by the MIDlets in the JAR file. Remember that multiple MIDlets can be stored in a single JAR file, in which case the collection is known as a MIDlet suite.

NOTE

All the examples throughout the book target MIDP 2.0 and CLDC 1.0. Although some mobile phones support CLDC 2.0, CLDC 1.0 is sufficient for most game programming. However, MIDP 2.0 is extremely important because game features were added to the MIDP API as of version 2.0.

The manifest file for a MIDlet suite must be named Manifest.mf, and must be placed in the JAR file with the MIDlet classes and resources. Following is the code for the Manifest file associated with the Skeleton MIDlet:

MIDlet-1: Skeleton, /icons/Skeleton_icon.png, SkeletonMIDlet
MIDlet-Name: Skeleton
MIDlet-Description: Skeleton Example MIDlet
MIDlet-Vendor: Stalefish Labs
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0

The first entry in the manifest file is by far the most important because it specifies the name of the MIDlet, along with its icon file and its executable class name. You might notice that the property is named MIDlet-1; if you were to include additional MIDlets in this MIDlet suite, you would reference them as MIDlet-2, MIDlet-3, and so on. The MIDlet-Name, MIDlet-Description, MIDlet-Vendor, and MIDlet-Version properties all refer to the MIDlet suite as a whole. However, in this case the Skeleton MIDlet is the only MIDlet in the suite, so it's okay to refer to the entire suite as Skeleton. The last two properties identify the versions of the configuration and profile that the MIDlet suite targets, which in this case are CLDC 1.0 and MIDP 2.0.

Earlier I mentioned that you must include any resources in a JAR file along with the MIDlet classes and the manifest file. At the very least a MIDlet will have an icon as a resource. This icon is simply a 12x12 pixel image that is stored in the PNG image format. It can be a color or black-and-white image, depending on whether or not the mobile phone you're targeting has a color screen. I created a small picture of a skull to use as the Skeleton icon, and stored it in a file called Skeleton_icon.png.

One small caveat in regard to the icon for a MIDlet is that it must be stored in a folder named icons within the MIDlet JAR file. Similar to ZIP files, JAR files enable you to store files within folders inside of the archive. To place a file in such a folder inside a JAR file, you must reference it from a subfolder when you add it to the JAR file. It is somewhat standard convention to place MIDlet resources in a folder named res beneath the folder where the source code files are located. Knowing this, a simple solution for the icon is to place it in an icons folder located beneath the res folder.

Figure 3.2Figure 3.2 Adhering to a simple folder structure for your MIDlet source files helps keep things organized.

Speaking of folder structure and MIDlets, there is a standard way to organize folders for MIDlet source files. Figure 3.2 shows the folder structure you should try and stick to when organizing your MIDlet source files.

The different folders in the figure are used to store the following:

  • src—Java source code files

  • bin—Manifest file, JAD file, and JAR file

  • classes—Compiled Java bytecode files

  • tmpclasses—Compiled and verified Java bytecode files

  • res—Resource files other than icons (images, sounds, and so on)

  • res/icons—Icon files

NOTE

The example MIDlets included in the J2ME Wireless Toolkit, including the example games you saw in the previous chapter, adhere to this same folder structure.

In addition to the manifest file that resides in the JAR file for a MIDlet, an additional application descriptor file is required for distributing a MIDlet. An application descriptor file, or JAD file, contains information similar to that found in a manifest file. The JAD file is used by the Java emulator when you test a MIDlet suite. Following is the JAD file for the Skeleton MIDlet:

MIDlet-1: Skeleton, /icons/Skeleton_icon.png, SkeletonMIDlet
MIDlet-Name: Skeleton
MIDlet-Description: Skeleton Example MIDlet
MIDlet-Vendor: Stalefish Labs
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0
MIDlet-Jar-Size: 2706
MIDlet-Jar-URL: Skeleton.jar

This is your own version number for the MIDlet, which in this case means Skeleton 1.0.

If this size (in bytes) doesn't match the exact size of the JAR file, the MIDlet won't run.

With the exception of the last two entries, the JAD file contains information with which you are already quite familiar. The last two entries specify the size of the JAR file (in bytes) for the MIDlet and the name of the JAR file. It is important that you update the size of the JAR file any time you repackage the MIDlet because the size is likely to change each time you rebuild the MIDlet.

Building and Testing the Finished Product

The previous chapter introduced you to the KToolbar visual development tool that allows you to build and run MIDlets with very little effort. To build the Skeleton MIDlet with KToolbar, you must first copy the entire Skeleton MIDlet folder to the apps folder beneath the J2ME Wireless Toolkit installation folder. After the Skeleton folder has been copied, you can open the Skeleton project from within KToolbar by clicking the Open Project button on the toolbar.

After the project opens, just click the Build button on the toolbar to build the Skeleton MIDlet. After the project is built, click the Run button on the toolbar to run it in the J2ME emulator. Figure 3.3 shows the Skeleton MIDlet available to be run within the emulator.

Figure 3.3Figure 3.3 The Skeleton MIDlet is made available for running within the application manager of the J2ME emulator.

NOTE

All the source code and relevant files for the example MIDlets throughout the book are available on the accompanying CD-ROM.

Figure 3.4Figure 3.4 The Skeleton MIDlet displays information about the mobile phone such as the screen size and number of available colors.

Because Skeleton is the only MIDlet in the MIDlet suite, it is already highlighted and ready to be launched. To run it, click the Action button on the device keypad, which appears between the arrow keys, or the Launch soft button; you can also press Enter on your computer keyboard. Figure 3.4 shows the Skeleton MIDlet executing in the emulator.

To exit the Skeleton MIDlet, click the soft button beneath the word Exit. This invokes the Exit command and results in the MIDlet being destroyed. You can also exit a MIDlet by clicking the red End button, which is used on a real device to end a phone call.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020