0 Obfuscation / bytecode optimization

Wednesday, August 29, 2007 Labels:

Reducing size by obfuscating your midlet class files is a standard approach when developing J2ME games. It’s also a good way to protect your sources (non-obfuscated java class files can be decompiled from it’s bytecode to almost the same format as it was before you compiled your sources). Some obfuscators also has bytecode optimization features. That means that it analyzes the code and removes code and declarations that simply isn’t needed for the application’s functionality. A standard optimization that an optimizer can do is to remove all final static constants declarations.


The king of the java obfuscators / bytecode optimizers is Proguard. use it with eclipse or jbuilder.
Read more

1 Image optimization

Labels:

The PNG format is pretty versatile. It can contain bitmaps indexed with palettes in both 8-bit and 4-bit format, bitmaps in grayscale, bitmaps in 32bit color using alpha masks and so on.

The first thing you have to do is make sure that each image you use is converted to it’s most efficient color format. If it’s pixeled art, you can reduce the colors in an indexed palette to include just the ones needed. If it has anti-aliased edges, you must save it in 32bit color format to make use of the alpha channel (24 bit for the bitmap data, 8 bit for the alpha channel). 32bit images are always larger in byte size, but of course they look nicer. Even if you’re using 32bit images, it can be good to reduce the amount of different colors used as this makes the bitmap data easier to compress. An easy way of doing this is to use the “adjust - posterize” feature in Photoshop.

Note: It is possible to create 8bit indexed PNG files that use a 8 bit alpha channel using a program called PNGOutWin, but it’s not commonly supported and I’ve heard of problems with such images on certain phone models. (Anyway, thanks to Ed for pointing this out)

I use the “save for web” option in Photoshop when I first export my images for use in J2ME games, it is really good on producing indexed images.

The PNG format has support for a lot of descriptive “chunks” that’s not really needed just for drawing them in J2ME. These can be removed using PNG optimizer tools. Also, the PNG format uses the deflate algorithm for compression (just as ZIP does) so by using a tool that recompresses the data chunks using a more efficient deflate you can get even smaller PNGs. The PNG format also has support for different “filters” that varies the way the image data is stored. This can be used to optimize a PNG image for smaller size as well.

You can often reduce the total size of your images by joining them together into bigger images (that looks like film strips). The ground rule of compression is that data compresses better when the compression algorithm has more data to work with (instead of compressing images individually). However, sometimes it’s better to leave the images separate, as they can be using different optimized 8-bit and 4-bit palettes. You have to try different approaches to find what combination works best for your images.

Read more

0 Size optimization

Labels:

Size does matter! At least in the world of mobile game development. There are a lot of different reasons why you want your midlet Jar to be as small and compact as possible. Phone limitations is the most important reason. Old MIDP 1.0 phones often have a jar size limit of around 64kb, although newer phones are much more tolerant. And a large jar-file takes up more of the precious cell-phone memory. On some platforms, the size of the jar file even decreases the amount of available heap memory you have when you’re running your midlet.

Another reason is cellphone operator restrictions in downloading files, at least it was a couple of years ago (some wap-gateways had a size limit for files being downloaded). Another one is mobile content distributor requirements. They prefer modestly sized games, and that makes sense. If you’re going to sell your game, the users buying it don’t want to wait forever while downloading and they don’t want to be charged extra just because you couldn’t fit your game in less than 500 kb.

So, how do you create the smallest possible midlet jar? There are a lot of things to consider:


  • Use few classes.

  • Optimize your PNG images.

  • Use a good obfuscator/bytecode optimizer.

  • Recompress your Jar file.

Read more

0 Programming Tips

Labels:

Well, if you’re serious about making J2ME games, you’ve probably heard this one before, but I guess it doesn’t hurt to repeat it. You can’t use the standard object oriented java approach using a lot of classes, inheritance, getters and setters. You need to fit everything into just a few Java classes. Two or maybe three classes, that’s what you have to work with.


There are several reasons for this. Memory consumption is one thing, there is some memory overhead every time you create a new object from a class and so forth. Speed is another, on the low level side of it, true object oriented java creates more bytecode opcode instructions and more instructions take a longer time to execute.

But the main issue is size. And it has more to do with java midlet packaging in jar files than the structure of java bytecode, really. Midlet jar-files are compressed using the zip deflate algorithm, and deflate compresses files individually. Two separate files always get better compressed if you join them to one file. Basically, this is because the deflate algorithm gets more data to work with. So if you think about this, your jar file will compress better if you gather your code into a few java class files instead of having your code spread out in lots of smaller class files. The approach to join data into bigger data pack files to get better compression can be used for your game data (images, level data etc) as well.

So, two classes is basically what you need. One MIDlet class and one Canvas class. The canvas class can implement the Runnable interface so you can use it to run an update thread for your game animation.

Some other basic tips:

  • Use switch-case blocks instead of if-blocks as much as you can. Switch case blocks gets translated in to java bytecode “jump tables” when compiled that uses less instructions and runs faster. This is good for speed optimization, especially in your inner loops.

  • Access public variables directly instead of using get and set functions. This looks like bad programming, but it’s actually faster and uses less bytecode instructions.

  • Use local instead of global variables when you can. Using local variables is faster and uses less bytecode instructions.

  • Don’t forget to free memory by setting your objects to null when you don’t need them anymore. The garbage collector will take care of it when it gets a chance. If you want to be sure the garbage collector runs (after an initialization routine for example) you can always use the System.gc(); function to activate it.

  • Another very basic but still good tip is to always declare your constants to “final static”. The declarations are still going to be compiled into your java class file, but they get removed if you use a good bytecode optimizer such as Proguard.

Read more
 
Waqas Sadiq © 2014