Developing Applications with the Java APIs for Bluetooth (JSR-82)

Developing Applications with the Java APIs for Bluetooth (JSR-82)



This paper covers the Java API for Bluetooth (JSR-82) with respect to Sony Ericsson devices. It starts by introducing the Bluetooth technology, followed by the Java APIs for Bluetooth, and how to use them.


Currently, these APIs are currently available in the Sony Ericsson P900/P908 handsets.


Click here to view “Developing Applications with the Java APIs for Bluetooth (JSR-82)”



Click here to view the Training Materials (.zip) associated with this article.


Real World Experiences with the WMA and the Push Registry

Real World Experiences with the WMA and the Push Registry


Introduction


This article will recount my experiences on a recent project that involved use of the Wireless Messaging API (WMA) and the Push Registry. The Push Registry is a feature new to the MIDP 2.0 spec, and the WMA, while not a MIDP 2.0 feature, is an optional feature that can be found on several MIDP 1.0 and 2.0 phones.


The functionality achievable with the Push Registry is summarized as follows: the device first receives a message, and if the message contains a header that defines a specific port, the device will pass the message to the application that has been registered for that port. For Java applications, though, the message first gets passed to the JAM (Java Application Manager), and it in turn will pass the message to the J2ME application that has registered the port number.


The WMA allows an application to send and receive SMS or CBS messages while the application is running. When the application is not running (which is probably most of the time), it cannot receive messages unless it is registered with the Push Registry. Controlled by the JAM, the Push Registry will launch the application which has previously registered the port to which the incoming message is destined. The Push Registry can also be set to launch an application at predefined time, but that function will not be discussed here (as it does not apply to using the WMA).



Handling incoming messages


The WMA JavaDocs (specifically, the javax.wireless.messaging.MessageListener page) has an excellent reference implementation for receiving messages. Essentially, the application’s main thread implements the MessageListener interface and performs the main application logic.When a message arrives, a separate object (possibly within another thread) is passed the message and handles it. This is the model I implemented in my several of my client’s projects (with some subtle transformations, of course), and it works well (see Code Sample 1).


This implementation applies to messages received not only while the application is running, but also when the application is started due to a Push Registry notification. When the application is launched in this later way, the Push Registry is queried to see if messages are waiting for this application and processes any that are there.


One issue you may want (or have) to consider at the client application level is how to deal with multiple messages arriving at the same time. To handle all of the messages, they will need to be handled serially, or else some of the messages will be dropped. The downside of this is that if for each message the implementation might display some type of alert message or invoke a function of the application. So sending multiple messages to a destination at once is not a good idea. As always, and especially with this type of messaging we must be vigilant about making the user experience as friendly and simple as possible.


 


Security considerations with messages


An issue to consider with incoming messages is the authenticity of the sender. Assuming the sender had the proper privileges to send an SMS message on the carrier’s network, and further assuming the sender knew the port number at which the Java application is registered in the JAM (via the Push Registry or a live J2ME application that has requested a port), you still may want to include some application-specific way of authenticating the message.


The MIDlet-Push- parameter in the JAD has three comma-delimited values, the last of which is . Defining this value, which is basically a URL, allows incoming messages to be received only from the stated address. While this may be good for friendly network communications, this cannot be relied upon to be completely secure. Thus, you may want to define your own mechanism for validating the incoming message. The message may have cleared the device and the JAM’s security restrictions, but that does not mean the message is safe or valid.


One technique is to embed a binary hash at the head of every message sent by your server. This hash will then be checked for validity by your application every time a new message is received. In this scenario, the message is still read by the application, but it can be verified before starting to perform application logic.


In the current mobile space, security concerns of this ilk might not be so vital, but it may be crucial for enterprise-type applications.


 


Provisioning the Application


There are some additional deployment issues to take into account when using WMA or Push Registry. Applications using the Push Registry must be provisioned OTA (Over The Air), as installing via USB/infrared is not guaranteed to work (or, at the least, will not be one hundred percent functional). Assuming your OTA server is properly configured (correct MIME types, host address, and so on), the first issue to work through is the Push Registry URL that must be declared in the JAD property MIDlet-Push-. The URL will look like “sms://:16885”. The most difficult and unpredictable part of this URL is the all Java applications on the device that use the Push Registry must have a unique port number. If an application is already registered on port 16885, and the user downloads a new application that also tries to use port 16885, the installation of the new application will fail. As there is no way to know beforehand what ports are in use by other Java application, its kind of a gamble as to which ports are unused. At this time (mid-2004), not many applications use the Push Registry functionality, so port number conflicts should not be too much of a concern. In my projects, however, I did have to handle it.


The most flexible mechanism to handle this situation is to dynamically generate a port number for the application when the user chooses to download and install your application; in other words, a dynamically-created JAD file will be sent to the device (Note: this is not possible on some operators, particularly if the operator provisions the J2ME application themselves). As you will be tracking the user’s profile data anyway (in order to send SMS messages to the device in the first place), retaining a dynamically generated port number (versus a “one app-one port number” paradigm) is almost no extra work.


To create a dynamically generated port number, we chose to generate a random value between the port numbers 16000 and 16999 (*1). Beware that some OEMs/operators predefine some of these port numbers on their devices, so you may consider maintaining a list of “port numbers to avoid” which is incorporated into your random port number generator’s algorithm.


Now for the tough question: what happens when the user’s device already has an application installed which uses the SMS port number you have defined in your JAD? When this occurs, the JAM is required to halt the installation process and consider the process as failed.


There is a JAD attribute that can be set, MIDlet-Install-Notify, whose value is a URL to which the device can send a message to indicate the success or failure of the installation. According to the OTA provisioning spec (*2) (which is now part of the MIDP 2.0 spec, JSR-118 (*3)), the device will send a status report regarding the result of the install, to which the server can only reply with a HTTP 200. (The server can send more data, but, according the specs, the device must ignore it.) The possible response messages from the device are as follows (see the MIDP 2.0 spec for full details):


 


Status Code Status Message
900 Success
901 Insufficient Memory
902 User Canceled
903 Loss of Service
904 JAR size mismatch
905 Attribute mismatch
906 Invalid Descriptor
907 Invalid JAR
908 Incompatible Configuration or Profile
909 Application authentication failure
910 Application authorization failure
911 Push registration failure
912 Deletion notification
 


You can setup a server-side component to listen for incoming messages about install status reports. In addition to recording additional information about the deployment of your application, you can track and react to installation failures based on the status code returned. One possibility for recovering from a failed installation is to send a WAP Push message to the device with a URL for downloading the JAD and application again. If the user is reinstalling the application due to a port number conflict, the previous port number should be excluded from new port numbers that are generated. Admittedly, this WAP Push technique was not implemented in our projects due to the complex (and potentially confusing) nature of the user interaction.


 


Getting messages to the device


For various reasons, not just anybody is allowed to send SMS messages to devices. Thus, a mobile development company ends up with two options: forge a relationship with each individual carrier or partner with an SMS aggregator. As the former option is far from being a trivial task (the business needs alone are daunting), working with an SMS aggregator is a viable option as they have already created partnerships with many carriers and usually have a simple API that you can use (rather than writing your own SMPP code).


Two leading aggregators in the U.S. are MBlocks and SimpleWire. As my company had contacts there, we opted to use SimpleWire’s services. Typically, you have an account with the aggregator and pass your account information with every SMS message that you send. SimpleWire’s API is simple and does not take much time to integrate into your server-side components (my current implementation consists of about fifteen lines of simple code – see Code Sample 2).


One quasi-problem I ran into is that after my servlet transmitted a message there often was a delay before the device received it (3 to 10 seconds). For the vast majority of uses, though, the delay will be irrelevant, although it is something to be aware of.


Another issue to keep in mind is that messages are limited in the size of data they can hold. While this does vary from carrier to carrier, the maximum data size for some carriers is 160 characters (single-byte characters, that is) per message. While you may have more data space with some carriers, it is probably best to keep message length (either text or binary) to an absolute minimum. To make matters more difficult, the SMS port number must be embedded into the body of the message, and if you employ some type of message security (see the Security considerations with messages section), your data length will be even less. Still, with a delicate combination of live data from the incoming message and predefined application elements, you should be able to transmit a meaningful message to the user and invoke special application functions all within one message.


 


Emulators


In the J2ME/mobile Java space, working with the various emulators from the different OEMs, as well as Sun’s Wireless Toolkit (WTK), is typically a hit or miss situation. While an emulator may excel at one set of functions, it may completely crash or throw a litany of exceptions when asked to perform other functions. Thus, it’s always good to keep a handful of emulators around when debugging and testing.


For myself, I found the WTK to work well for testing the WMA and Push Registry functions. The WTK has a feature to send SMS and CBS messages to the emulator; the messages can either be text or binary. The project I was involved with involved one specific phone which handed only binary messages to the Java layer. That is, only instances of javax.wireless.messaging.BinaryMessage were passed to the application, and attempts to cast the incoming message to a javax.wireless.messaging.TextMessage threw a ClassCastException. Thus I needed to pass binary to the emulator, which it in turn passed to the application. The WTK only sends binaries via a file that is written on the hard disk, so to test the J2ME application, I wrote a small Java program to write binary data to a file on the hard disk. Of course, the format of the binary file matched the format that my a J2ME application was expecting. Then I used the WTK to send that binary to the emulator, at which point it could be read and parsed inside my application. This method proved to be a reliable test when compared to the operation of the device.


The Nokia emulators also support the WMA, and others may as well, so instead of using the “Default Color Phone” emulator with the WTK, you can setup the WTK to use the Nokia (or other OEM) emulators. Admittedly, I found the interaction between the WTK and non-WTK emulators a little lacking when using advanced functionality, so I decided to stick with the WTK’s “Default Color Phone” emulator most of the time. Furthermore, the skin for the “Default Color Phone” emulator of the WTK 2.1 seems to impress non-technical types, so you may get extra “ooos” and “ahhs” from the bosses above.


To use the WTK for WMA/Push Registry testing, though, you must “install” the application via OTA to emulator, instead of just clicking “Run”. To install via OTA, select “Run via OTA” from the Project menu. The process is simple; just follow the screens in the emulator. When you are done, the application will appear to the emulator as if it had been installed OTA, and you can use functions like the WMA and Push Registry easily. Both functions can be invoked from the WTK’s WMA console (File – > Utilities, click “Open Console” in the WMA section of the window). Text messages are easy to push to the emulator, but if your real world device only allows you BinaryMessage instances, pass the emulator a file containing the binary payload data you want to send.


 


Conclusion


The issues involved with getting a WMA/Push Registry-enabled application to market can seem daunting, but the benefits are clearly worthwhile. Through these mechanisms you can have a much more dynamic interaction with your users to aide in customer retention and brand loyalty. The one truly important caveat is the varying costs of SMS traffic. Thus, the message must be completely relevant to user and their interaction with the application. Also, the user must have a way to opt-in and opt-out of messages they may receive from your company. With a well-conceived business model, users may consider it essential to receive messages on their device about your application or services.


 


 


Code Sample 1 – A simplified version of the message handling classes


 


class MessageListenerImpl implements MessageListener


{


public void notifyIncomingMessage(MessageConnection mCon)


{ messageReader.handleMessage(); }


}


 


class WirelessMessageReader implements Runnable


{


private boolean readMessages = true;


private int pendingMessages;


private MessageConnection msgConn = null;


 


public void run()


{


while(readMessages)


{


synchronized(this)


{


if(pendingMessages == 0)


{


try { wait(); }


catch(InterruptedException ie) {}


}



pendingMessages–;


}



Message message = null;



try


{


Message message = msgConn.receive();


/* parse payload */


}


catch(IOException ioe) {}


}


}



synchronized void handleMessage()


{


pendingMessages++;


notify();


}


}


 


Code Sample 2 – integration with the SimpleWire API.


 


import com.simplewire.sms.*;


 


public void sendSmsMessage(String msisdn, short msgPort)


{


SMS smsMessage = new SMS();


smsMessage.setSubscriberID(YOUR_SUBSCRIBER_ID);


smsMessage.setSubscriberPassword(YOUR_PASSWORD);


smsMessage.setMsgPin(“+1” + msisdn);


smsMessage.setDestPort(msgPort);


smsMessage.setMsgText(“Your msg here”);


smsMessage.msgSend();


}


 


 


 


——————————————————————————–


1.  Sony Ericsson, “Advanced Message Coding using JSR 120”, section 3.4.


2. Sun Microsystems, “Over The Air Initiated Provisioning Recommended Practice for the .Mobile Device Profile”


3. Sun Microsystems, Mobile Information Device Profile, v2.0 (JSR-118)


J2ME Game Optimization Secrets (part 5)

Other Techniques


One technique I was unable to include in my example code was the optimal use of a switch() statement. Switches are very commonly used to implement Finite State Machines, which are used in game Artificial Intelligence code to control the behavior of non-player actors. When you use a switch, it is good programming practice to write code like this:


  public static final int STATE_RUNNING = 1000;
  public static final int STATE_JUMPING = 2000;
  public static final int STATE_SHOOTING = 3000;
  switch ( n ) {
    case STATE_RUNNING:
      doRun();
    case STATE_JUMPING:
      doJump();
    case STATE_SHOOTING:
      doShoot();
  }


There’s nothing wrong with this, and the int constants are nice and far apart, in case we might want to stick another constant in between RUNNING and JUMPING, like STATE_DUCKING = 2500. But apparently switch statements can be compiled into one of two byte codes, and the faster of the two is used if the ints used are close together, so this would be better:


  public static final int STATE_RUNNING = 1;
  public static final int STATE_JUMPING = 2;
  public static final int STATE_SHOOTING = 3;


There are also some optimizations you can perform when using a Fixed Point math library. First, if you’re doing a lot of division by a single number, you should instead work out the inverse of that number and perform a multiplication. Multiplication is slightly quicker than division. So instead of…


  int fpP = FP.Div( fpX, fpD );
  int fpQ = FP.Div( fpY, fpD );
  int fpR = FP.Div( fpZ, fpD );


…you should rewrite it like this:


  int fpID = FP.Div( 1, fpD );
  int fpP = FP.Mul( fpX, fpID );
  int fpQ = FP.Mul( fpY, fpID );
  int fpR = FP.Mul( fpZ, fpID );


If you’re performing hundreds of divisions every frame, this will help. Secondly, don’t take your FP math library for granted. If you have source for it, open it up and take a look at what’s going on in there. Make sure all the methods are declared final static and look for other opportunities to improve the code. For example, you may find that the multiplication method has to cast both ints to longs and then back to an int:


public static final int Mul (int x, int y) {
  long z = (long) x * (long) y;
  return ((int) (z >> 16));
}


Those casts take time. Collision detection using bounding circles or spheres involves adding the squares of ints together. That can generate some big numbers that might overflow the upper bound of your int Fixed Point data type. To avoid this, you could write your own square function that returns a long:


    public static final long Sqr (int x) {
      long z = (long) x;
      z *= z;
      return (z >> 16);
    }


This optimized method avoids a couple of casts. If you’re doing a great deal of Fixed Point math, you might consider replacing all of the library calls in the main game loop with the long-hand math. That will save a lot of method calls and parameter passing. You may also find that when the math is written out manually you can reduce the number of casts that are required. This is especially true if you are nesting several calls to your library, e.g.


  int fpA = FP.Mul( FP.toInt(5),
                    FP.Mul( FP.Div( 1 / fpB ),
                    FP.Mul( FP.Div( fpC, fpD ),
                    FP.toInt( 13 ) ) ) );


Take the time to unravel nested calls like this and see if you can reduce the amount of casting. Another way to avoid casting to longs is if you know that the numbers involved are small enough that they definitely won’t cause an overflow.


To help with high-level optimization, you should look for articles on game programming. A lot of the problems presented by game programming such as fast 3D geometry and collision detection have already been solved very elegantly and efficiently. If you can’t find Java source, you will almost certainly find C source or pseudo-code to convert. Bounds checking, for example, is a common technique that we could have used inside our paint() method. Instead of clearing the entire screen every time, we really only need to clear the section of the screen that changes from frame to frame. Because graphics routines are relatively slow you will find that the extra housekeeping required to keep track of which parts of the screen need to be cleared is well worth the effort.


Some phone manufacturers offer proprietary APIs that help programmers get around some of the limitations J2ME presents, such as lack of sound, lack of Image transparency, etc. Motorola, for example, offers a floating point math library that uses floating point math instructions on the chip. This library is much faster than the fastest Fixed Point math library, and a lot more accurate. Using these libraries completely destroys the portability of your code, of course, but they may be an option to consider if deployment on many different handsets is not a concern.


Conclusions
Only optimize code if you need to
Only optimize where it counts
Use the profiler to see where to optimize
The profiler won’t help you on the device, so use the System timer on the hardware
Always study your code and try to improve the algorithms before using low-level techniques
Drawing is slow, so use the Graphics calls as sparingly as possible
Use setClip() where possible to minimize the drawing area
Keep as much stuff as possible out of loops
Pre-calculate and cache like crazy
Strings create garbage and garbage is bad so use StringBuffers instead
Assume nothing
Use static final methods where possible and avoid the synchronized modifier
Pass as few parameters as possible into frequently-called methods
Where possible, remove method calls altogether
Unroll loops
Use bit shift operators instead of division or multiplication by a power of two
You can use bit operators to implement circular loops instead of modulo
Try to compare to zero instead of any other number
Array access is slower than C, so cache array elements
Eliminate common sub-expressions
Local variables are faster than instance variables
Don’t wait() if you can callSerially()
Use small, close constants in switch() statements
Look inside your Fixed Point math library and optimize it
Unravel nested FP calls to reduce casting
Division is slower than multiplication, so multiply by the inverse instead of dividing
Use tried and tested algorithms
Use proprietary high-performance APIs with care to preserve portability
Where to next?
Optimization is a black art. At the heart of any computer lies the CPU and at the heart of Java lies a virtual CPU, the JVM. To squeeze the last ounce of performance from the JVM, you need to know a lot about how it functions beneath the hood. Specifically, you need to know what things the JVM can do fast, and what it does slowly. Look for sites with solid information on the inner workings of Java. You don’t necessarily have to learn how to program in byte code, but the more you know, the easier it will be to come up with new ways to optimize your applications for performance.


There’s no substitute for experience. In time you will discover your own secrets about the performance characteristics of J2ME and of the handsets you are developing for. Even if you can’t code around certain idiosynchrasies, you could design your next game around them. While developing my game I found that calling drawImage() five times to draw five images of 25 pixels each is much slower than calling it once to draw an image five times the size. That knowledge will definitely help shape my next game.


Good luck, and have fun.


Resources:



  1. J2ME’s official web site contains the latest on what’s happening on this front.

  2. Like wireless games? Read the Wireless Gaming Review.

  3. Discuss J2ME Game Development at j2me.org

  4. A great site on many aspects of Java Optimization

  5. Another great site on Optimization

  6. Many articles on J2ME performance tuning

  7. The amazing Graphics Programming Black Book by Michael Abrash
  8. The Art of Computer Game Design by Chris Crawford

J2ME Game Optimization Secrets (part 4)

Low-Level Optimization


All programmers are familiar with the concepts of the sub-routine and the function – separate out common code to avoid duplicating it in several places around your app. Unfortunately, this commonly “Good” programming practice can impact performance because method calls involve a certain amount of overhead. The easiest way to reduce the amount of time it takes to call a method is by carefully selecting its declaration modifiers. Our programmer has been very cautious, and has made his work() and workMore() methods synchronized, in case some other thread might call them simultaneously. This is all well and good, but if we’re serious about performance, we often have to make sacrifices, and today we will be sacrificing safety.


Well, not really. We know for a fact that no-one else is going to be calling these methods, so we can de-synchronize them without too much worry. What else can we do? Take a look at this list of method types:


synchronized methods are the slowest, since an object lock has to be obtained
interface methods are the next slowest
instance methods are in the middle
final methods are faster
static methods are fastest
So we definitely shouldn’t be making anything synchronized, and it looks like we can even mark work() and workMore() as final static methods. Doing this cut 1% from the time the emulator spent inside run().


Another factor that affects the performance of method calls is the number of parameters passed into the method. We are calling workMore() 51712 times, passing an int array and two ints into the method and returning an int each time. In this, somewhat trivial, example it’s going to be easy to collapse the workMore() method into the the body of work() to avoid the call entirely. In the real world, that decision might be harder to make, especially if it means that code will be duplicated around your application. Test with the profiler and on the device to see how much difference it actually makes before taking that step. If you can’t remove the method altogether, try to reduce the number of parameters you’re passing into it. The more parameters, the greater the overhead.


  public final static int work( int[] n ) {
    divisor = 1;
    r = 0;
    for ( int j = 0 ; j < DIVISOR_COUNT ; j++ ) {
      for ( int i = 0 ; i < n.length ; i++ ) {
        r += n[i] * n[i] / divisor + n[i];
      }
      divisor *= 2;
    }
    return r;
  }


Wow! Removing the call to workMore() slashed the amount of time spent in run to 9.96%. From here on it will be uphill all the way. Let’s look at two general optimization techniques – strength reduction and loop unrolling.


Strength reduction is where you replace a relatively slow operation with a fast one that does exactly the same thing. The most common example is using the bitshift operators, which are equivalent to multiplication and division by a power of two. For example, x >> 2 is equivalent to x / 4 ( 2 to the power of 2 ) and x << 10 is equivalent to x * 1024 ( 2 to the power of 10 ). By an amazing coincidence, our divisor is always a power of 2 (isn’t that lucky!) so we can use bitshifting in place of division.


Unrolling loops reduces the overhead of flow control code by performing more than one operation each time through the loop, executing fewer iterations, or even removing the loop entirely. As our DIVISOR_COUNT is only 8, it’s going to be easy to unroll our outer loop:


public final static int work( int[] n ) {
  r = 0;
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  n[i] * n[i]  + n[i]; }
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  (n[i] * n[i] >> 1) + n[i]; }
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  (n[i] * n[i] >> 2) + n[i]; }
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  (n[i] * n[i] >> 3) + n[i]; }
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  (n[i] * n[i] >> 4) + n[i]; }
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  (n[i] * n[i] >> 5) + n[i]; }
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  (n[i] * n[i] >> 6) + n[i]; }
  for ( int i = 0 ; i < n.length ; i++ ) { r +=  (n[i] * n[i] >> 7) + n[i]; }
  return r;
}


Two important points. First, you’ll notice that unrolling our loop requires us to duplicate some code. This is the last thing you want in J2ME, where developers are often fighting JAR bloat, but remember that the JARing process involves compression, and compression works best on repetitive data, so the above code might not make as big an impact on your jar size as you might think. Again, it’s all about the trade-off. Your code can be small, fast, easy to read. Pick any two. The second point is that the bitshift operators have a different precedence from / and *, so you will often have to put parentheses around statements that otherwise would not need them.


Unrolling the loop and using the bitshift operators shaved off slightly more than 1%. Not bad. Now let’s turn our attention to array access. Arrays are fast data structures in C, but for that reason they can also be dangerous – if your code starts accessing array elements beyond the end of the array, you’re over-writing sections of memory you shouldn’t be messing with and the consequences will most likely be dire.


In contrast, Java is a very safe language – running off the end of an array like that will simply throw an ArrayIndexOutOfBoundsException. The system checks for an invalid index value every time you access an array, which makes array access slower than in C. Again, there’s nothing we can do about the internals of array handling in Java, but we can work around it by making smart decisions. In the code above, for example, we’re accessing n[i] 24 times. We can omit a lot of those array accesses by storing the value of n[i] in a variable. A little high-level thought also reveals that we can rearrange things in a much smarter way like this…


  private static int divisor;
  private static int r;
  private static int ni;
  public final static int work( int[] n ) {
    r = 0;
    for ( int i = 0 ; i < n.length ; i++ )  {
      ni = n[i];
      r +=  ni * ni + ni;
      r +=  (ni * ni >> 1) + ni;
      r +=  (ni * ni >> 2) + ni;
      r +=  (ni * ni >> 3) + ni;
      r +=  (ni * ni >> 4) + ni;
      r +=  (ni * ni >> 5) + ni;
      r +=  (ni * ni >> 6) + ni;
      r +=  (ni * ni >> 7) + ni;
    }
    return r;
  }


We’ve eliminated a whole lot of looping and array accessing. Let’s now eliminate a whole lot of squaring using a technique known as common sub-expression elimination. We’re calculating the square of n[i] eight times each time through our loop. We can eliminate those repetitive calculations by working out the square once at the beginning:


  private static int r;
  private static int ni;
  private static int nis;
  public final static int work( int[] n ) {
    r = 0;
    for ( int i = 0 ; i < n.length ; i++ )  {
      ni = n[i];
      nis = ni * ni;
      r +=  nis  + ni;
      r +=  (nis >> 1) + ni;
      r +=  (nis >> 2) + ni;
      r +=  (nis >> 3) + ni;
      r +=  (nis >> 4) + ni;
      r +=  (nis >> 5) + ni;
      r +=  (nis >> 6) + ni;
      r +=  (nis >> 7) + ni;
    }
    return r;
  }


…which cuts down the time spent in run() to 6.18%. Not bad at all. Before we move on, let me say a couple more things about arrays. A little high-level optimization ( i.e. “thought” ) might reveal that an array isn’t necessarily the right data structure to use. Think about using a linked list or some other structure if that would increase performance. Secondly, if you are going to use an array and you ever need to copy its contents into another array, always use System.arraycopy(). It’s way faster than trying to write your own routine to do the same thing. Finally, arrays are generally higher performance than the java.util.Vector object. If you require the kind of functionality that a Vector offers, think about writing it yourself and run tests to make sure your code is faster.


Okay, we’re really running out of things to optimize. We just introduced another couple of variables to cache the array element and the value of that element squared. You may have been wondering why those variables have been declared outside the body of the method declaration. They’re outside because even declaring ints takes a little time and we should keep that out of our loop, right? Wrong!


Assume nothing. It’s true that we’re saving time by avoiding the int declarations, but this code may actually be slower than if those variables were declared locally, inside the method. That’s because local variables perform better, as the JVM takes longer to resolve variables declared outside a method. So let’s turn them into local variables.


Finally, we can tweak our for() loop slightly. Computers are generally better at comparing a number to zero than to any other non-zero number. That means we can turn our loop upside down and rewrite the method like this so we’re comparing against zero:


  public final static int work( int[] n ) {
    int r = 0;
    int ni;
    int nis;
    int i;
    for ( i = n.length ; –i >= 0 ; ) {
      ni = n[i];
      nis = ni * ni;
      r +=  nis  + ni;
      r +=  (nis >> 1) + ni;
      r +=  (nis >> 2) + ni;
      r +=  (nis >> 3) + ni;
      r +=  (nis >> 4) + ni;
      r +=  (nis >> 5) + ni;
      r +=  (nis >> 6) + ni;
      r +=  (nis >> 7) + ni;
    }
    return r;
  }


And that’s it! This code may be a little faster, but the profiler results are less conclusive. What is clear is that this method is tougher to read. There may be further room for improvement, but let’s instead take another look at our paint() method, to see if any of what we learned can be introduced there.


Remember what we learned about local variables? If you are forced to use an instance variable and you are referencing that variable multiple times inside a method, it might be worth introducing a local variable so that the JVM only has to resolve the reference once. You’ll introduce a declaration and an assignment which will slow things down, but as a rule of thumb, we’ll use that technique if an instance variable is referenced more than twice.


We can also use strength reduction in our paint() method to replace the modulo operator with a circular counter that uses a bit operator. This is only possible because the length of our random numbers cache array is (amazingly!) a power of two. Finally, we can juggle our comparisons to always compare with zero. Here’s our new and improved paint() method:


  public void paint(Graphics g) {
    StringBuffer sb = stringBuffer;
    Graphics ig = imageGraphics;
    char[] sc = stringChars;
    int sl;
    int ml = messageLength;
    int ril = ri;
    int iw = 0;
    g.setColor( COLOR_BG );
    g.fillRect( 0, 0, dw, dh );
    if ( frameTime – oldFrameTime != 0  ) {
      sb.delete( ml, stringLength );
      sb.append( (int)frameTime );
      sl = stringLength = sb.length();
      sb.getChars( ml, sl, sc, ml );
      iw = font.charsWidth( sc, 0, sl );
      ig.setColor( COLOR_BG );
      ig.fillRect( 0, 0, iw, ih );
      ig.setColor( COLOR_FG );
      ig.drawChars( sc, 0, sl, 0, 0, textAnchor );
    }
    for ( int i  = DRAW_COUNT ; –i >=0  ; ) {
      g.setClip( randomNumbersX[ril], randomNumbersY[ril], iw, ih );
      g.drawImage( stringImage, randomNumbersX[ril],
                   randomNumbersY[ril], textAnchor );
      ril++;
      ril &= 255;
    }
    ri = ril;
    oldFrameTime = frameTime;
  }


Again, we are at the end of the road with respect to profiler results. These changes don’t affect the number of times the graphics routines are called, so the difference will be minor at best. But when we combine all the changes we made to our work() method and load the new JAR onto the device, the difference is huge. My motorola i85s now completes the test in 14030ms – over twice as fast!


There is one last change to make to the code. I have left it to the end because it uses a method that is not particularly well documented and my experience has been that its behavior varies across implementations. Looking at the start() and run() methods on OCanvas, you can see that I’ve been using a separate animation thread. This is the traditional way of doing animation in Java. An issue with using this technique for games is that we are forced to pause every time we iterate through the loop to allow system events, such as key presses and command actions to be delivered. We call the wait() method in a synchronized block to make this happen. This is hardly optimized code. After all our hard work optimizing everything else, we’re actually stopping to do nothing right in the thick of things. What’s worse, it’s not easy to arrive at a good figure for WAIT_TIME. If we wait() too long, the game slows down. If we don’t wait() for long enough, key presses are missed and the game stops being responsive to user input.


J2ME provides a solution to this problem by using the Display.callSerially() method. The API states that callSerially( Runnable r ) “causes the Runnable object r to have its run() method called later, serialized with the event stream, soon after completion of the repaint cycle”. By using callSerially() we can miss out the call to wait() entirely. The system will ensure that our work() and paint() methods are called in synch with the user input routines, so our game will remain responsive. Here are the new methods…


  public void start() {
    started = frameStarted = System.currentTimeMillis();
    loopCounter = result = 0;
    finished = false;
    exitStatus = EXIT_DONE;
    run();
  }
  public void run() {
    frameTime = System.currentTimeMillis() – frameStarted;
    frameStarted = System.currentTimeMillis();
    if ( midlet.running && !finished ) {
      result += work( numbers );
      repaint();
      display.callSerially(this);
      loopCounter++;
      finished = ( loopCounter > LOOP_COUNT );
    }
    else {
      elapsed = System.currentTimeMillis() – started;
      midlet.exitCanvas( exitStatus );
    }
  }


…plus we have to declare and get a handle on the Display:


    Display display = Display.getDisplay( midlet );


Without the call to wait() my i85s now runs this code in 10180ms – around a 40% savings. You might expect a greater increase in performance, given that we just eliminated 100 calls that wait() 50ms, but remember this technique is also about responsiveness to user input.


Again, let me stress that this method of animation should be used with caution. I had trouble getting it to work on NOKIA, and all of their example code (even game code) uses the wait() technique instead. Even on Motorola I had problems using callSerially() if I added Command objects to the animated Canvas. Test carefully before you try this at home.


 

J2ME Game Optimization Secrets (part 3)

Out of the loop?


Code inside a for() loop will be executed as many times as the loop iterates. To improve performance, therefore, we want to leave as much code as possible outside of our loops. We can see from the profiler that our paint() method is being called 101 times, and the loop inside iterates 16 times. What can we leave out of those two loops? Let’s start with all those declarations. We are declaring a Font, a String, an Image and a Graphics object every time paint() is called. We’ll move these outside of the method and to the top of our class.


public static final Font font =
  Font.getFont( Font.FACE_PROPORTIONAL,
                Font.STYLE_BOLD | Font.STYLE_ITALIC,
                Font.SIZE_SMALL);
public static final int graphicAnchor =
                   Graphics.VCENTER | Graphics.HCENTER;
public static final int textAnchor =
      Graphics.TOP | Graphics.LEFT;
private static final String MESSAGE = ” ms per frame”;
private String msMessage = “000” + MESSAGE;
private Image stringImage;
private Graphics imageGraphics;
private long oldFrameTime;


You’ll notice I made the Font object a public constant. This is often a useful thing to do in your apps, as you can gather the font declarations you use most together in one place. I have found the same goes for anchors, so I’ve done the same with the text and graphic anchors. Pre-calculating these things keeps those calculations, however insignificant, out of our loop.


I’ve also made the MESSAGE a constant. That’s because Java loves to create String objects all over the place. Strings can be a huge memory drain if they’re not controlled. Don’t take them for granted, or you will probably bleed memory, which can in turn affect performance, especially if the garbage collector is being called too often. Strings create garbage, and garbage is bad. Using a String constant reduces the problem. Later we’ll see how to use a StringBuffer to completely stop memory loss from String abuse.


Now that we’ve made these things instance variables, we need to add this code to the constructor:


stringImage = Image.createImage( font.stringWidth( msMessage ),
                                 font.getBaselinePosition() );
imageGraphics = stringImage.getGraphics();
imageGraphics.setFont( font );


Another cool thing about getting our Graphics object up-front is that we can set the font once and then forget about it instead of setting it every time we iterate through the loop. We still have to wipe the Image object each time using fillRect(). Gung-ho coders might see an opportunity there to create two Graphics objects from the same Image, and pre-set the color of one to COLOR_BG for the call to fillRect() and COLOR_FG on the other for the calls to drawString(). Unfortunately, the behavior of getGraphics() when called multiple times on the same Image is ill-defined in J2ME and differs across platforms so your optimization tweak might work on Motorola but not NOKIA. If in doubt, assume nothing.


There is another way to improve on our paint() method. Using our brain again we realize that we only need to re-draw the string if the frameTime value has changed since the method was last called. That’s where our new variable oldFrameTime comes in. Here’s the new method:


public void paint(Graphics g) {
  g.setColor( COLOR_BG );
  g.fillRect( 0, 0, getWidth(), getHeight() );
  if ( frameTime != oldFrameTime ) {
    msMessage = frameTime + MESSAGE;
    imageGraphics.setColor( COLOR_BG );
    imageGraphics.fillRect( 0, 0, stringImage.getWidth(),
                            stringImage.getHeight() );
    imageGraphics.setColor( COLOR_FG );
    imageGraphics.drawString( msMessage, 0, 0, textAnchor );
  }
  for ( int i  = 0 ; i < DRAW_COUNT ; i ++ ) {
    g.drawImage( stringImage, getRandom( getWidth() ),
                 getRandom( getHeight() ), graphicAnchor );
  }
  oldFrameTime = frameTime;
}


The Profiler now shows that the time spent in OCanvas paint is down to 42.01% of the total. Comparing the frameTime across calls to paint() resulted in drawString() and fillRect() being called 69 times instead of 101. That’s a decent savings, and there’s not much more to go, but now it’s time to get serious. The more you optimize, the harder it gets. Now we are down to scraping out the last pieces of superfluous, cycle-eating code. We’re dealing with shaving off very small percentages, or even fractions of percentages now, but if we’re lucky, they’ll add up to something significant.


Let’s start with something easy. Instead of calling getHeight() and getWidth(), let’s call those methods once and cache the results outside our loop. Next, we’re going to stop using Strings and do everything manually with a StringBuffer. We’re then going to shave a little off the calls to drawImage() by restricting the drawing area through calls to Graphics.setClip(). Finally, we’re going to avoid making calls to java.util.Random.nextInt() inside our loop.


Here are our new variables…


  private static final String MESSAGE = “ms per frame:”;
  private int iw, ih, dw, dh;
  private StringBuffer stringBuffer;
  private int messageLength;
  private int stringLength;
  private char[] stringChars;
  private static final int RANDOMCOUNT = 256;
  private int[] randomNumbersX = new int[RANDOMCOUNT];
  private int[] randomNumbersY = new int[RANDOMCOUNT];
  private int ri;


…and here is the new code for our constructor:


iw = stringImage.getWidth();
ih = stringImage.getHeight();
dw = getWidth();
dh = getHeight();
for ( int i = 0 ; i < RANDOMCOUNT ; i++ ) {
  randomNumbersX[i] = getRandom( dw );
  randomNumbersY[i] = getRandom( dh );
}
ri = 0;
stringBuffer = new StringBuffer( MESSAGE+”000″ );
messageLength = MESSAGE.length();
stringLength = stringBuffer.length();
stringChars = new char[stringLength];
stringBuffer.getChars( 0, stringLength, stringChars, 0 );


You can see we’re pre-calculating Display and Image dimensions. We’re also cacheing the results of 512 calls to getRandom(), and we’ve dispensed with the msMessage String in favor of a StringBuffer. The meat is still in the paint() method, of course:


  public void paint(Graphics g) {
    g.setColor( COLOR_BG );
    g.fillRect( 0, 0, dw, dh );
    if ( frameTime != oldFrameTime ) {
      stringBuffer.delete( messageLength, stringLength );
      stringBuffer.append( (int)frameTime );
      stringLength = stringBuffer.length();
      stringBuffer.getChars( messageLength,
                             stringLength,
                             stringChars,
                             messageLength );
      iw = font.charsWidth( stringChars, 0, stringLength );
      imageGraphics.setColor( COLOR_BG );
      imageGraphics.fillRect( 0, 0, iw, ih );
      imageGraphics.setColor( COLOR_FG );
      imageGraphics.drawChars( stringChars, 0,
                               stringLength, 0, 0, textAnchor );
    }
    for ( int i  = 0 ; i < DRAW_COUNT ; i ++ ) {
      g.setClip( randomNumbersX[ri], randomNumbersY[ri], iw, ih );
      g.drawImage( stringImage, randomNumbersX[ri],
                   randomNumbersY[ri], textAnchor );
      ri = (ri+1) % RANDOMCOUNT;
    }
    oldFrameTime = frameTime;
  }


We’re using a StringBuffer now to draw the characters of our message. It’s easier to append characters to the end of a StringBuffer than to insert them at the beginning, so I’ve switched our display text around and the frameTime is now at the end of the message, e.g. “ms per frame:120”. We’re just writing over the last few frameTime characters each time, and leaving the message part intact. Using a StringBuffer explicitly like this saves the system from creating and destroying Strings and StringBuffers each time through our paint() method. It’s extra work, but it’s worth it. Note that I’m casting frameTime to an int. I found that using append(long) caused a memory leak. I don’t know why, but it’s a good example of why you should use the utilities to keep an eye on things.


We’re also using font.charsWidth() to calculate the width of the message image so that we have to do the minimum of drawing. We’ve been using a proportional font, so the image for “ms per frame:1” will be smaller than the image for “ms per frame:888”, and we’re using Graphics.setClip() so we don’t have to draw the extra. This also means we only have to fill a rectangle big enough to blank out the area we need. We’re hoping that the drawing time we save makes up for the extra time spent calling font.charsWidth().


It may not make much of a difference here, but this is a great technique to use in a game for drawing a player’s score on the screen. In that case, there’s a big difference between drawing a score of 0 and a score of 150,000,000. This is hampered somewhat by the implementation’s incorrect return values for font.getBaselinePosition(), which seems to return the same value as font.getHeight(). Sigh.


Finally, we’re just looking up the pre-calculated “random” co-ordinates in our two arrays, which saves us making those calls. Note the use of the modulo operator to implement a circular array. Note also that we’re using the textAnchor for drawing both the image and the string now so that setClip() works correctly.


We are now firmly in a gray area with respect to the numbers this version of the code produces. The profiler tells me that the code is spending roughly 7% more time in paint() than without these changes. The call to font.charsWidth() is probably to blame, weighing in at 4.6%. ( That’s not great, but it could be reduced. Notice that we’re retrieving the width of the MESSAGE string every time. We could easily calculate that ahead of the loop body and simply add it to the frameTime width. ) Also, the new call to setClip() is labelled 0.85%, and seems to significantly increase the percentage of time spent in drawImage ( to 33.94% from 27.58% ).


At this point, it looks like all this extra code must certainly be slowing things down, but the values generated by the application contradict with this assumption. Figures on the emulator fluctuate so much as to be inconclusive without running longer tests but my i85s reports that things are a little faster with the extra clipping code than without, coming in at 37130ms without either call to setClip() or charsWidth(), and coming in at 36540 with both. I ran this test as many times as I had patience for, and the results were solid. This highlights the issues of varying execution environments. Once you get to the point where you’re not sure if you’re making headway, you might be forced to continue all your testing on the hardware, which would require a lot of installing and uninstalling of JAR files.


So it looks like we’ve squeezed a lot more performance from our graphical routines. Now it’s time to take the same high-level and low-level approaches with our work() method. Let’s review that method:


  public synchronized int work( int[] n ) {
    r = 0;
    for ( int j = 0 ; j < DIVISOR_COUNT ; j++ ) {
      for ( int i = 0 ; i < n.length ; i++ ) {
        divisor = getDivisor(j);
        r += workMore( n, i, divisor );
      }
    }
    return r;
  }


Every time through the loop in run() we’re passing in our array of numbers. The outer loop in the work() method calculates our divisor, then calls workMore() to actually perform the division. All kinds of things are wrong here, as you can probably tell. For a start, the programmer has put the call to getDivisor() inside the inner loop. Given that the value of j does not change through the inner loop, the divisor is an invariant, and really belongs outside the inner loop.


But let’s think about this some more. The call itself is completely unnecessary. This code does the same thing…


  public synchronized int work( int[] n ) {
    r = 0;
    divisor = 1;
    for ( int j = 0 ; j < DIVISOR_COUNT ; j++ ) {
      for ( int i = 0 ; i < n.length ; i++ ) {
        r += workMore( n, i, divisor );
      }
      divisor *= 2;
    }
    return r;
  }


…without that call to getDivisor(). Now our profiler is telling me that we are spending 23.72% in our run() method, versus 38.78% before we made these improvements. Always optimize with your head first before messing with low-level optimization tricks. With that said, let’s take a look at some of those tricks.


J2ME Game Optimization Secrets (part 2)

Where to Optimize – the 90/10 rule


In performance-hungry games, 90 percent of a program’s execution time is spent running 10 percent of the code. It is in this 10 percent of the code that we should concentrate all of our optimization efforts. We locate that 10 percent using a profiler. To turn on the Profiler Utility in the J2ME Wireless Toolkit, select the Preferences item from the Edit menu. This will bring up the Preferences window. Select the Monitoring tab, check the box marked “Enable Profiling”, and click the OK button. Nothing will happen. That’s okay – we need to run our program in the emulator and then exit before the Profiler window appears. Do that now.


Figure 1 illustrates how to turn on the Profiler Utility.


 


My emulator (running under Windows XP on a 2.4GHz Intel P4) reports that 100 iterations of the loop took 6,407ms, or just under six and a half seconds. The app reported 62 or 63ms per frame. On the hardware ( a Motorola i85s ) it ran much slower. Time per frame was around 500ms and the whole thing ran in 52460ms. We’ll try to improve these figures in the course of this article.


When you exit the application the profiler window will appear and you will see something that resembles a folder browser, with the familiar tree widget displayed in a panel on the left. Method relationships are shown in this hierarchical list. Each folder is a method and opening a methods folder displays the methods called by it. Selecting a method in the tree shows the profiling information for that method and all the methods called by it in the panel on the right. Notice that a percentage is displayed next to each element. This is the percentage of total execution time spent in that particular method. We must navigate through this tree to find where all the time is going, and optimize the methods with the highest percentages, where possible.


Figure 2 – the Profiler Utility call graph.



 
Click here for larger image


A couple of notes about the profiler. First, your percentages will almost certainly vary from mine, but they will be similarly proportioned – always follow the biggest numbers. My numbers varied every time I ran the app. To keep things as uniform as possible, you might want to close any background applications, like email clients, and keep activity to a minimum while you’re running tests. Also, don’t obfuscate your code before using the profiler or all your methods will be mysteriously named “b” or “a” or “ff”. Finally, the profiler doesn’t shed any light on the performance of whatever device you are emulating. The hardware itself is a completely different animal.


Opening the folder with the highest percentages we see that 66.8% of the execution time went to a method named “com.sun.kvem.midp.lcdui.EmulEventHandler$EventLoop.run”, which doesn’t really help us. Digging down further unfolds a level or two of methods with similarly obscure names. Keep going and you’ll trace the fat percentages to serviceRepaints() and finally to our OCanvas.paint() method. Another 30% of the time went into our OCanvas.run() method. It should come as no surprise that both of these methods live inside of our main game loop. We won’t be spending any time trying to optimize code in our MIDlet class, just as you shouldn’t bother optimizing code in your game that’s outside the main game loop. Only optimize where it counts.


The way that these percentages are divided in our example app is not entirely uncharacteristic of how they would be in a real game. You will most likely find that the vast proportion of execution time in a real videogame is spent in the paint() method. Graphics routines take a very long time when compared to non-graphical routines. Unfortunately, our graphics routines are already written for us somewhere below the surface of the J2ME API, and there’s not much we can do to improve their performance. What we can do is make smart decisions about which ones we use and how we use them.


High-Level vs. Low-Level optimization
Later in this article we will look at low-level code optimization techniques. You will see they are quite easy to plug into existing code and tend to degrade readability as much as they improve performance. Before you employ those techniques, it is always best to work on the design of your code and its algorithms. This is high-level optimization.


Michael Abrash, one of the developers of id software’s “Quake”, once wrote, “the best optimizer is between your ears”. There’s more than one way to do it (TMTOWTDI) and if you take the extra time to think about doing things the right way first, then you will reap the greatest reward. Using the right (i.e. fastest) algorithm will increase performance much more than using low-level techniques to improve a mediocre algorithm. You might shave a few more percentage points off using the low-level stuff, but always start at the top and use your brain (you’ll find it between your ears).


So let’s look at what we’re doing in our paint() method. We’re calling Graphics.drawString() 16 times every iteration to paint our message “n ms per frame” onscreen. We don’t know anything about the inner workings of drawString, but we can see that it’s using up a lot of time, so let’s try another approach. Let’s draw the String directly onto an Image object once and then draw the Image 16 times.


  public void paint(Graphics g) {
    g.setColor( COLOR_BG );
    g.fillRect( 0, 0, getWidth(), getHeight() );
    Font font = Font.getFont( Font.FACE_PROPORTIONAL,
                              Font.STYLE_BOLD | Font.STYLE_ITALIC,
                              Font.SIZE_SMALL );
    String msMessage = frameTime + “ms per frame”;
    Image stringImage =
         Image.createImage( font.stringWidth( msMessage ),
                            font.getBaselinePosition() );
    Graphics imageGraphics = stringImage.getGraphics();
    imageGraphics.setColor( COLOR_BG );
    imageGraphics.fillRect( 0, 0, stringImage.getWidth(),
                            stringImage.getHeight() );
    imageGraphics.setColor( COLOR_FG );
    imageGraphics.setFont( font );
    imageGraphics.drawString( msMessage, 0, 0,
                              Graphics.TOP | Graphics.LEFT );
    for ( int i  = 0 ; i < DRAW_COUNT ; i ++ ) {
      g.drawImage( stringImage, getRandom( getWidth() ),
                   getRandom( getHeight() ),
                   Graphics.VCENTER | Graphics.HCENTER );
    }
  }


When we run this version of our software, we see that the percentage of time spent in our paint method is a little less. Looking deeper we can see that the drawString method is only being called 101 times, and it is now the drawImage method that sees most of the action, being called 1616 times. Even though we are doing more work, the app runs a little quicker because the graphics calls we are using are faster.


You will probably notice that drawing the string to an image affects the display because J2ME does not support image transparency, so a lot of the background is overwritten. This is a good example of how optimization might cause you to re-evaluate application requirements. If you really needed the text to overlap, you might be forced to deal with the slower execution time.


This code might be slightly better, but it still has a lot of room for improvement. Let’s look at our first low-level optimization technique.


J2ME Game Optimization Secrets (part 1)

This article describes the role that code optimization plays in writing fast games for mobile devices. Using examples I will show how, when and why to optimize your code to squeeze every last drop of performance out of MIDP-compliant handsets. We will discuss why optimization is necessary and why it is often best NOT to optimize. I explain the difference between high-level and low-level optimization and we will see how to use the Profiler utility that ships with the J2ME Wireless Toolkit to discover where to optimize your code. Finally this article reveals lots of techniques for making your MIDlets move.


Why Optimize?
It is possible to divide video games into two broad categories; real-time and input-driven. Input-driven games display the current state of game play and wait indefinitely for user input before moving on. Card games fall into this category, as do most puzzle games, strategy games and text adventures. Real-time games, sometimes referred to as Skill and Action games do not wait for the player – they continue until the game is over.


Skill and Action games are often characterized by a great deal of on-screen movement (think of Galaga or Robotron). Refresh rates must be at least 10fps (frames per second) and there has to be enough action to keep gamers challenged. They require fast reflexes and good hand-eye co-ordination from the player, so compelling S&A games must also be extemely responsive to user input. Providing all that graphical activity at high framerates while responding quickly to key-presses is why code for real-time games has to be fast. The challenges are even greater when developing for J2ME.


Java 2 Micro Edition (J2ME) is a stripped-down version of Java, suitable for small devices with limited capabilities, such as cell phones and PDAs. J2ME devices have:


limited input capabilities (no keyboard!)
small display sizes
restricted storage memory and heap sizes
slow CPUs
Writing fast games for the J2ME platform further challenges developers to write code that will perform on CPUs far slower than those found on desktop computers.


When not to Optimize
If you’re not writing a Skill and Action game, there’s probably no need to optimize. If the player has pondered her next move for several seconds or minutes, she will probably not mind if your game’s response to her action takes more than a couple hundred milliseconds. An exception to this rule is if the game needs to perform a great deal of processing in order to determine its next move, such as searching through a million possible combinations of chess pieces. In this case, you might want to optimize your code so that the computer’s next move can be calculated in a few seconds, not minutes.


Even if you are writing this type of game, optimization can be perilous. Many of these techniques come with a price tag – they fly in the face of conventional notions of “Good” programming and can make your code harder to read. Some are a trade-off, and require the developer to significantly increase the size of the app in order to gain just a minor improvement in performance. J2ME developers are all too familiar with the challenges of keeping their JAR as small as possible. Here are a few more reasons not to optimize:


optimization is a good way to introduce bugs
some techniques decrease the portability of your code
you can expend a lot of effort for little or no results
optimization is hard
That last point needs some illumination. Optimization is a moving target, only more so on the Java platform, and even more so with J2ME because the execution environments vary so greatly. Your optimized code might run faster on an emulator, but slower on the actual device, or vice versa. Optimizing for one handset might actually decrease performance on another.


But there is hope. There are two passes you can make at optimization, a high-level and a low-level. The first is likely to increase execution performance on every platform, and even improve the overall quality of your code. The second pass is the one more likely to cause you headaches, but these low-level techniques are quite simple to introduce, and even simpler to omit if you don’t want to use them. At the very least, they’re very interesting to look at.


We will also use the System timer to profile your code on the actual device, which can help you to gauge exactly how effective ( or utterly ineffective ) these techniques can be on the hardware you’re targeting for deployment.


And one last bullet-point:
optimizing is fun
A Bad Example
Let’s take a look at a simple application that consists of two classes. First, the MIDlet…


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class OptimizeMe extends MIDlet implements CommandListener {
  private static final boolean debug = false;
  private Display display;
  private OCanvas oCanvas;
  private Form form;
  private StringItem timeItem = new StringItem( “Time: “, “Unknown” );
  private StringItem resultItem =
                            new StringItem( “Result: “, “No results” );
  private Command cmdStart = new Command( “Start”, Command.SCREEN, 1 );
  private Command cmdExit = new Command( “Exit”, Command.EXIT, 2 );
  public boolean running = true;
  public OptimizeMe() {
    display = Display.getDisplay(this);
    form = new Form( “Optimize” );
    form.append( timeItem );
    form.append( resultItem );
    form.addCommand( cmdStart );
    form.addCommand( cmdExit );
    form.setCommandListener( this );
    oCanvas = new OCanvas( this );
  }
  public void startApp() throws MIDletStateChangeException {
    running = true;
    display.setCurrent( form );
  }
  public void pauseApp() {
    running = false;
  }
  public void exitCanvas(int status) {
    debug( “exitCanvas – status = ” + status );
    switch (status) {
      case OCanvas.USER_EXIT:
        timeItem.setText( “Aborted” );
        resultItem.setText( “Unknown” );
      break;
      case OCanvas.EXIT_DONE:
        timeItem.setText( oCanvas.elapsed+”ms” );
        resultItem.setText( String.valueOf( oCanvas.result ) );
      break;
    }
    display.setCurrent( form );
  }
  public void destroyApp(boolean unconditional)
                          throws MIDletStateChangeException {
    oCanvas = null;
    display.setCurrent ( null );
    display = null;
  }
  public void commandAction(Command c, Displayable d) {
    if ( c == cmdExit ) {
      oCanvas = null;
      display.setCurrent ( null );
      display = null;
      notifyDestroyed();
    }
    else {
      running = true;
      display.setCurrent( oCanvas );
      oCanvas.start();
    }
  }
  public static final void debug( String s ) {
    if (debug) System.out.println( s );
  }
}


Second, the OCanvas class that does most of the work in this example…


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.Random;
public class OCanvas extends Canvas implements Runnable {
  public static final int USER_EXIT = 1;
  public static final int EXIT_DONE = 2;
  public static final int LOOP_COUNT = 100;
  public static final int DRAW_COUNT = 16;
  public static final int NUMBER_COUNT = 64;
  public static final int DIVISOR_COUNT = 8;
  public static final int WAIT_TIME = 50;
  public static final int COLOR_BG = 0x00FFFFFF;
  public static final int COLOR_FG = 0x00000000;
  public long elapsed = 0l;
  public int exitStatus;
  public int result;
  private Thread animationThread;
  private OptimizeMe midlet;
  private boolean finished;
  private long started;
  private long frameStarted;
  private long frameTime;
  private int[] numbers;
  private int loopCounter;
  private Random random = new Random( System.currentTimeMillis() );
  public OCanvas( OptimizeMe _o ) {
    midlet = _o;
    numbers = new int[ NUMBER_COUNT ];
    for ( int i = 0 ; i < numbers.length ; i++ ) {
      numbers[i] = i+1;
    }
  }
  public synchronized void start() {
    started = frameStarted = System.currentTimeMillis();
    loopCounter = result = 0;
    finished = false;
    exitStatus = EXIT_DONE;
    animationThread = new Thread( this );
    animationThread.start();
  }
  public void run() {
    Thread currentThread = Thread.currentThread();
    try {
      while ( animationThread == currentThread && midlet.running
                                               && !finished ) {
        frameTime = System.currentTimeMillis() – frameStarted;
        frameStarted = System.currentTimeMillis();
        result += work( numbers );
        repaint();
        synchronized(this) {
          wait( WAIT_TIME );
        }
        loopCounter++;
        finished = ( loopCounter > LOOP_COUNT );
      }
    }
    catch ( InterruptedException ie ) {
      OptimizeMe.debug( “interrupted” );
    }
    elapsed = System.currentTimeMillis() – started;
    midlet.exitCanvas( exitStatus );
  }
  public void paint(Graphics g) {
    g.setColor( COLOR_BG );
    g.fillRect( 0, 0, getWidth(), getHeight() );
    g.setColor( COLOR_FG );
    g.setFont( Font.getFont( Font.FACE_PROPORTIONAL,
         Font.STYLE_BOLD | Font.STYLE_ITALIC, Font.SIZE_SMALL ) );
    for ( int i  = 0 ; i < DRAW_COUNT ; i ++ ) {
      g.drawString( frameTime + ” ms per frame”,
                    getRandom( getWidth() ),
                    getRandom( getHeight() ),
                    Graphics.TOP | Graphics.HCENTER );
    }
  }
  private int divisor;
  private int r;
  public synchronized int work( int[] n ) {
    r = 0;
    for ( int j = 0 ; j < DIVISOR_COUNT ; j++ ) {
      for ( int i = 0 ; i < n.length ; i++ ) {
        divisor = getDivisor(j);
        r += workMore( n, i, divisor );
      }
    }
    return r;
  }
  private int a;
  public synchronized int getDivisor( int n ) {
    if ( n == 0 ) return 1;
    a = 1;
    for ( int i = 0 ; i < n ; i++ ) {
      a *= 2;
    }
    return a;
  }
  public synchronized int workMore( int[] n, int _i, int _d ) {
    return n[_i] * n[_i] / _d + n[_i];
  }
  public void keyReleased(int keyCode) {
    if ( System.currentTimeMillis() – started > 1000l ) {
      exitStatus = USER_EXIT;
      midlet.running = false;
    }
  }
  private int getRandom( int bound )
  {  // return a random, positive integer less than bound
    return Math.abs( random.nextInt() % bound );
  }
}


This app is a MIDlet that simulates a simple game loop:


work
draw
poll for user input
repeat



For fast games, this loop has to be as tight and fast as possible. Our loop continues for a finite number of iterations (LOOP_COUNT = 100) and uses the System timer to calculate how long in milliseconds the whole exercise took, so we can measure and improve its performance. The time and the results of the work are displayed on a simple Form. Use the Start command to begin the test. Pressing any key will exit the loop prematurely. The Exit command exits the application.


In most games, the work phase of the main game loop involves updating the state of the game world – moving all the actors, testing for and reacting to collisions, updating scores, etc. In this example, we’re not doing anything particularly useful. The code simply runs through an array of numbers and performs a few arithmetic operations on each, aggregating the results in a running total.


The run() method also calculates the amount of time it takes to execute each iteration of the loop. Every frame, the OCanvas.paint() method displays this value in milliseconds at 16 random locations on screen. Normally you would be drawing the graphical elements of your game in this method, but our code offers a reasonable facsimile of this process.


Regardless of how pointless this code may seem, it will allow us ample opportunity to improve its performance.


MIDP 2.0 Games: a Step-by-Step Tutorial with Code Samples (Step 6)

And here’s the code for Tumbleweed.java:


package net.frog_parrot.jump;


import java.util.Random;


import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;


/**
 * This class represents the tumbleweeds that the player
 * must jump over.
 *
 * @author Carol Hamer
 */
public class Tumbleweed extends Sprite {


  //———————————————————
  //   dimension fields


  /**
   * The width of the tumbleweed’s bounding square.
   */
  static int WIDTH = 16;


  //———————————————————
  //    instance fields


  /**
   * Random number generator to randomly decide when to appear.
   */
  Random myRandom = new Random();


  /**
   * whether or not this tumbleweed has been jumped over.
   * This is used to calculate the score.
   */
  boolean myJumpedOver;


  /**
   * whether or not this tumbleweed enters from the left.
   */
  boolean myLeft;


  /**
   * the Y coordinate of the tumbleweed.
   */
  int myY;


  //———————————————————
  //   initialization


  /**
   * constructor initializes the image and animation.
   * @param left whether or not this tumbleweed enters from the left.
   */
  public Tumbleweed(boolean left) throws Exception {
    super(Image.createImage(“/icons/tumbleweed.png”),
   WIDTH, WIDTH);
    myY = JumpManager.DISP_HEIGHT – WIDTH – 2;
    myLeft = left;
    if(!myLeft) {
      setTransform(TRANS_MIRROR);
    }
    myJumpedOver = false;
    setVisible(false);
  }


  //———————————————————
  //   graphics


  /**
   * move the tumbleweed back to its initial (inactive) state.
   */
  void reset() {
    setVisible(false);
    myJumpedOver = false;
  }


  /**
   * alter the tumbleweed image appropriately for this frame..
   * @param left whether or not the player is moving left
   * @return how much the score should change by after this
   *         advance.
   */
  int advance(Cowboy cowboy, int tickCount, boolean left,
       int currentLeftBound, int currentRightBound) {
    int retVal = 0;
    // if the tumbleweed goes outside of the display
    // region, set it to invisible since it is
    // no longer in use.
    if((getRefPixelX() + WIDTH <= currentLeftBound) ||
       (getRefPixelX() – WIDTH >= currentRightBound)) {
      setVisible(false);
    }
    // If the tumbleweed is no longer in use (i.e. invisible)
    // it is given a 1 in 100 chance (per game loop)
    // of coming back into play:
    if(!isVisible()) {
      int rand = getRandomInt(100);
      if(rand == 3) {
 // when the tumbleweed comes back into play,
 // we reset the values to what they should
 // be in the active state:
 myJumpedOver = false;
 setVisible(true);
 // set the tumbleweed’s position to the point
 // where it just barely appears on the screen
 // to that it can start approaching the cowboy:
 if(myLeft) {
   setRefPixelPosition(currentRightBound, myY);
   move(-1, 0);
 } else {
   setRefPixelPosition(currentLeftBound, myY);
   move(1, 0);
 }
      }
    } else {
      // when the tumbleweed is active, we advance the
      // rolling animation to the next frame and then
      // move the tumbleweed in the right direction across
      // the screen.
      if(tickCount % 2 == 0) { // slow the animation down a little
 nextFrame();
      }
      if(myLeft) {
 move(-3, 0);
 // if the cowboy just passed the tumbleweed
 // (without colliding with it) we increase the
 // cowboy’s score and set myJumpedOver to true
 // so that no further points will be awarded
 // for this tumbleweed until it goes offscreen
 // and then is later reactivated:
 if((! myJumpedOver) &&
    (getRefPixelX() < cowboy.getRefPixelX())) {
   myJumpedOver = true;
   retVal = cowboy.increaseScoreThisJump();
 }
      } else {
 move(3, 0);
 if((! myJumpedOver) &&
    (getRefPixelX() > cowboy.getRefPixelX() + Cowboy.WIDTH)) {
   myJumpedOver = true;
   retVal = cowboy.increaseScoreThisJump();
 }
      }
    }
    return(retVal);
  }


  /**
   * Gets a random int between
   * zero and the param upper.
   */
  public int getRandomInt(int upper) {
    int retVal = myRandom.nextInt() % upper;
    if(retVal < 0) {
      retVal += upper;
    }
    return(retVal);
  }


}


The TiledLayer Class


As mentioned above, the TiledLayer class is similar to the Sprite class except that a TiledLayer can be composed of multiple cells, each of which is painted with an individually set image frame. The other differences between TiledLayer and Sprite are mostly related to extra functionality missing from TiledLayer: TiledLayer has no transforms, reference pixel, or frame sequence.


Of course the mere fact that you’re simultaneously managing multiple images complicates things a bit. I’ll explain it by going over my subclass of TiledLayer which I have called Grass. This class represents a row of grass in the background which waves back and forth as the game is being played. To make it more interesting, some of the cells in my TiledLayer have animated grasses and others have no tall grasses and hence just consist of a green line representing the ground at the bottom of the cell. Here’s the corresponding image file:


 
WARNING: the tile index for Sprite starts with 0, but the tile index for TiledLayer starts with 1! This is a little confusing (it caused me to get an IndexOutOfBoundsException the first time I made a Sprite because I had assumed that the Sprite images were numbered like the TiledLayer images…). Yet the system is completely logical. In a TiledLayer, the tile index 0 indicates a blank tile (i.e. paint nothing in the cell if the cell’s tile index is set to zero). A Sprite, however, is composed of only one cell, so if you want that cell to be blank, then you can just call setVisible(false), meaning that Sprite doesn’t need to reserve a special index to indicate a blank tile. This little confusion in the indices should not pose a big problem, but it’s something to keep in mind if you can’t figure out why your animation appears to be displaying the wrong images.. Aside from this point, the image file is divided into individual frames or tiles in TiledLayer just as in Sprite, explained above.


The first step in creating your TiledLayer is to decide how many rows and columns of cells you will need. If you don’t want your layer to be rectangular it isn’t a problem because any unused cells are by default set to being blank which prevents them from getting in the way of other images. In my example I have only one row, and I calculate the number of columns based on the width of the screen.


Once you’ve set how many rows and columns you’ll be using, you can fill each cell with a tile using the method setCell(int col, int row, int tileIndex). The tileIndex argument is as explained in the Sprite section and the warning paragraph above. If you would like some of the cells to be filled with animated images, you need to create an animated tile by calling createAnimatedTile(int staticTileIndex), which returns the tile index that has been allotted to your new animated tile. You can make as many animated tiles as you want, but remember that each animated tile can be used in multiple cells if you want the cells to display the same animation simultaneously. In my case, I create only one animated tile and reuse it because I want all of my animated grass to be waving in sync. The cells are set in the constructor of Grass below. To advance the animation you don’t get built-in frame-sequence functionality as in Sprite, so you have to set the frames with the method setAnimatedTile(int animatedTileIndex, int staticTileIndex). This sets the current frame of the given animated tile. Thus all of the cells that have been set to contain the animated tile corresponding to animatedTileIndex will change to the image given by the argument staticTileIndex. To simplify the animation updates, it’s easy to add your own frame-sequence functionality: see the method Grass.advance(int tickCount) for an idea of how to do it.


Here’s the code for the last class, Grass.java:


package net.frog_parrot.jump;


import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;


/**
 * This class draws the background grass.
 *
 * @author Carol Hamer
 */
public class Grass extends TiledLayer {


  //———————————————————
  //    dimension fields
  //  (constant after initialization)


  /**
   * The width of the square tiles that make up this layer..
   */
  static int TILE_WIDTH = 20;


  /**
   * This is the order that the frames should be displayed
   * for the animation.
   */
  static int[] FRAME_SEQUENCE = { 2, 3, 2, 4 };


  /**
   * This gives the number of squares of grass to put along
   * the bottom of the screen.
   */
  static int COLUMNS;


  /**
   * After how many tiles does the background repeat.
   */
  static int CYCLE = 5;


  /**
   * the fixed Y coordinate of the strip of grass.
   */
  static int TOP_Y;


  //———————————————————
  //    instance fields


  /**
   * Which tile we are currently on in the frame sequence.
   */
  int mySequenceIndex = 0;


  /**
   * The index to use in the static tiles array to get the
   * animated tile..
   */
  int myAnimatedTileIndex;


  //———————————————————
  //   gets / sets


  /**
   * Takes the width of the screen and sets my columns
   * to the correct corresponding number
   */
  static int setColumns(int screenWidth) {
    COLUMNS = ((screenWidth / 20) + 1)*3;
    return(COLUMNS);
  }


  //———————————————————
  //   initialization


  /**
   * constructor initializes the image and animation.
   */
  public Grass() throws Exception {
    super(setColumns(JumpCanvas.DISP_WIDTH), 1,
   Image.createImage(“/icons/grass.png”),
   TILE_WIDTH, TILE_WIDTH);
    TOP_Y = JumpManager.DISP_HEIGHT – TILE_WIDTH;
    setPosition(0, TOP_Y);
    myAnimatedTileIndex = createAnimatedTile(2);
    for(int i = 0; i < COLUMNS; i++) {
      if((i % CYCLE == 0) || (i % CYCLE == 2)) {
 setCell(i, 0, myAnimatedTileIndex);
      } else {
 setCell(i, 0, 1);
      }
    }
  }


  //———————————————————
  //   graphics


  /**
   * sets the grass back to its initial position..
   */
  void reset() {
    setPosition(-(TILE_WIDTH*CYCLE), TOP_Y);
    mySequenceIndex = 0;
    setAnimatedTile(myAnimatedTileIndex, FRAME_SEQUENCE[mySequenceIndex]);
  }


  /**
   * alter the background image appropriately for this frame..
   */
  void advance(int tickCount) {
    if(tickCount % 2 == 0) { // slow the animation down a little
      mySequenceIndex++;
      mySequenceIndex %= 4;
      setAnimatedTile(myAnimatedTileIndex, FRAME_SEQUENCE[mySequenceIndex]);
    }
  }


}


Putting it Together


Now that you have all to the relevant classes, the example needs to be built just as in the “Hello World” example. The classes should be compiled, preverified, and jarred. (Preverification is an extra step that makes bytecode verification easier for J2ME applications; it’s a necessary step but one that is performed by standard utility programs so you don’t need to worry too much about it.) Be sure that all of your resources have been correctly placed in the jar. In my example I need to place the files cowboy.png, tumbleweed.png, and grass.png in a top-level folder called icons in my jar since I constructed my Layers with images created by calls to Image.createImage(“/icons/grass.png”), etc. Also I need to place the correct MANIFEST.MF file in the jar. Here’s the one I used:


MIDlet-1: Hello World, /icons/hello.png, net.frog_parrot.hello.Hello
MIDlet-2: Tumbleweed, /icons/boot.png, net.frog_parrot.jump.Jump
MMIDlet-Description: Example games for MIDP
MIDlet-Name: Example Games
MIDlet-Permissions:
MIDlet-Vendor: frog-parrot.net
MIDlet-Version: 2.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0


Keep in mind that if you want to put a custom MANIFEST.MF file in your jar instead of an auto-generated one, you need to use the m option when creating your jar.


Once you have your jar file, you need a jad file. Here’s the one I used, which I called jump.jad:


MIDlet-1: Hello, /icons/hello.png, net.frog_parrot.hello.Hello
MIDlet-2: Tumbleweed, /icons/boot.png, net.frog_parrot.jump.Jump
MMIDlet-Description: Example games for MIDP
MIDlet-Jar-URL: jump.jar
MIDlet-Name: Example Games
MIDlet-Permissions:
MIDlet-Vendor: frog-parrot.net
MIDlet-Version: 2.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-2.0
MIDlet-Jar-Size: 17259


Don’t forget to verify that the MIDlet-Jar-Size is correct if you’re creating the jad file by hand. Also note that this jad file indicates that your jar file needs to contain the icon /icons/boot.png which is used in the game selection menu and looks like this:


 
Once the jar and jad files are ready, you can run the program. I ran it from the command line with the runmidlet script that came with the WTK2.0 toolkit.


Good luck with your own game!


Appendix A: Script Hints


Running the midlet in the emulator from the command line is very simple. All I did was go to the bin directory under the toolkit’s WTK2.0 directory. From there I typed ./bin/emulator followed by an option giving the name of the jad descriptor file corresponding to the MIDlet I wanted to run. For example in my case this was the following line:


./bin/emulator -Xdescriptor:/home/carol/j2me/book/ch02/bin/games.jad


Other emulator options are listed in the toolkit documentation in section D. Command Line Utilities under the heading of Running the Emulator.


The following build script will automatically fix the MIDlet-Jar-Size property in your jad file after rebuilding as long as the MIDlet-Jar-Size property is the last line of the jad file, as it is in the examples I provided.


Note that this script assumes that you have a file tree configured as follows: Under a main directory you must have four subdirectories: bin (which contains this script as well as the jad and MANIFEST.MF files), a tmpclasses directory (which may be empty), a classes directory (containing a subdirectory called images which contains all of your image files), and a src directory which contains the directory tree for the source code of the MIDlet you would like to compile.


# This script builds and preverifies the code
# for the tumbleweed game.


# reset this variable to the path to the correct javac
# command on your system:
JAVA4_HOME=/usr/java/j2sdk1.4.0_01/bin
# reset this variable to the corresct path to the WTK2.0
# directory of the WTK2.0 toolkit that you downloaded:
WTK2_HOME=../../../../WTK2.0


echo “clear directories”
# it’s better not to leave old class files lying
# around where they might accidentally get picked up
# and create errors…
rm ../tmpclasses/net/frog_parrot/hello/*.class
rm ../classes/net/frog_parrot/hello/*.class
rm ../tmpclasses/net/frog_parrot/jump/*.class
rm ../classes/net/frog_parrot/jump/*.class


echo “Compiling source files”


$JAVA4_HOME/javac -bootclasspath $WTK2_HOME/lib/midpapi.zip –
d ../tmpclasses -classpath ../tmpclasses ../src/net/frog_parrot/hello/*.java
../src/net/frog_parrot/jump/*.java


echo “Preverifying class files”


$WTK2_HOME/bin/preverify -classpath $WTK2_HOME/lib/midpapi.zip:
../tmpclasses -d ../classes ../tmpclasses


echo “Jarring preverified class files”
$JAVA4_HOME/jar cmf MANIFEST.MF jump.jar -C ../classes .


echo “Updating JAR size info in JAD file…”


NB=`wc -l jump.jad | awk ‘{print $1}’`
head –lines=$(($NB-1)) jump.jad > jump.jad1
echo “MIDlet-Jar-Size:” `stat -c ‘%s’ jump.jar`>> jump.jad1
cp jump.jad1 jump.jad


There’s one more little hint I would like to pass along to you. I noticed that at the end of the runmidlet script all of the messages generated by the runmidlet program are redirected to /dev/null. If you would like to see your messages for debugging purposes, you should remove the > /dev/null from the end of the script.


Appendix B: Images and the Gimp


If you’re wondering where all of the image files in this example came from, I drew them myself with a free program called the gimp, which you can download from http://www.gimp.org/download.html. If you decide to draw your image files with the gimp and you would like them to have transparent backgrounds, be sure to select a transparent background when you first create a new image file. Then make sure that you select “save background color” when you save the file. Also, you should save it with the .png extension so that the gimp will save it in the right format to be used by a J2ME game.


MIDP 2.0 Games: a Step-by-Step Tutorial with Code Samples (Step 5)

The Sprite Class


A Sprite is a graphical object represented by one image (at a time). The fact that a Sprite is composed of only one image is the principal difference between a Sprite and a TiledLayer, which is a region that is covered with images that can be manipulated. (The Sprite class has a few extra features, but the fact that it uses one image rather than filling an area with images is the most obvious difference.) So a Sprite is generally used for small, active game objects (such as your spaceship and the asteroids that are coming to crash into it) and a TiledLayer would be more likely to be used for an animated background.

One cool feature of Sprite is that even though a Sprite is represented by only one image at a time, it can be easily represented by different images under different circumstances, including by a series of images that make up an animation. In my example game the cowboy has three different images in which he is walking and one in which he is jumping. All of the images used for a given Sprite need to be stored together in a single image file. (To indicate where to find the image file to use, send the address of the image within the jar in exactly the same format that is used to find resources in the method Class.getResource(); see the Putting it Together section for more details.) The fact that multiple frames are stored in a single Image object is a convenience that means you don’t have to manipulate multiple Image objects to determine which face your Sprite is wearing at any given time. Here’s the image file for the cowboy:

 


And here is the image file for the tumbleweed which is animated to appear to be rolling:

 
The way to select which frame is shown at any given time is very intuitive. First, if your image file is composed of multiple images (as these two are), you should construct the Sprite with the constructor that specifies the width and height (in pixels) that you would like your Sprite to be. The width and height of the Image should be integer multiples of the width and height that you send to the constructor. In other words, the computer should be able to divide up your image file evenly into rectangles of the size you specify. As you can see from the examples above, the sub-images may be arranged horizontally or vertically. They can even be arranged in a grid with multiple rows and columns. Then to identify the individual frames, they are numbered starting with zero at the top left corner and continuing to the right and then continuing on to the lower rows, in exactly the same order in which you are reading the letters on this page. To select which frame is currently displayed, use the method setFrame(int sequenceIndex) sending the frame number as an argument.

The Sprite class has some added support for animation by allowing you to define a frame sequence with the method setFrameSequence(int[] sequence). As you can see in the code below, I’ve set a frame sequence of { 1, 2, 3, 2 } for my cowboy and { 0, 1, 2 } for my tumbleweed. To advance your Sprite’s animation from one frame to the next, you use the method nextFrame() (or if you prefer prevFrame()). This is very convenient in cases like my tumbleweed where all of the available frames are used in the animation. It’s slightly less convenient in cases like my cowboy that have an image or images that fall outside of the frame sequence of the animation. This is because once a frame sequence has been set, the argument to the method setFrame(int sequenceIndex) gives the index of an entry in the frame sequence instead of giving the index of the frame itself. What that means is that once I’ve set my cowboy’s frame sequence to { 1, 2, 3, 2 }, if I call setFrame(0) it will show frame number 1, setFrame(1) will show frame number 2, setFrame(2) will show frame number 3, and setFrame(3) will show frame number 2. But when the cowboy is jumping, I would like it to show frame number 0 which is no longer accessible. So when my cowboy jumps, I have to set my frame sequence to null before calling setFrame(0), and then I have to set my frame sequence back to the animation sequence { 1, 2, 3, 2 } afterwards. This is illustrated in the code below in the methods jump() and advance(int tickCount, boolean left).

In addition to changing your Sprite’s appearance by changing frames, you can change it by applying simple transforms such as rotations or mirror images. Both my cowboy and my tumbleweed below can be going either left or right, so of course I need to use the mirror image transform to change from one direction to the other. Once you start applying transforms, you need to keep track of the Sprite’s reference pixel. This is because when you transform your Sprite, the reference pixel is the pixel that does not move. You might expect that if your Sprite’s image is square then after a transformation the Sprite’s image will continue to occupy the same square of area on the screen. This is not the case. The best way to illustrate what happens is to imagine an example Sprite of a standing person facing left whose reference pixel has been defined to be the tip of his toe. Then after applying a 90-degree rotation, your person will be in the spot he would be in if he had tripped and fallen forward. Clearly this has its applications if your Sprite has a special pixel (such as the tip of an arrow) that should stay put after a transformation. But if you want your Sprite to continue to occupy the same space on the screen after a transformation, then you should first call defineReferencePixel(int x, int y) and set your Sprite’s reference pixel to the center of the Sprite, as I did in the Cowboy constructor below. Be aware that the coordinates in defineReferencePixel(int x, int y) are relative to the top corner of the Sprite whereas the coordinates sent to setRefPixelPosition(int x, int y) tell where to place the Sprite’s reference pixel on the screen in terms of the screen’s coordinates. To be more precise, the coordinates sent to setRefPixelPosition(int x, int y) refer to the coordinate system of the Canvas if the Sprite is painted directly onto the Canvas, but if the Sprite is painted by a LayerManager, these coordinates should be given in terms of the LayerManager’s coordinate system. (How these coordinate systems fit together is explained in the LayerManager section above.) The coordinates in the various methods to set and get the position of the reference pixel or to set and get the position of the top left corner pixel refer to the coordinates of the appropriate Canvas or LayerManager. Also note that if you perform multiple transformations, the later trasformations are applied to the original image and not to its current state. In other words, if I apply setTransform(TRANS_MIRROR) twice in a row, the second transform will not mirror my image back to its original position, it will just repeat the action of setting the Image to being a mirror image of the original Image. If you want to set a transformed Sprite back to normal, use setTransform(TRANS_NONE). This is illustrated in the top of the Cowboy.advance(int tickCount, boolean left) method.

Another great feature of the Layer class (including both Sprites and TiledLayers) is the support it gives you for placing your objects in relative terms instead of in absolute terms. If your Sprite needs to move over three pixels regardless of where it currently is, you can just call move(int x, int y) sending it the x and y distances it should move from its current position, as opposed to calling setRefPixelPosition(int x, int y) with the absolute coordinates of the Sprite’s new location. Even more useful is the set of collidesWith() methods. This allows you to check if a Sprite is occupying the same space as another Sprite or TiledLayer or even an Image. It’s easy to see that this saves you quite a number of comparisons, especially since when you send the pixelLevel argument as true, it will only consider the two Layers as having collided if their opaque pixels overlap.

In my “Tumbleweed” game, after advancing all of the Sprites, I check if the cowboy has collided with any tumbleweeds. (This happens in the Cowboy.checkCollision(Tumbleweed tumbleweed) method which is called from JumpManager.advance(int gameTicks).) I check the collisions between the cowboy and all of the tumbleweeds each time because it automatically returns false for any tumbleweeds that aren’t currently visible anyway, so I’m not really being wasteful by checking the cowboy against tunbleweeds that are not currently in use. In many cases, however, you can save some effort by only checking for collisions that you know are possible rather than checking all of the Sprites against each other. Note that in my example I don’t bother to check if the tumbleweeds collide with each other or if anything collides with the background grass because that is irrelevant. If you’re checking for pixel-level collisions, you will want to be sure that your images have a transparent background. (This is also helpful in general so that your Sprite doesn’t paint an ugly rectangle of background color over another Sprite or Image.) Some discussion of creating the image files correctly is included in Appendix B.

Here’s the code for Cowboy.java:

package net.frog_parrot.jump;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;

/**
 * This class represents the player.
 *
 * @author Carol Hamer
 */
public class Cowboy extends Sprite {

  //———————————————————
  //    dimension fields

  /**
   * The width of the cowboy’s bounding rectangle.
   */
  static int WIDTH = 32;

  /**
   * The height of the cowboy’s bounding rectangle.
   */
  static int HEIGHT = 48;

  /**
   * This is the order that the frames should be displayed
   * for the animation.
   */
  static int[] FRAME_SEQUENCE = { 3, 2, 1, 2 };

  //———————————————————
  //    instance fields

  /**
   * the X coordinate of the cowboy where the cowboy starts
   * the game.
   */
  int myInitialX;

  /**
   * the Y coordinate of the cowboy when not jumping.
   */
  int myInitialY;

  /**
   * The jump index that indicates that no jump is
   * currently in progress..
   */
  int myNoJumpInt = -6;

  /**
   * Where the cowboy is in the jump sequence.
   */
  int myIsJumping = myNoJumpInt;

  /**
   * If the cowboy is currently jumping, this keeps track
   * of how many points have been scored so far during
   * the jump.  This helps the calculation of bonus points since
   * the points being scored depend on how many tumbleweeds
   * are jumped in a single jump.
   */
  int myScoreThisJump = 0;

  //———————————————————
  //   initialization

  /**
   * constructor initializes the image and animation.
   */
  public Cowboy(int initialX, int initialY) throws Exception {
    super(Image.createImage(“/icons/cowboy.png”),
   WIDTH, HEIGHT);
    myInitialX = initialX;
    myInitialY = initialY;
    // we define the reference pixel to be in the middle
    // of the cowboy image so that when the cowboy turns
    // from right to left (and vice versa) he does not
    // appear to move to a different location.
    defineReferencePixel(WIDTH/2, 0);
    setRefPixelPosition(myInitialX, myInitialY);
    setFrameSequence(FRAME_SEQUENCE);
  }

  //———————————————————
  //   game methods

  /**
   * If the cowboy has landed on a tumbleweed, we decrease
   * the score.
   */
  int checkCollision(Tumbleweed tumbleweed) {
    int retVal = 0;
    if(collidesWith(tumbleweed, true)) {
      retVal = 1;
      // once the cowboy has collided with the tumbleweed,
      // that tumbleweed is done for now, so we call reset
      // which makes it invisible and ready to be reused.
      tumbleweed.reset();
    }
    return(retVal);
  }

  /**
   * set the cowboy back to its initial position.
   */
  void reset() {
    myIsJumping = myNoJumpInt;
    setRefPixelPosition(myInitialX, myInitialY);
    setFrameSequence(FRAME_SEQUENCE);
    myScoreThisJump = 0;
    // at first the cowboy faces right:
    setTransform(TRANS_NONE);
  }

  //———————————————————
  //   graphics

  /**
   * alter the cowboy image appropriately for this frame..
   */
  void advance(int tickCount, boolean left) {
    if(left) {
      // use the mirror image of the cowboy graphic when
      // the cowboy is going towards the left.
      setTransform(TRANS_MIRROR);
      move(-1, 0);
    } else {
      // use the (normal, untransformed) image of the cowboy
      // graphic when the cowboy is going towards the right.
      setTransform(TRANS_NONE);
      move(1, 0);
    }
    // this section advances the animation:
    // every third time through the loop, the cowboy
    // image is changed to the next image in the walking
    // animation sequence:
    if(tickCount % 3 == 0) { // slow the animation down a little
      if(myIsJumping == myNoJumpInt) {
 // if he’s not jumping, set the image to the next
 // frame in the walking animation:
 nextFrame();
      } else {
 // if he’s jumping, advance the jump:
 // the jump continues for several passes through
 // the main game loop, and myIsJumping keeps track
 // of where we are in the jump:
 myIsJumping++;
 if(myIsJumping < 0) {
   // myIsJumping starts negative, and while it’s
   // still negative, the cowboy is going up. 
   // here we use a shift to make the cowboy go up a
   // lot in the beginning of the jump, and ascend
   // more and more slowly as he reaches his highest
   // position:
   setRefPixelPosition(getRefPixelX(),
         getRefPixelY() – (2 << (-myIsJumping)));
 } else {
   // once myIsJumping is negative, the cowboy starts
   // going back down until he reaches the end of the
   // jump sequence:
   if(myIsJumping != -myNoJumpInt – 1) {
     setRefPixelPosition(getRefPixelX(),
    getRefPixelY() + (2 << myIsJumping));
   } else {
     // once the jump is done, we reset the cowboy to
     // his non-jumping position:
     myIsJumping = myNoJumpInt;
     setRefPixelPosition(getRefPixelX(), myInitialY);
     // we set the image back to being the walking
     // animation sequence rather than the jumping image:
     setFrameSequence(FRAME_SEQUENCE);
     // myScoreThisJump keeps track of how many points
     // were scored during the current jump (to keep
     // track of the bonus points earned for jumping
     // multiple tumbleweeds).  Once the current jump is done,
     // we set it back to zero. 
     myScoreThisJump = 0;
   }
 }
      }
    }
  }

  /**
   * makes the cowboy jump.
   */
  void jump() {
    if(myIsJumping == myNoJumpInt) {
      myIsJumping++;
      // switch the cowboy to use the jumping image
      // rather than the walking animation images:
      setFrameSequence(null);
      setFrame(0);
    }
  }

  /**
   * This is called whenever the cowboy clears a tumbleweed
   * so that more points are scored when more tumbleweeds
   * are cleared in a single jump.
   */
  int increaseScoreThisJump() {
    if(myScoreThisJump == 0) {
      myScoreThisJump++;
    } else {
      myScoreThisJump *= 2;
    }
    return(myScoreThisJump);
  }

}