Chapter 10. Making the Most of Limited Resources

Games are one of the most powerful factors forcing computer users to upgrade to better hardware. The latest games run on up-to-date machines with powerful processors, lots of working memory, and fast video acceleration and 3D-rendering cards. Fortunately, PCs are expandable, with lots of empty slots for additional cards. When a slick new game comes out, fans can easily swap in a new video card or add more memory chips.

On the other hand, most small J2ME devices offer what's inside and nothing more. They don't usually provide any extension slots, although PDAs such as the Palm, iPaq, or Handspring do offer basic expansion ports.

Here's another crazy fact: The micro devices that users buy today will most likely have been in use for a year or two already, and users are generally tied to their mobile phone or other micro device for a few years.

If you want to develop games for micro devices, then, you have to be acutely aware of a target device's limitations. And you have to face the fact that these limits won't be improved upon anytime soon.

The Limitations

Most J2ME MIDP devices can fit in your hand. Several years ago, mobile devices were very expensive and geared toward business people. Today, almost 90% of all mobile phone users own a device for personal use, especially in Europe and Asia.

By looking at the mobile scene in Japan, and based on predictions by European mobile operators such as Vodafone, Deutsche Telecom, and Telefonica, as well as American operators Sprint PCS, Nextel, and Voicestream, entertainment is going to become the number one mobile application. As better games hit the market, mobile users will demand faster processors and more memory. Hopefully this will create a mutually beneficial relationship between consumers, phone manufacturers, and game developers, with better games driving better hardware and vice versa.

However, no matter how advanced hardware gets, there will always be three problematic areas for games on micro devices:

  • Processor speed

  • Memory

  • Video

Processor Paucity

A lot goes on under the hood in a typical game. Games must move the sprites, calculate new positions, check for collisions, and paint everything. Artificial intelligence adds additional processing.

All this functionality is supported by multithreading, where separate actions are executed at the same time. Threading is discussed in much more detail in Chapter 12, “Multithreaded Game Programming.”

In reality, however, only one thread is executed at any given time. The processor execution time is sliced into small time chunks, and each slice is used to execute a given thread's code. For slow human eyes, the fast execution of different threads makes it seem like many things are happening at the same time.

When all is said and done, the execution time of all the threads must be under a certain maximum. This maximum is usually dictated by the frame rate of the game. For example, to achieve 16 frames per second, the complete execution cycle must be invoked in under 62.5 milliseconds. That's possible only if the processor is powerful enough to execute the code needed for each animation frame in that time.

As you will soon see, most micro device processors are not powerful enough to deliver animations of 16 frames per second.

Memory Madness

Even if a processor was powerful enough, memory can dictate whether a device will support a given game. Although the CPU affects the overall speed of a game, memory problems can crop up at any time, because new objects are constantly being created.

Video Vex

Different micro devices also offer different screen resolutions. Although more and more color displays are coming out, especially in Japan, most mobile phones are still black and white. Drawing operations can be executed with different speeds on different devices. The more pixels a screen has, the more time is needed to draw a complete screen.

Most PDAs, for example, have large screens, generally 160×160 pixels or more. This makes for slower drawing times compared to smaller devices with the same processors.

Processors of the Future

The microprocessor is the brain and heart of every device. The J2ME CLDC specification doesn't force the hardware manufacturers to conform to any special processor, or even keep to a specific processor speed. Rather, any 16-or 32-bit processor can be supported.

Although Nokia, Siemens, and Motorola currently offer high-end mobile devices (such as the Nokia Communicator 9110, Motorola Accompli A008, and Siemens SL45i), these devices are expensive and geared toward a business audience. The most addicted game players are young and don't have a lot of their own money to spend on devices. As such, most of the gaming will likely be done on phones with very slow, cheap processors.

Memory Limitations

Memory is the place where the brain of the device stores its data, and where the list of things that need to be done (the execution code) is located. The J2ME memory model can be split into three sections:

  • Working memory—Where the device stores data needed only during the lifetime of the game. When the game is terminated, everything in this memory is forgotten. When the game is started up, the complete execution code is also copied here as the classes are loaded. This memory also holds all bitmap images created from PNG files.

  • Storage memory—Where the device stores RMS data in its own local database. When the game is terminated or the device is turned off, the information stored here remains.

  • Application memory—Where the device stores installed games and other applications. This memory can take the same place as storage memory.

All these memories have their limitations, depending on free memory. Although working and storage memory have an impact on the game execution, the application memory dictates how large the game can be and how many games can be installed onto a given device.

Working Memory

When the game is started up, it is first copied from the application memory into the working memory and then executed. In fact, only the classes that the classloader needs (the starting classes) are copied. Other classes are loaded upon their first instantiation. If games are too large to fit into working memory, the device notifies the user with an out-of-memory warning.

That restriction is one of the reasons why J2ME devices ask developers to restrict the size of their applications. Another reason is the fear that larger applications would crash the mobile network. If all 2G mobile networks are capable of 9600 bytes per second, an application with a size of 50KB needs almost a minute to be transferred from the Internet into the application memory. If thousands of users try to download a large popular game at once, then the network might become clogged.

During execution, a game constantly allocates memory for primitive data and objects. The created information takes up more memory space and can be divided into three groups:

  • Static data—Created when the class is loaded into the working memory. It occupies part of the memory and stays there as long as the game lives.

  • Global data—Created when the instance of the class is created. This stays in memory as long as the object is alive. When the object is destroyed by the garbage collector, the data disappears too.

  • Local data—Created each time the method that creates the variables is executed. At the end of the method, local variables become candidates for garbage collection. Local data is created and destroyed so often that is one of the biggest reasons for memory fragmentations.

Memory Fragmentation

Memory fragmentation happens when working memory is completely allocated with smaller objects. After a time, some of those objects are destroyed and some parts of the memory space are cleaned up. If developer checks for available memory, the device will return the correct value. But when the game tries to allocate a large object in memory, the object can't be placed anywhere because there is not enough consecutive room for it. The memory looks like Swiss cheese—a lot of empty space, but none of it in one clean block.

A good implementation of garbage collection should take care of this problem. Most J2ME virtual machines, however, don't have enough room for a good implementation. Chapter 11, “Making the Most of it: Optimizations,” contains tips and tricks for getting around this problem.

In general, the key to avoiding fragmentation and other memory issues is to avoid constantly allocating and de-allocating objects. Instead, try to create every object you need ahead of time. For example, you can create a pool of sprites. When you need a new object, grab an unused sprite from the pool instead of creating a new one. When you're done with the object, drop it back into the pool.

Memory Matters

All in all, it is important to build a compatibility list for any game you release. You should carefully check the specification for any device you are targeting, because every gadget has a different amount of working memory. For example, the Siemens SL45i has 128KB of available working memory, the Motorola i85 has 256KB, and the Motorola Accompli A008 has 640KB. Some larger games will only run on certain devices.

Storage Memory

Games also need memory for persistent storage of data, such as the current status, high scores, and so on. When the device is turned off, the storage stays intact and nothing is forgotten. This memory is usually larger than the working memory, and uses a different type of hardware, such as flash memory, a multimedia memory card, or even a small disk drive.

For example, the Siemens SL45i has a 32MB multimedia memory card (MMC) that can be replaced with a larger one, and is completely available for J2ME application and database storage. With J2ME applications averaging 30KB for each JAR file, each MMC can hold more than a thousand games! On the other hand, the Motorola Accompli A008 uses internal memory limited to 1.6MB.

Internal memories are smaller than memory cards, but are also faster. Speed can be important. The Siemens' MMC is very slow, and Siemens also suggests that developers use their non-standard File I/O API instead of local storage (RMS). The Accompli's RMS, because of its large memory, is also quite slow. On the other hand, the Motorola i85 and similar phones can manipulate the RMS relatively quickly.

RMS speed also has a lot to do with the Java implementation. The Java virtual machine for iDEN devices was developed in Florida, and the KVM for the Accompli A008 was built in Sweden. Apparently, developers in warm weather do a better job implementing database storage than those up north!

Displays

Screen resolution is one of the largest problems for game developers. If displays were standard on every J2ME device the way they are on personal computers, we could fix all images to one size everything would look fine.

Unfortunately, the graphics resolution of J2ME devices starts at 96×54 pixels, but is usually much higher (101×80 on the Siemens SL45i, or 240×234 on the Motorola Accompli A008). PDAs have even larger screens.

Additionally, some devices offer double buffering on the screen, while others do not.

Breaking Through the Limitations

Ultimately, game producers will have to make some tough decisions. On the one hand, it's a fine idea to support every J2ME device and make more income from a game. But, if you want your game to look really good, some lower-end devices will have to be excluded. Unfortunately, most mobile gamers will own cheaper devices with smaller screens, smaller amounts of memory, and slower processors.

Detecting the Minimum Speed

If your game is running too fast, users will be unable to play it. Enemies will move at the player too quickly, not giving the player enough time to dodge. If your game is running too slowly, it will become boring.

Finding the right execution speed is key. To accomplish this, your game should set a frame rate and try to achieve this rate no matter how slow or fast the device being used is.

Frame Rate

A frame rate is exactly what it sounds like—the rate at which one still frame flashes by, creating the appearance of motion. For example, think of a Bugs Bunny cartoon. Normally, a cartoon flickers by at 16 frames per second (FPS). This is quick enough for the human eye to believe that the image is “moving.” If the frame rate slows down, the eye begins to see choppiness and flickering.

In order for a game to achieve 16 FPS, the device would need to paint each frame in under 62.5 milliseconds. This is not feasible on most micro devices, given most processor and screen paint speeds. However, games are not as detailed as cartoons. Game characters are made up of larger pixels, and usually things don't change that much per frame. As such, a frame rate of 10 frames per second is acceptable, and gives the game 100 milliseconds to process and paint each frame. Chapter 17, “Sprite Movement,” delves into the finer points of sprite movement and painting.

Multiple Display Support

As new J2ME devices come out, your game will need to support new screen resolutions and color depths. One solution is to have different JAR files for each J2ME device. The difference between all those JAR files would be in the images within, as well as minor changes to the code that displays the image. For example, sprites on a device with a screen resolution of 200×200 pixels should be twice as large as those that are meant for a device with a 100×100 pixel screen.

It is a good idea to design your game into two separate classes:

  • Logical classes—This part represents the game itself, together with the game's artificial intelligence. This should be where 90% of all game functionality takes place.

  • Visual classes—This part is responsible for painting on the screen and information that depends heavily on the device specifications, such as screen size, image size, movement values, and so on. This code can either read in parameters and adjust drawing sizes on-the-fly, or can be totally rewritten for each new device.

Another approach is to use the lowest common denominator for all devices. For example, let's say that you want to support the following screen resolutions: 96×80, 120×64, and 102×72. Simply paint the game at 96×64 pixels and center the game in the screen. The empty space on the devices with larger screen resolutions can be filled out with a border image.

Black and White World

It would be a mistake to attempt to use color images in your game. Although most phones in Japan have color screens, most small devices around the world only have black and white screens.

When a device paints an image, the image's colors are translated into colors that are actually supported. If a phone can only paint in black or white, a colorful image will be reduced to an odd-looking smear.

As such, be sure to create all game images as black and white bitmaps. You can then scale up for better devices.

Summary

Limitations exist. That's life. Throughout this book, however, we will strive to break through the limitations. We will focus on how to create games that look as good as they can possibly look, no matter what the device is. The key lies in finding the right game execution speed and reducing the game's memory usage.

It is important to benchmark the processor speed, working memory size, storage memory size, and display for any device you want to target. You can then adjust your game's frame rate, graphics size and color depth, or artificial intelligence as appropriate.

The next chapter contains a slew of tips for optimizing the speed, size, and flexibility of your game code.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.40.189