A few J2ME related questions

Started by
25 comments, last by thelegendofzaku 18 years, 1 month ago
Since I'm trying to write a 2D platform game, I need help implementing the following: How do I make a rectangular bar that increments or decreases for applications such as a loading bar and/or a life bar? In other words, I need help implementing a loading screen and a life bar for my game sprite. How do I make my sprite move through the screen's tile layers according to user inputed directions and where would I implement this? How do I implement a Loading and Saving feature that creates a saved game file? Thanks in advance.
Advertisement
Creating a bar can be as complex or as a simple as you want. One quick way to do it, would be to use fillRect() and draw on the screen based on a counter that you use. This counter could be updated many ways, from a switch statement that loops through after every call to paint() or in a seperate thread that has access to a static or public member variable in one of your classes. pseudocode could be(not tested)

private int m_iLoadingProgess = 0;public void paint( Graphics g ){LoadSomething();g.setColor( 0xff2345 ); //dunno what color that is...but good for demonstrationg.fillRect( kScreenHeight>>1, 0, kScreenHeight>>1 + 10, iLoadingProgess * 5 ); //kScreenHeight is a constant for the screen height}public void LoadSomething(){switch( m_iLoadingProgess ){case 0://load resource Acase 1://Load resource Bcase 2://load resource C//exit the loading sectiondefault:


Loading and saving issues are pretty easy. Use J2ME's RecordStore classes. use addRecord() to create a new record in the record store, and then setRecord() to update a currently get a new record or getRecord() to get the data from a record store. One peice of advice that I do is use constants to define where in the record store everything is. for example recordstore 1 (yes...j2me starts with 1 not 0 ) could be the characters Life. 2 could be level...et cetera. Some people prefer to store everything in RecordStore slot 1 as a byte array that way its more like reading a file. that's fine too.

hope that gets u off in the right direction.

~guyaton
~guyaton
I'm really confused as to where to implement a loading bar and what processes would trigger it to increment the bar. In other words, should I make a seperate class for this and run the method through the main MIDlet? Also, how would I know if certain images for tile maps and sprites are loaded? Can you be more clearer?
You must have some kind of state machine in the application right? Just create a new state that will represent the loading. I am not sure how your state machine runs, but the loading state itself will also need substates. In each substate, you want to do a small portion of the loading. For example, one image or some data file. Once each resource is loaded, you would exit the function, allowing other aspects of the app (mainly the paint() function) to be called, which will draw the updated bar based on how far along in the state you are. As far as needing another class, I am guessing not, but it totally depends on how your application is set up. You will know if certain images are loaded, by whether or not your load function threw in error, in which case that would need to be handled accordingly.

Hope this answers your questions,

~guyaton
~guyaton
You know what, I'll hold off on the loading screen issue until I can first solve this issue:

I have my game canvas set up and I was wondering, how do I make my sprite move through the tile layer and move the game screen along with it?
This question actually depends a lot on the hardware you are running it on. Some phones are slower then others or may have less heap and therefore need to be compensated accordingly. Another thing to be aware of, GOOD framerate on phones is horrible frame rate on computers, so don't be shocked if you see frame rate that is low. On some decent handsets that I've worked on 12-15 fps was considered good. To start, of course you need some image (I would recommend .png as they support transparency), and this image can be composed many different ways. The easiest way is for the image to compose frames that make up the animations. For example:

(Assume this is a png file here)
| Walk frame 1 | Walk frame 2 | ...etc
| Run frame 1 | Run frame 2 | ...etc


Each series of animations may take a different amount of time for them to complete, so you may want to create constants for those. Then u can just interpolate over time. Making sure to set you clips to show only the current frame in the animation.

You will also need tile layers. It depends on how complex you want the scene to be, but I think 4 frames will probably provide you with a nice looking scene. The tile layers COULD be as follows: (in order of drawing to the screen)

* Background (probably just a static image that you can draw such as sky etc)
* Forground layer (your main level)
* The main character and enemies
* a sprite or "action" layer (such as bullets, fire from various traps, explosions, etc. )

The forground layer is best when subdivided into smaller peices so that it can be reused throughout the game. For example: a brick in mario world, you just have 1 image of a brick, and u draw it over and over instead of 1 BIG tile that contains all the brinks).

The most efficient way to do this, is to use a back buffer (which is really just an Image that you create of varying width and height. In most cases (depends on the phone) you want to create this image larger then the screen size. You draw everything to this image first, getting the Graphics like this:

Image someImage = new Image.createImage( 400, 800 );
Graphics g = someImage.getGraphics();

Then you draw the 2 base layers on to that and from there you use the backbuffer to draw the background, then draw the top layers so that you minimize the actual graphics calls you make.

This is a link I found on Google, which might help you out a little bit.

hope this helps,

~guyaton
~guyaton
OK, I'm about to implement the loading bar. But before doing so, I wanna write it out here in conjunction with my current code so that you can let me know if I'm doing this correctly. As of late, I've been having this problem where I can't seem to load my Game Canvas from my main menu, even though I've been trying to invoke the setCurrent method of the Display class to do it, unless of course I'm doing it all wrong. Anyways, here's my main menu, what I have for my loading class, my game canvas, and my level class that handles the tile layer. If there is a better way I should structure my current classes, by all means feel free to edit this code:

EDIT: New code is a few posts ahead.

I'll post my tile map and player sprite class upon request.

[Edited by - thelegendofzaku on February 14, 2006 9:19:03 PM]
Few changes that I see that are very obvious to me:

Main MIDlet:

1)
public Display getDisplay()
{
return display;
}

*** not needed. If you ever need the display, just do:
Display.getDisplay( MainMIDlet /*or whatever ur MIDlet Class is*/).setCurrent( /*some Displayable*/ );

2) If you want to use Threads with the LoadingScreen class, it needs to impliment Runnable.

public class LoadingScreen extends Canvas impliments Runnable
{

public void run()
{
//this will terminate the thread as soon as the counter reaches whatevre value it should reach.
while( counter < MAX_CTR_VAL )
{
repaint();
serviceRepaints();

try
{
Thread.sleep( 50 );
}
catch( Exception e ){}
}
}

3)
paintThread= new Thread(this);
paintThread.start();
repaint();

***
Remove these 3 lines and replace the only the first 2 should belong in the constructor. (It will work now that you've implimented runnable).

4) One small optomization to do, is in the LoadingScreen class:
private int k = 160/2;

***Instead of dividing by 2, its faster (especially if you are doing it alot) to bitshift one. So in other words:
private int k = 160>>1;

5) One thing that I have found very useful, is in the "main" MIDlet class always have a static variable that keeps an instance of the MIDlet, for example:

public MyMIDlet extends MIDlet
{
MyMIDlet m_PublicMyMIDlet = null;

MyMIDlet()
{
PublicMyMIDlet = this;
}


6) In the constructor of the LoadingScreen class, add this in the constructor:
Display.getDisplay( /*MIDlet class here, from fix 5: MyMIDlet.m_PublicMyMIDlet*/ ).setCurrent( this );

I haven't had a chance to look through the GameScreen class yet. I will have to check that out later.

~guyaton
~guyaton
Well, I managed to work a little bit more on the LoadingScreen class and for some reason, Netbeans, my IDE, is complaining that I did not extend the Canvas class. Here it is. Also, I was also told that another way to do this was to create seperate draw methods so that they can be called when I select "New Game" in the main menu.

Edit: I found why I didn't extend Canvas, drawLoadScreen should of been named paint :D.
package de.enough.polish.example;import javax.microedition.lcdui.*;import javax.microedition.lcdui.Canvas.*;import java.util.*;import java.lang.*;public class LoadingScreen extends Canvas implements Runnable{    private int MAX_CTR_VAL=2;    private int counter;    private int page;    private Image img1, img2;    private int width, height;    private int k = 160>>1; //160 pixels wide I want my bar to be.    private Thread paintThread;    MenuMidlet myMidlet;    public LoadingScreen() {        page=0;        myMidlet = new MenuMidlet();        Display.getDisplay(myMidlet).setCurrent(this);        paintThread= new Thread(this);        paintThread.start();        width = getWidth();        height = getHeight();    }    public void run(){    //this will terminate the thread as soon as the counter reaches whatevre value it should reach.        while(counter<MAX_CTR_VAL){            repaint();            serviceRepaints();        try{            Thread.sleep(50);        }        catch(Exception e){}        }    }            private void loadImages(){     // couter is zero at first        try{            switch(counter){            case 0:                img1 = Image.createImage("&#47;street.png"); //tile map                counter++;                break;            case 1:                img2 = Image.createImage("&#<span class="java-number">47</span>;sprite.png"</span>); <span class="java-comment">//player sprite</span><br>                counter++;<br>                <span class="java-keyword">break</span>;<br>            }<br>            <span class="java-keyword">if</span>(counter == <span class="java-number">2</span>)<br>                page = <span class="java-number">2</span>;    <span class="java-comment">// my game screen setter</span><br>         }<br>         <span class="java-keyword">catch</span> (Exception e){<br>            System.out.println(e);<br>         }<br>     }<br>    <span class="java-visibilitymodifier">public</span> <span class="java-primitives">void</span> paint(Graphics g){<br>        g.setColor(<span class="java-number">255</span>, <span class="java-number">255</span>, <span class="java-number">255</span>);<br>        g.fillRect(<span class="java-number">0</span>, <span class="java-number">0</span>, width , height);     <br>     <br>        g.setColor(<span class="java-number">255</span>, <span class="java-number">0</span>, <span class="java-number">0</span>);<br>        g.setFont(Font.getFont(<span class="java-number">64</span>, <span class="java-number">1</span>, <span class="java-number">8</span>));<br>        g.drawString(<span class="java-literal">"Loading.."</span>, width/<span class="java-number">2</span>, <span class="java-number">124</span>, Graphics.HCENTER | Graphics.TOP);<br>     <br>        g.setColor(<span class="java-number">255</span>, <span class="java-number">0</span>, <span class="java-number">0</span>);<br>        g.fillRoundRect(<span class="java-number">20</span>, <span class="java-number">140</span>, counter*k, <span class="java-number">10</span>, <span class="java-number">10</span>, <span class="java-number">10</span>);  <span class="java-comment">// k = total length of gauge/no of cases in load scrn</span><br>        g.setColor(<span class="java-number">0</span>, <span class="java-number">0</span>, <span class="java-number">0</span>);<br>        g.drawRoundRect(<span class="java-number">20</span>, <span class="java-number">140</span>, width-<span class="java-number">40</span>, <span class="java-number">10</span>, <span class="java-number">10</span>, <span class="java-number">10</span>);<br>        g.drawRoundRect(<span class="java-number">19</span>, <span class="java-number">139</span>, width-<span class="java-number">38</span>, <span class="java-number">12</span>, <span class="java-number">16</span>, <span class="java-number">16</span>);<br>    }<br>}<br></pre></div><!--ENDSCRIPT--> <br><br><!--EDIT--><span class=editedby><!--/EDIT-->[Edited by - thelegendofzaku on February 13, 2006 10:24:40 PM]<!--EDIT--></span><!--/EDIT-->
From what I have found writting J2ME is that when writting the loading portion of the application, you don't want the loading class to Render. Why is this you ask? The reason is simple, on a lot of "average" phones, they are not very good at doing certain things, one of the major ones, is loading resources. The best way to do this, is have the loading in a seperate class, so that the rendering cna be done in a different thread allowing both of them to update at the same time. If you don't, you may see the odd results, such as the phone getting a phone call, and as it resumes it may not repaint because it is still trying to load a resource. Another advantage, is you can do other things on screen, such as text that changes as while the Loading Bar is being incremented or other cool effects. Now that you have the basics, this is some more exciting stuff that you can do. As far as an IDE, I am personally not a fan of NetBeans (maybe it has something to do with the fact that I'm not a fan of Java in general and how if I leave NetBeans on for a long time it can steal 200 to 300 MB of RAM easily). I use either JCreator (there is a free version) or Textpad and use build scripts to do the actual compilations. Other then that, what you have is a good starting pointfor your loading engine. If you have any more questions feel free to ask me!

~guyaton
~guyaton

This topic is closed to new replies.

Advertisement