Dev 135 – J2ME and graphics

When creating a program and in particular a video game most of the attention obviously goes to the graphic aspect. For this reason we will introduce the fundamental concepts to use the drawing tools offered by MIDP2.

After having established a “standard” architecture – in the last article – for the functional core of our future applications we will focus on one object in particular. The program shown introduces the first concepts for drawing on the display through a short example of a greeting text and several colored quadrilaterals. It is all about to use one of the fundamental characteristics of all devices that lend themselves to being used in gaming applications, that is the ability of these to show writings, images, shapes and colors.

The Graphics class

Devices that support the MIDP2 profile make the Graphics class available to programmersThis has methods for drawing simple 2D primitives such as text , images, rectangles, lines, arcs and triangles . Closed figures such as rectangles, angles and arches can be filled with any color.

Speaking of colors, they are managed at 24bit with 8bit triads to represent each of the three RGB components. Working with images you can also make use of an additional channel called Alpha channel (transparency channel) through which it is possible to create overlapping effects with transparency.

The previous article mentioned the problem of the diversity of characteristics possessed by the displays of different devices. For this reason it has been structured to let the program require data relating to the characteristics of its display in terms of color depth and transparency levels from device on which it is executed.

Other important features of this class are the possibility of creating clipping areas and translating the origin of the reference system. This allows you to change the size and position of the area within which the output is displayed . This feature is useful – for example – when the display size of a device is different from that of the device used for the application development. In this situation to avoid unpleasant visual anomalies it will be necessary to resize and center the output area with respect to the screen. It is also possible to obtain the reference to the Graphics object of an image for reading its pixels’ values or modification of the same.

Draw the primitives

The first and simplest topic to be discussed here is the use of drawing primitives. To do this you can download the file related to this article from the FTP site. Inside the ApplicationBase folder you will find the template code. After creating a new project with the Wireless Toolkit copy the Template.java and TemplateCanvas.java files to the src folder created by the tool.

Inside the folder MIDP Classification Documentation you will find the documentation of the aforementioned classes and methods.

Therefore, we will create a program that shows a scrolling greeting string on the display. The Listing 1 shows the code to be inserted inside the method draw () in the file TemplateCanvas.java. 

int x = 0, y = 0, direction = 0;
        
private void draw()
{   
    String greeting = new String("Hello World!");
            
    Font f = Font.getFont(0);
            
    g.setColor(0, 0, 0);
    g.fillRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);

    x = DISPLAY_WIDTH / 2 - f.stringWidth(greeting) / 2;
            
    g.setColor(0, 0, 255);
    g.drawString(greeting, x, y, 0);
           
    g.setColor(255, 0, 255);
    g.drawRect(0, y - f.getHeight() / 2, DISPLAY_WIDTH - 1, f.getHeight() * 2);
           
    g.setColor(255, 0, 0);
    g.drawString("Hello World!", x, DISPLAY_HEIGHT - y, 0);

    g.setColor(0, 255, 255);
    g.drawRect(0, DISPLAY_HEIGHT - y - f.getHeight() / 2, DISPLAY_WIDTH - 1, f.getHeight() * 2);
            
    if (direction == 1) {
        y++;
        if (y + f.getHeight() / 2 >= DISPLAY_HEIGHT) direction = 0;
    } else {                
        y--;
        if (y - f.getHeight() / 2 <= 0) direction = 1;
    }
}

Let’s review the instructions

g.setcolor(0, 0, 0);
g.fillRect(0, 0, WIDTH_DISPLAY, HEIGHT_DISPLAY);

With the call to the setcolor method we set the color that will be used for subsequent drawing operations. It should be noted that there are several variants of the method, but we have chosen the most intuitive one that allows to specify a value for each of the three RGB components. These values ​​can vary, as usual, between 0 and 255. With a triad of zeros we indicate to the system to use the black color.

The second instruction is used to draw a rectangle filled with the color just specified. From the definition of the fillRect method we can easily interpret the meaning of the parameters passed to it. In practice we want to fill the entire screen at each frame thus erasing its previous contents. In this way we will have a clean and ready display.

With the following instructions now we draw the classic “Hello World!” in positions progressively moved upwards 

g.setColor(0, 0, 255);
g.drawString(greeting, x, y, 0);
g.setColor(255, 0, 255);
g.drawRect(0, y - f.getHeight() / 2, WIDTH_DISPLAY - 1, f.getHeight() * 2);

It is trivial to guess which change will be reflected in the design color. The second call requests that the string indicated at x and y coordinates be displayed. Let’s change the drawing color again to get purple and draw a rectangle around the string, centering it correctly inside it. To obtain this last result it was necessary to use the Font object which returns the height of the string drawn on the screen according to the font currently used. Now try to compile and run the program to see the results obtained.

Manage images

Going beyond the simple draw of trivial shapes MIDP2 offers the possibility to load, edit and view image files. We will introduce the Image class which exposes the methods to generate image objects by decoding the data present on files inside the JAR package – usually in PNG format – or creating new ones according to particular criteria. As you can see from the summary in Figure 1 you can crop a portion of an existing image, use a buffer containing a series of integers or create a completely empty and editable area.

Figure 1 – Summary of methods of the Image class

Keep in mind that MIDP provides two ways of accessing the memory used to maintain the image data. In fact, we must distinguish between mutable and immutable images .  

It is possible to modify only the mutable ones, ie created from scratch by the method

static Image createImage(int width, int height) 

while all other types are not editable.

For the moment we are interested in learning how to upload images from PNG files and for this reason we will create a new project, as done previously.

This time, in the package on the FTP site, a subfolder called res was added where the project resources are stored, that is, the images to be loaded.

Below the new function createImage added to the class Image

private Image background = null;
private Image sphere = null;

private void upload Pictures()
{
    try {
        sfondo = Image.createImage("/res/sfondo.png");
        sfera = Image.createImage ("/res/sfera.png");
    } catch (Exception e) {
        // Error loading images
    }
}

As you can see the paths indicated are relative to the root “/” which coincides with the virtual path within the JAR package.

At this point the game is done. To display the newly loaded images on the screen, just use the appropriate method of the Graphics class

void drawImage(Image img, int x, int y, int anchor)

The draw() method can be implemented this way

int x = DISPLAY_WIDTH / 2, y = DISPLAY_HEIGHT / 2, directionX = 1, directionY = 1;

private void draw()
{   
    g.drawImage(background, 0, 0, 0);
    g.drawImage(sphere, x, y, 0);

    if (directionX == 1)
    {
        if ((x += directionX) + sphere.getWidth() >= DISPLAY_WIDTH) direzioneX = -1;
    }
    else if(directionX == -1)
    {
        if ((x += directionX) <= 0) directionX = 1;
    }

    if (directionY == 1)
    {
        if ((y += directionY) + sphere.getHeight() >= DISPLAY_HEIGHT) direzioneY = -1;
    }
    else if(directionY == -1)
    {
        if ((y += directionY) <= 0) directionY = 1;
    }
}

obtaining a simple but certainly effective animation, visible in Figure .

Figure 2 – The output of the demonstrative program without setting the cutting area

Clipping and translation of the output

We now want to correct the display defect presented in the example given here. As mentioned in the introduction, MIDP 2 gives the possibility to restrict the output area and reposition it anywhere in the display.

In fact, we would like to ensure that the ball remains within the area occupied by the background image. This image is composed of 176 x 220 pixels, against the 240 x 320 of the emulator display.

It is a very simple operation, just add the following lines in the start() method or in the class constructor

int px = (DISPLAY_WIDTH - 176) / 2;
int py = (DISPLAY_HEIGHT - 220) / 2;

g.setClip(px, py, 176, 220);
g.translate(px, py);

The call to the setClip() function just specifies the output clipping area. The variables px and py contain the value of the position of the upper left corner of this area, while 176 and 220 are the dimensions of the background image.

The translate() function makes the origin of the reference system coincide with the angle of the clipping area to make this change transparent to the application.

Obviously some changes will have to be made to the code that moves the ball. In particular we will have to change the lines

if ((x += directionX) + sphere.getWidth() >= DISPLAY_WIDTH) directionX = -1;
…
if (( y+= directionY) + sphere.getHeight() >= DISPLAY_HEIGHT) directionY = -1;

in

if ((x += directionX) + sphere.getWidth() >= g.getClipX() + g.getClipWidth()) directionX = -1;
…
if ((y += directionY) + sphere.getHeight() >= g.getClipY() + g.getClipHeight()) directionY = -1;

just because now we can generalize the situation by determining the position and size of the crop area as boundaries.

Conclusions

We are diving more and more in depth into the exploration of the mobile world. The beauty is still to come, especially when we face the most advanced topics. How could you see the use of MIDP2 profile classes is anything but complicated. It will be enough, in fact, to refer to the documentation of the classes to create very sophisticated effects.

I added a further demonstration program to study, see Figure 3 .

Figure 3 – This demonstration program brings together all the concepts presented, creating a sort of Christmas card with lots of snowflakes and running lights.

That’s all for now and I wish you a very happy Christmas!

Bibliography

  1. Carol Hamer , ” J2ME Games with MIDP2 “, Apress, 2004 , ISBN 1-59059-382-0, www.apress.com
  2.  John W. Muchow , ” J2ME Practical Guide to Programming Wireless Devices “, Mc Graw Hill , 2002, ISBN 88-386-4278-8 , website

Original article

Downloads

Leave a Reply

Your email address will not be published. Required fields are marked *