At the same time as we load and create all our needed Images we can create our off screen buffer if needed.
- Code: Select all
/*
* Creates all the needed images, called upon creation
* of our GameScreen class
*/
public void createImages()
{
try
{
//if device doesnt do automatic double buffering
if( !isDoubleBuffered() )
{
//create offscreen Image
bufferImage = Image.createImage( getWidth(), getHeight() );
//get a Graphics context to we can render onto the bufferImage
buffer = bufferImage.getGraphics();
}
myImage = Image.createImage("/sprite.png");
}
catch( Exception e )
{
e.printStackTrace();
}
}
We create a new empty Image by calling Image.createImage( width, height ). The Image should be the exact same size as the Canvas's viewable area. In MIDP there are Mutable and Immutable Images. The difference being that Immutable Images, the ones created from image files/data, cannot be modified once created. A mutable Image, normally created through Image.createImage( width, height) can be modified by obtaining a Graphics context that will render to the Image itself. This is done by calling getGraphics() on the Image. This is what we have done for our back buffer!
With a small modification to our paint() method we can accommodate for those devices that do not do the buffering for us.
- Code: Select all
/*
* called when the Canvas is to be painted
*/
protected void paint( Graphics g )
{
//cache a reference to the original Graphics context
Graphics original = g;
//if device doesn't do automatic double buffering
if( !isDoubleBuffered() )
{
//change the g object reference to the back buffer Graphics context
g = buffer;
}
//set the current color of the Graphics context to the specified RRGGBB colour
g.setColor( colour );
//draw a filled rectangle at x,y coordinates 0, 0 with a width
// and height equal to that of the Canvas itself
g.fillRect( 0, 0, this.getWidth(), this.getHeight() );
//draw an image to the centre of the screen
g.drawImage( myImage, this.getWidth()/2, this.getHeight()/2, Graphics.VCENTER | Graphics.HCENTER );
if( !isDoubleBuffered() )
{
//draw the off screen Image to the original graphics context
original.drawImage( bufferImage, 0, 0, Graphics.TOP | Graphics.LEFT );
}
}
This might be a little confusing at first, at the top of the paint() method we keep a reference to the original Graphics context that was passed as a parameter to the method. We then check whether we need to perform the double buffering, if so we change the Graphics context that the g variable references to the Graphics context obtained from the buffer Image. At the end of the paint method we again check if we needed to perform the double buffering, and draw the buffer Image to the original Graphics context we kept earlier.
To wrap up, lets change our input handling so we can move our image around the screen by pressing the keys.
- Code: Select all
/*
* called when a key is pressed and this Canvas is the
* current Displayable
*/
protected void keyPressed( int keyCode )
{
//get the game action from the passed keyCode
int gameAction = getGameAction( keyCode );
switch( gameAction )
{
case LEFT:
//move image left
imageDirection = LEFT;
break;
case RIGHT:
//move image right
imageDirection = RIGHT;
break;
case UP:
//move image up
imageDirection = UP;
break;
case DOWN:
//move image down
imageDirection = DOWN;
break;
case FIRE:
//set current to a random colour
colour = generator.nextInt()&0xFFFFFF;
break;
}
}
/*
* Our games main loop, called at a fixed rate by our game Thread
*/
public void tick()
{
int myImageSpeed = 4;
switch( imageDirection )
{
case LEFT:
myImageX-=myImageSpeed;
break;
case RIGHT:
myImageX+=myImageSpeed;
break;
case UP:
myImageY-=myImageSpeed;
break;
case DOWN:
myImageY+=myImageSpeed;
break;
}
//schedule a repaint of the Canvas
repaint();
//forces any pending repaints to be serviced, and blocks until
//paint() has returned
serviceRepaints();
}
