Loading Images Into Your Game

Updated : 10/22/2007

The title says it all. We're gonna load some graphics into your game. We're going to build upon the project we made in the tutorial Basic MIDP 2.0 Game Template. So better do that part first if you haven't already. I will be referring to that project as "project".


Image Format
The preferred image format is the PNG format. This is a good thing since PNG supports alpha transparency which means that the images can be anti-aliased and smoother looking. The bad news is not all phones can display images with alpha transparent pixels correctly. It depends on your target phone. But it's still better to avoid alpha transparent pixels as much as possible.


Color Depth
Take note that different phones have different color depths. The color depth of the phones today ranges from 8-bit(256colors) to 24-bit color (16,777,216 colors). What does this all mean? While your hi-res imagery looks great on phones with higher depth, they would get dithered on phones with lower color depth making the images look pixelated. Further loss of color might even make your images unrecognizable given the small screen size the game will be viewed from.

There's also only a small amount of memory available on mobile phones for you to work with and pictures that use more colors eats up more memory. So as a rule of thumb use less colors for your graphics.


Introducing earth.png
For this tutorial I've prepared a quick-and-dirty 16x16 pixel version of your home planet. W000t!! I drew a whole planet in less than 5 minutes!! It's a bit large though coz' it used up 34 colors (502 bytes).

Actual Size of Earth (16x16)

earth.png




Enlarged View of Earth (64x64)

earth.png



Open an explorer window and navigate to the folder where you saved the project and make a backup of the whole project folder just in case something goes wrong (or for historical purposes). Better yet use a VCS like CVS or VSS. NetBeans supports either (VSS via plug-in). I

After making a backup, go inside the the project folder and inside the src folder.

So if the path to your project folder is:
c:\YourDocs\netbeans\BasicGameTemplate

...the path to the src folder should be:
c:\YourDocs\netbeans\BasicGameTemplate\src

Create a new folder inside the src folder named "images". The path to which should look like this:
c:\YourDocs\netbeans\BasicGameTemplate\src\images

Firefox users can right-click on the earth.png image and choose Save Image As from the context menu. IE users can right-click on the earth.png image and choose Save Picture As from the context menu. Save the PNG file in the images folder you just created. You can save any of the images above as they are the same file.

An even easier way to create the "images" folder is to:
  1. Open the project in NetBeans.
  2. Right-click on the project name in the Projects panel.
  3. From the pop-up menu, choose New and then Folder.
  4. Type "images" as the Folder Name in the resulting dialog box.
  5. Make sure src is selected as the Parent Folder.
  6. Click on the "Finish" button.


Loading the Image
Open NetBeans and press CTRL+Shift+O. This will bring about the Open Project dialog box where you can choose the project folder. You can also click on the purple/violet colored folder icon in the main toolbar. Don't forget to set it as the main project by selecting the Open as Main Project at the right side of the dialog box. If that was the same project you had open when you closed NetBeans, the project would be automatically loaded the next time you open NetBeans.

Open Project Dialog Box


Expand the nodes of the treeview in the Projects panel. You should now see the images folder listed there and earth.png listed under that folder.

Open Project Dialog Box


You can now open the class file clsCanvas.java so we can start coding.

First we need to make a global variable to hold our image. Let's name it "imgEarth". Declare imgEarth right under the fParent declaration like so:


private midMain fParent;
private Image imgEarth;



Now would be a good time to press Shift+ALT+F to update the imports section.

Let's make a new method named load() where we will place all the code to initialize our game. This is where we actually load the image file. Place it right after the start() method like so:


public void start(){
Thread runner = new Thread(this);
runner.start();
}

public void load(){
try{
// try to load the image file
imgEarth = Image.createImage("/images/earth.png");
}catch(Exception ex){
// exit the app if it fails to load the image
isRunning = false;
return;
}
}




The createImage() method of the Image class is used to load the image and assign the resulting Image object to our imgEarth variable. We used the method inside an exception handling block so you can catch the exception error it generates when it fails to load the image. Just so you know, NetBeans won't let you use it without exception handling.

Let's make an unload() method where we can place all the shutdown or cleanup code our game needs. Place it after the newly created load() method:


public void load(){
try{
// try to load the image file
imgEarth = Image.createImage("/images/earth.png");
}catch(Exception ex){
// exit the app if it fails to load the image
isRunning = false;
return;
}
}

public void unload(){
// make sure the object get's destroyed
imgEarth = null;
}





Now it's time to call the new functions inside the run() method. Place the load() method under the iKey variable declaration like so:


public void run() {
int iKey = 0;
load();
g = getGraphics();




...then call the unload() method after we assign null to the g variable:


}
g = null;
unload();
fParent.destroyApp(false);



When you're done, your clsCanvas code should look like this:


package MyGame;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;

public class clsCanvas extends GameCanvas implements Runnable {
private boolean isRunning = true;
private Graphics g;
private midMain fParent;
private Image imgEarth;

public clsCanvas(midMain m) {
super(true);
fParent = m;
setFullScreenMode(true);
}

public void start(){
Thread runner = new Thread(this);
runner.start();
}

public void load(){
try{
// try to load the image file
imgEarth = Image.createImage("/images/earth.png");
}catch(Exception ex){
// exit the app if it fails to load the image
isRunning = false;
return;
}
}

public void unload(){
// make sure the object get's destroyed
imgEarth = null;
}

public void run() {
int iKey = 0;
load();
g = getGraphics();
while(isRunning){

iKey = getKeyStates();

if ((iKey & GameCanvas.FIRE_PRESSED) != 0){
isRunning = false;
}

//set drawing color to black
g.setColor(0x000000);
//fill the whole screen
g.fillRect(0, 0, getWidth(), getHeight());
// set drawing color to white
g.setColor(0xffffff);
//display the key code last pressed
g.drawString(Integer.toString(iKey), 2, 2, Graphics.TOP | Graphics.LEFT);
flushGraphics();

try{
Thread.sleep(30);
} catch (Exception ex){

}
}
g = null;
unload();
fParent.destroyApp(false);
fParent = null;
}
}




Drawing the Image
To draw the image on the screen insert this line of code inside the run() method just before the flushGraphics() function call:



//draw the image
g.drawImage(imgEarth, 50, 50, Graphics.TOP | Graphics.LEFT);

flushGraphics();





The drawImage() method of the Graphics object g is used to draw the image unto our canvas at the coordinates 50(X), 50(Y). The last parameter, Graphics.Top | Graphics.Left, defines the anchor point or part of the image that will reside at the given coordinates. In this example the top-left part of the image will be positioned at coordinates 50,50 , X and Y respectively.

The completed clsCanvas source code:


package MyGame;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;

public class clsCanvas extends GameCanvas implements Runnable {
private boolean isRunning = true;
private Graphics g;
private midMain fParent;
private Image imgEarth;

public clsCanvas(midMain m) {
super(true);
fParent = m;
setFullScreenMode(true);
}

public void start(){
Thread runner = new Thread(this);
runner.start();
}

public void load(){
try{
// try to load the image file
imgEarth = Image.createImage("/images/earth.png");
}catch(Exception ex){
// exit the app if it fails to load the image
isRunning = false;
return;
}
}

public void unload(){
// make sure the object get's destroyed
imgEarth = null;
}

public void run() {
int iKey = 0;
load();
g = getGraphics();
while(isRunning){

iKey = getKeyStates();

if ((iKey & GameCanvas.FIRE_PRESSED) != 0){
isRunning = false;
}

//set drawing color to black
g.setColor(0x000000);
//fill the whole screen
g.fillRect(0, 0, getWidth(), getHeight());
// set drawing color to white
g.setColor(0xffffff);
//display the key code last pressed
g.drawString(Integer.toString(iKey), 2, 2, Graphics.TOP | Graphics.LEFT);

//draw the image
g.drawImage(imgEarth, 50, 50, Graphics.TOP | Graphics.LEFT);

flushGraphics();

try{
Thread.sleep(30);
} catch (Exception ex){

}
}
g = null;
unload();
fParent.destroyApp(false);
fParent = null;
}
}




Whenever your ready you can hit F6 on your keyboard and start the MIDlet when the emulator pops up. You should see the something like the screeny below.


Screen Shot of Output


Got an error? Something could've been done better? --> Post a comment.

Update
The code in this tutorial now runs in fullscreen mode. Details can be found here : Making a FullScreen Canvas

14 comments   |   post a comment
said...
I am a casual scanner of this blog who is very interested in learning more. Unfortunately I don't have time to dedicate to actually running the applications right now. My question/comment is this. I have not seen in the tutorials (yet)where the application is actually run on a mobile device, only an emulator. Given my experiences with this type of stuff so far, this is where you get bit. Did I miss it? Have you described the process of downloading and running the application on the mobile device?

Thanks! It's a great article.
said...
I mentioned it a bit in the Getting Started post but not in detail, sorry. The reason I only post screenshots of the applications running in the emulator is that it makes my life easier :). I mean the emulator is running in the pc so a screen shot is just a press of a button. The problem with taking a picture of the phone with the running MIDlets is that the mobile phones I use for testing don't have great camera resolutions (most only have vga or 1.3MP, and an S40 with 2MP) and would just appear blurred and whatnot. I would rather give you a clean picture of what we're trying to doing.

Another reason is that I can't make a tutorial on how to transfer the MIDlet to all types of mobile phones because I just don't have those devices (it would be nice if someone donates a device for testing purposes, heh ). The best I can probably do is show how to use Nokia PC Suite to transfer MIDlets to a Nokia Mobile Phone via Bluetooth or data cable because I only have access to Nokia handsets. Although it's rather limited, I think it will still be a good tutorial.

In any case, you can find the information on how to transfer files from the pc to the mobile device from the manufacturers website. Usually, you would need to download their software application and accompanying drivers. Most often, those applications already comes with mobile phone you purchased in the form of a cd-rom. Some phones even come with their own data cable to let you transfer files. It's all in a case to case basis. You have to refer to the technical specifications of the mobile device if it even allows you to install new MIDlets at all.

Here are some sample output taken from the tutorial No Commands: Delicious Graphical Menus. The phone is a Nokia 6233 s40 3rd Ed., MIDP 2.0 and has a 240x320 screen resolution. The MIDlet, on the other hand, is design for 176x208 screen resolution so it doesn't take up the whole screen even if it's in fullscreen mode. I tried to capture the picture three times in different lighting conditions using a Samsung SGH-E770 with a 1.3 Megapixel camera at 640x480. It has MIDP 2.0 but doesn't allow you to install additional games. The results aren't good but here are the links anyway:
(Hosted on Photobucket)
6233 Capture 1
6233 Capture 2
6233 Capture 3

The next picture shows the same MIDlet running on an N70 which has a 176x208 resolution, a perfect fit, and was taken by the same Nokia 6233 from the images above.
N70 Capture

Here's a link to a video of the same MIDlet running on an N70:
(Hosted on MOSH)
N70 Video Capture

I just currently don't have the means to make nice hi-res image/video captures, so I'll just have to make do with emulator screenshots. But if the readers think the quality of the images/videos above are good enough, then I will post images/videos of actual running MIDlets for all the tutorials.

I will try to make a tutorial on how to transfer a MIDlet to a NOKIA mobile phone via Bluetooth and data cable using Nokia PC Suite as soon as possible.

Maybe I'll even start making video tutorials like in Lynda.com but with a bad voice over, heh.

Thanx for the heads up.

(Does anyone want to donate a digital camera? Lol, just kidding XD)
said...
I'm just learning Java, and love what I've been reading so far.

As for loading to your own cell phones, the simplest way I've found was to store the files on my web host & just use my phone to download them.
said...
i have followed all the instruction..but i can't loop the midlet... the earth image just shown awhile and then dissapear again...i think it only shows 30 milisecond..
got error when i click the select on the emulator to run the midlet..
"Uncaught exception java/lang/NullPointerException."

how to solve this prob?
said...
Make sure you used the code created from the Basic MIDP 2.0 Game Template tutorial as this tutorial relies heavily on that framework. So if you miss a variable or failed to initialize an object you will get a null pointer exception.

Then check your code once again, line by line, against the complete clsCanvas code presented at the end of the article.

To make it a bit easier for you, here's the full source code for this tutorial created with NetBeans 6.0:
MyGame.zip (38.38KB)
Hi......
Do you have adventure mobile game sample?
Thanks....
said...
Have tried your examples on Eclipse IDE and its working great.
i have a problem in clsCanvas
coz in netbeans6.1 interface is different in 5.5 may you help me plz
said...
been watching ur blog for over 6 months, first of all : gratz ! it looks and reads pretty good :D also a lot of good usable examples which are a great base to develop own classes/code/skills :D
i'm pretty interested if anything new is in the pipeline ?
said...
Hi TiGeR,

I am deciding if I should release some code for a simple midp game framework to serve as an example on how to implement states, menu and in-game menu stuff. Actually, I already have the code done including the javadoc comments to explain the parts but I'm not sure if it's good enough....or if it will just be frowned upon.

I'm also thinking if I should convert the STME to java since not everyone uses Win OS but there's so many good cross-platform map editors out there already.

After that stuff, some basic Bluetooth usage and accessing server-side php scripts.

Although I've finished with most of my projects I'm still really busy so I really can't say when I'm going to finish all that.
said...
owh well, it's already good news to know that ur still busy developing ;)
and dont worry about the quality of the game framework, based on what I've seen till now I'd say that u know what ur talking about ;)
and always look at it from the bright side, all comments on it will only make it better and give you some insights on how some thigns can be done differently ;) thats how I cope with comments/critics most of the time :D
well, we'll see whats coming our way, I'm gonna keep ur blog in my bookmarks and check it out every couple of days, like I have been doing for some time now :D
Hello;
I read your tutorial and did what it say
but it could not load image
The CreateImage return NULL
Help me Pls
I was getting the NullPointerException too. I think what I had to do to fix it was put the load() function call above the g = getGraphics() function call. I had accidenally reversed them in my code.
said...
I would recommend to use Box.net instead for file storage. :)