Featured Posts, J2ME Programming, Tech Corner

How to create transparent image at runtime in J2ME

Introduction:

In many scenarios, we have to load images from resources, create a mutable image from it and finally create sprites from the mutable image. However, J2ME does not support transparent background for mutable images. the sprites will always appear inside a white rectangle.

This post will show how to make a transparent image at runtime in J2ME.

Advantage:

Can create, modify images at runtime, save up storage for image.

Requirement:

Any Java IDE with J2ME

Steps:

First, initialize the environment with game canvas, layer manager and background:

// initialize a layer manager
layerManager = new LayerManager();


// initialize game canvas
gameCanvas = new GameCanvas(true) {
public void paint(Graphics g) {
// delegate paint to the layer manager
layerManager.paint(g, 0, 0);
}
};
gameCanvas.setFullScreenMode(true);
gameCanvas.addCommand(new Command("Exit", Command.EXIT, 0));
gameCanvas.setCommandListener(this);

// create background image as a single cell tiled layer
Image background = Image.createImage("/res/background.png");
TiledLayer tiledLayer = new TiledLayer(1, 1, background, background.getWidth(), background.getHeight());
tiledLayer.setCell(0, 0, 1);
layerManager.append(tiledLayer);

// initialize an image and use it in a sprite.
Image transparentBackgroundImage = createTransparentBackgroundImage();
Sprite sprite = new Sprite(transparentBackgroundImage);
sprite.setFrameSequence(new int[]{0});
sprite.move(70, 110);
layerManager.insert(sprite, 0);

Second, write createTransparentBackgroundImage() method:

private Image createTransparentBackgroundImage() {
// allocate image
Image image = Image.createImage(100, 100);

// get graphics object to paint on image.
Graphics g = image.getGraphics();

// pick color yellow
g.setColor(255, 255, 0);

// draw a circle
g.fillArc(0, 0, image.getWidth(), image.getHeight(), 0, 360);

return image;
}

And the result is:
Screenshot 1

Now, rewrite the createTransparentBackgroundImage() method to create transparent image:

private Image createTransparentBackgroundImage() {
// allocate image
Image image = Image.createImage(100, 100);

// get graphics object to paint on image.
Graphics g = image.getGraphics();

// pick color yellow
g.setColor(255, 255, 0);

// draw a circle
g.fillArc(0, 0, image.getWidth(), image.getHeight(), 0, 360);

// convert image pixels data to int array
int[] rgb = new int [image.getWidth() * image.getHeight()];
image.getRGB(rgb, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());

// drop alpha component (make it transparent) on pixels that are still at default color
for(int i = 0; i < rgb.length; ++i) {
if(rgb[i] == 0xffffffff) {
rgb[i] &= 0x00ffffff;
}
}

// create a new image with the pixel data and set process alpha flag to true
return Image.createRGBImage(rgb, image.getWidth(), image.getHeight(), true);
}

The created image is now transparent:
Screenshot 2

Reference:
Transparent Images Created at Runtime in JavaME – http://www.online-brain.com/blogs/transparent

Standard
Games, J2ME Programming

How to use animated TiledLayer

Author: Quan To

Student ID: s3298400

Sprite does help a lot in J2ME animation control. However, sometimes, you’ll need a more complex animation than just one animated sprite. For example, in the game Bomberman, an explosion will need several animated parts: the chop, the body, the center, and except from the center, the other parts need images for up, down, left, right. Moreover, when the bomb explodes, each part needs to display the strength of the explosion changing over time, and all of the animation have to be consistent with each other.

Sprite does not seem to be a good solution for this problem. Firstly, one explosion may come up with a dozen animated parts, which means the layer manager have to manage that number of layers. And when multiple explosions happen at the same time, it is easy to lead to Stack Overflow or Out Of Memory Exception.

Fortunately, the regularly used for managing multiple tiles, TiledLayer, is capable of being animated. However, it is not simple setting the tile into another image. This article is going to demonstrate how to properly use n animated TiledLayer.

Let’s take the explosion in Bomberman as an example:

Let’s say I have this image as the resource:

Explosion

The resource is divided into 4 parts representing for 4 phases of the explosion, let’s say: initializing, increasing, exploding, destroying. Each phase has 9 images. We’ll have some “private static final” variable for these images. Using private static final variable will save a little bit more memory than using private final variable.

Code:

    private static final int MAP_WIDTH = 19;
    private static final int MAP_HEIGHT = 19;
    private static final int FRAME_WIDTH = 24;
    private static final int FRAME_HEIGHT = 24;
    private static final int EXPLODE_CENTER = 1;
    private static final int[] EXPLODE_LEFT = {2, 3};
    private static final int[] EXPLODE_RIGHT = {4, 5};
    private static final int[] EXPLODE_UP = {6, 7};
    private static final int[] EXPLODE_DOWN = {8, 9};

Additionally, we’ll need one more constant indicating the index of the start of each phase, and one more indicating the interval of the animation.

Code:

    private static final int INTERVAL = 60;
    private static final int[] PHASE_INDEXES = {0, 9, 18, 27};

Using an array to keep track of the position and function of each tile. The TiledLayer also needs to keep track of the animated indexes (the indexes of the animated tiles) and values of the tiles at those indexes (this value indicates the role of the tile, for example: center, left, right…). One more variable indicate the spread of the explosion

    private int explosionMap[];
    private int animatedIndexes[];
    private int tileRoles[];
    private LayerManager lM;
    private int spread;

Now we need to override the TiledLayer class. The class needs to implement Runnable interface to control its animation. I’m going to demonstrate a very simple explosion tile.

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.TiledLayer;

public class ExplosionTiledLayer extends TiledLayer implements Runnable {

    private static final int INTERVAL = 60;
    private static final int MAP_WIDTH = 19;
    private static final int MAP_HEIGHT = 19;
    private static final int FRAME_WIDTH = 24;
    private static final int FRAME_HEIGHT = 24;
    private static final int[] EXPLODE_LEFT = {2, 3};
    private static final int[] EXPLODE_RIGHT = {4, 5};
    private static final int EXPLODE_CENTER = 1;
    private static final int[] EXPLODE_UP = {6, 7};
    private static final int[] EXPLODE_DOWN = {8, 9};
    private static final int[] PHASE_INDEXES = {10, 19, 28, 37};
    private int explosionMap[];
    private int animatedIndexes[];
    private int tileRoles[];
    private int spread;
    private LayerManager lM;

    public ExplosionTiledLayer(Image image, LayerManager lM, int mapX, int mapY, int spread) {
        super(MAP_WIDTH, MAP_HEIGHT, image, FRAME_WIDTH, FRAME_HEIGHT);
        this.lM = lM;
        this.spread = spread;
        initExplosionMap(mapX, mapY);
    }

     private void initExplosionMap(int x, int y) {
        //Need to keep track of the number of animated tiles
        int count = 0;
        //Initialize map
        explosionMap = new int[MAP_WIDTH * MAP_HEIGHT];
        //Init with 0's
        for (int i = 0; i  0 && go > 1; i--) {
            explosionMap[MAP_WIDTH * i + x] = EXPLODE_UP[0];
            go--;
            count++;
        }
        explosionMap[MAP_WIDTH * i + x] = EXPLODE_UP[1];
        count++;
        //From center down
        go = spread;
        for (int i = y; i  1; i++) {
            explosionMap[MAP_WIDTH * i + x] = EXPLODE_DOWN[0];
            go--;
            count++;
        }
        explosionMap[MAP_WIDTH * i + x] = EXPLODE_DOWN[1];
        count++;
        //From center to the left
        go = spread;
        for (int i = x; i > 0 && go > 1; i--) {
            explosionMap[MAP_WIDTH * y + i] = EXPLODE_LEFT[0];
            go--;
            count++;
        }
        explosionMap[MAP_WIDTH * y + i] = EXPLODE_LEFT[1];
        count++;
        //From center to the right
        go = spread;
        for (int i = x; i  1; i++) {
            explosionMap[MAP_WIDTH * y + i] = EXPLODE_RIGHT[0];
            count++;
            go--;
        }
        explosionMap[MAP_WIDTH * y + i] = EXPLODE_LEFT[1];
        count++;
        //Center
        explosionMap[MAP_WIDTH * y + x] = EXPLODE_CENTER;
        count++;
        //There are 4 duplicates as all directions start from center
        count -= 4;
        /*Set cells*/
        //The number of animated tiles has been counted
        animatedIndexes = new int[count];
        tileRoles = new int[count];
        count = 0;
        for (int i = 0; i < explosionMap.length; i++) {
            int col = i % MAP_WIDTH;
            int row = (i - col) / MAP_HEIGHT;
            if (explosionMap[i] != 0) {
                int animatedIndex;
                if (explosionMap[i] != 0) {
                    //Initialize with PHASE_INDEXES[0]: Phase 0
                    animatedIndex = createAnimatedTile(explosionMap[i] + PHASE_INDEXES[0]);
                    setCell(col, row, animatedIndex);
                    //Have to save the animated indexes and the role of that tile
                    animatedIndexes[count] = animatedIndex;
                    tileRoles[count] = explosionMap[i];
                    count++;
                }
            }
        }
    }
    //Override run() method of Runnable interface
    public void run() {
        //Loop through every phases
        for (int j = 0; j < PHASE_INDEXES.length; j++) {
            for (int i = 0; i < animatedIndexes.length; i++) {
                setAnimatedTile(animatedIndexes[i], tileRoles[i] + PHASE_INDEXES[j]);
            }
            //Sleep a while
            Utilities.sleepThread(INTERVAL);
        }
        //Rollback
        for (int j = PHASE_INDEXES.length - 2; j >= 0; j--) {
            for (int i = 0; i < animatedIndexes.length; i++) {
                setAnimatedTile(animatedIndexes[i], tileRoles[i] + PHASE_INDEXES[j]);
            }
            //Sleep a while
            Utilities.sleepThread(INTERVAL);
        }
        lM.remove(this);
    }
}

How to use ExplosionTiledLayer:

Precondition: Availability of an instance of LayerManager, position of the explosion on the map, the image for the tiles and the spread of the bomb (How far will the bomb reach.)
Example Code:

 ExplosionTiledLayer explosion = new ExplosionTiledLayer(image, layermanager, 4, 5, 3);
 layerManager.append(explosion);
 /*
    Or: 
        layerManager.insert(explosion, position); 
    with position is an index between 0 and layerManager.getSize()
 */
 Thread thread = new Thread(explosion);
 //Let the animation begins
 thread.start();

 

Standard
Featured Posts, J2ME Programming

How to – Setup score storing script

Introduction

J2ME supports Http(s) communication, so people can use it to send and receive score to server. The sample script has been provided by our handsome lecturer – George Nguyen. However, we need to set it up in order to use it. Here is how.

2.     When should you apply this? (Optional)

People should apply this when they want to implement the script on their own server.

3.     Advantages & disadvantages

  • Advantages:
    • Full control over everything
    • Fast (not Mekong server!)
    • Can implement more features by re-coding the script
  • Disadvantages:
    • More complicating
    • Require server with appropriate support.
    • Require setup steps.
    • Require maintenance.

4.     Requirements

5.     Steps & Screen shots

1.      Extract the script bundle into a folder. For example: /mad
2.      If you use Mekong Server, proceed to the next step.

Setup an account on 000webhost.com (This is a very good free web hosting for PHP web applications. It supports nearly all popular PHP functions. If you cannot visit it to sign up, use a proxy or VPN instead because they block some of Vietnam’s IP ranges.)

Step 1. Go to Homepage, click Sign Up

Step 1. Go to Homepage, click Sign Up

Step 2. Fill in information

Step 2. Fill in information

3.      Use Filezilla to connect to the server.

3.1.   Mekong Server:
Host: mekong.rmit.edu.vn
Port: 22 (NOT21)
Username and password

3.2.   000webhost.com
Login to your account and CPanel, then click on View FTP Details to see details.

Link to login: http://members.000webhost.com/login.php

Step 3. Login to Your Account

Step 3. Login to Your Account

Step 4. Go to CPanel

Step 4. Go to CPanel

Step 5. View your host details and FTP info

Step 5. View your host details and FTP info

Step 6. This is FTP info to connect

Step 6. This is FTP info to connect

Step 7. Connect to FTP using FileZilla

Step 7. Connect to FTP using FileZilla

4.      Upload /mad to your /public_html folder.
Most web hosting use /public_html folder. If this is not your case, follow your web hosting provider instructions.

 

5.      Set permission for highscore.xml to 666 (This is the most important step)

In Filezilla, tab Remote, right-click on highscore.xml and choose “File permissions…” and type 666 in the textbox, click OK.

 

6.      Now, your script is ready to be used.

Use the URL as below:

Remember: this is HTTPS, and Mekong will redirect any HTTP to HTTPS. Therefore, in your J2ME, you must use HttpsConnection; otherwise you will receive only an html file whose content is a 302 – Found response from server.

Find chosenname.chosendomain information in your CPanel or on the Signup page, or in the email sent to you.

 

6.     Reference

Written by myself!

Student ID: 3342135

Degree: Bachelor of Information Technology – Application

Standard