Hi all.
I was trying to figure out which approach to Sprite Management could be more efficient on Nokia devices.
I try to describe my remarks with a simple example.

The structure of a typical game MIDlet could be:

class MainMIDlet extends MIDlet >>> the MIDlet class of our game
class GameStage extends Canvas/FullCanvas >>> the class used to display and control the game
class Sprite >>> the class from which we're going to create our sprites displayed in the GameStage
...

Let's say we have a large image "allSprites.png" containing all the frames of all sprites we're about to use in our game (players, enemies, obstacles, ...).
In the following code we assume we have only one transparent Sprite object made of 4 frames and the image allSprites.png is tiled orizontally.


Two approaches will be described: the "Nokia approach" [ref. Nokia_UIAPI_Guide.pdf] and the "MIDP approach" =)




************** NOKIA STYLE (ref. Nokia_UIAPI_Guide.pdf)

class GameStage extends Canvas{
// stuffs
// ...

// the file name of the Image
static final String SPRITESIMAGE_NAME = "allSprites.png";
// the Image containing all the sprites
private Image imgAllSprites = Image.createImage(SPRITESIMAGE_NAME);
// the sprite
private Sprite mySprite = null;


private void createSprites(){
// stuffs
// ...

// create mySprite instance here
int numFrames = 4;
int frameWidth = 12;
int frameHeight = 12;
mySprite = new Sprite(imgAllSprites, numFrames, frameWidth, frameHeight);

// now kill the imgAllSprites Object
imgAllSprites = null;
}

// stuffs
// ...

}

/* >>>>>>>>>> The Sprite Class Nokia Style <<<<<<<<<<< */
class Sprite {
// stuffs
// ...

// Image array containing the Sprite's frames
private Image[] _frames;
// a transparent color used to create the mutable images
private int _transpCol = 0x00000000;
// current frame
private int _currFrame;

// constructor
public Sprite(Image imgAllSprites, numFrames, frameWidth, frameHeight){
_frames = new Image[numframes];
for (int i = 0; i < numFrames; i++) {
// create the i mutable transparent image
_frames[i] = DirectUtils.createImage(frameWidth, frameHeight, _transpCol);
// get its Graphics
Graphics g = _frames[i].getGraphics();
// draw the frame from the imgAllSprites Image
g.drawImage(imgAllSprites, -frameWidth * i, 0, Graphics.TOP | Graphics.LEFT);
}
// set the current frame to 0
_currFrame = 0;
}

// method to draw the the current frame in x,y
public void paintSprite(Graphics g, int x, int y){
g.drawImage(_frames[_currFrame],x,y,Graphics.TOP|Graphics.LEFT);
}

// stuffs
// ...

}





************** MIDP STYLE

class GameStage extends Canvas{
// stuffs
// ...

// the file name of the Image
static final String SPRITESIMAGE_NAME = "allSprites.png";
// make imgAllSprites Class visible so define it static
private static Image imgAllSprites = Image.createImage(SPRITESIMAGE_NAME);
// the sprite
private Sprite mySprite = null;


private void createSprites(){
// stuffs
// ...

// create mySprite instance here
int numFrames = 4;
int frameWidth = 12;
int frameHeight = 12;
mySprite = new Sprite(numFrames, frameWidth, frameHeight);
}


// stuffs
// ...

}

/* >>>>>>>>>> The Sprite Class MIDP Style <<<<<<<<<<< */
class Sprite {
// stuffs
// ...

private int _numFrames, _frameWidth, _frameHeight;
private int _currFrame;

// constructor
public Sprite(numFrames, frameWidth, frameHeight){
_numFrames = numFrames;
_frameWidth = frameWidth;
_frameHeight = frameHeight;
// set the current frame to 0
_currFrame = 0;
}

// method to draw the the current frame in x,y
public paintSprite(Graphics g, int x, int y){
g.setClip(x,y,_frameWidth,_frameHeight);
// "slide" imgAllSprites under the clipping area
g.drawImage(GameStage.imgAllSprites,x - (_currFrame*_frameWidth),y,Graphics.TOP|Graphics.LEFT);
}

// stuffs
// ...
}




>>>>>>>> REMARKS:

In The NOKIA-style approach:

1. The original Image imgAllSprites is discharged after the Sprite Creation.
2. There are new NF*NS Image Objects created(where NF is the number of the frames for each sprite and NS is the total number of Sprite objects created).
3. It works ONLY on Nokia devices
4. On most emulators a transparent sprite is displayed as fully opaque. (like Series 60 Concept Beta SDK - the 7210 SDK displays transparency correctly)

In The MIDP-style approach:

1. The original Image imgAllSprites is NOT discharged after the Sprite Creation.
2. No objects are built after creating the Sprites instances.
3. It works on every device (transparency available where supported)
4. It works on every emulator



>>>>>>>> TESTING:
I made a few tests on several devices for both memory usage and speed.
Results were somehow inconsistent from device to device.
No differences in execution speed (tested with a thread spinning many sprites derived from a large image).
With the Nokia emulators the first ("NOKIA approach&quot is definetly faster (the other one often stops when changing frames of a moltitude of sprites).



>>>>>>>> CONCLUSIONS:
I would say the second approach is the best since it creates less objects on the heap and it's somehow more portable then the Nokia one.
Moreover the Nokia approach seems not to work very well on many devices (see this forum =).

I can't figure out how the creation of many small image tiles from the same image and the overhead generated after the creation of many new object could possibly sum up as a less heap usage.


What's your opinion?
Any suggestion/idea?


cheers

davide
<AtomicTag.com/>