Namespaces
Variants
Actions
(Difference between revisions)

Parallax Scrolling in Java ME

Jump to: navigation, search
(Reflexus@ig.com.br - Parallax Scrolling in Java ME)
 
m (Hamishwillee - Add link to definition of Parallax scrolling)
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:Java ME]]
+
[[Category:Java ME]][[Category:Series 40]][[Category:Graphics]][[Category:General Programming]]
Parallax Scrolling in Java ME.
+
{{ArticleMetaData
 +
|sourcecode= <!-- Link to example source code e.g. [[Media:The Code Example ZIP.zip]] -->
 +
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) -->
 +
|devices= <!-- Devices tested against - e.g. ''devices=Nokia 6131 NFC, Nokia C7-00'') -->
 +
|sdk= <!-- SDK(s) built and tested against (e.g. [http://linktosdkdownload/ Nokia Qt SDK 1.1]) -->
 +
|platform= <!-- Compatible platforms - e.g. Symbian^1 and later, Qt 4.6 and later -->
 +
|devicecompatability= <!-- Compatible devices e.g.: All* (must have internal GPS) -->
 +
|dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 -->
 +
|signing=<!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer -->
 +
|capabilities=<!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
 +
|keywords= <!-- APIs, classes and methods (e.g. QSystemScreenSaver, QList, CBase -->
 +
|id= <!-- Article Id (Knowledge base articles only) -->
 +
|language=<!-- Language category code for non-English topics - e.g. Lang-Chinese -->
 +
|review-by=<!-- After re-review: [[User:username]] -->
 +
|review-timestamp=<!-- After re-review: YYYYMMDD -->
 +
|update-by=<!-- After significant update: [[User:username]]-->
 +
|update-timestamp=<!-- After significant update: YYYYMMDD -->
 +
|creationdate=20110622
 +
|author=[[User:Reflexus@ig.com.br]]
 +
}}
  
This is what i use im my game. Guess Which game?
+
{{Abstract| This article illustrates how to use [http://en.wikipedia.org/wiki/Parallax_scrolling parallex scrolling] in Java ME.}}
I decided to release the code 'cause i couldn't find it in
+
==Introduction==
any web page. The net is an open book (or university) and
+
Parallax Scrolling is something that I use in my game. I decided to release the code because I thought it could be useful to somebody.
i've taken too much from it....now it's my time to contribute...
+
I still want to give back to the community for helping me so much
+
when I was a novice, and as a result I decided to write this tutorial.  
+
  
It also demonstrate how to:
+
This article also demonstrates how to:
* pause/unpause an app (RIGHT SOFT KEY / incoming phone call);
+
* pause/unpause an app (RIGHT SOFT KEY / incoming phone call)
* get high frames por second (fps);
+
* get high frames por second (fps)
* get randomNumbers / randomBoolean;
+
* get randomNumbers / randomBoolean
* use custom fonts (bitmap fonts);
+
* use custom fonts (bitmap fonts)
 
* use LayerManager/TiledLayer.
 
* use LayerManager/TiledLayer.
  
Go to my projects and grab JavaMEParallaxScrolling project
+
Go to my projects and grab [http://projects.developer.nokia.com/Parallax_Scrolling JavaMEParallaxScrolling] project
 
(with all resources and full source code).
 
(with all resources and full source code).
You can easily open it in NetBeans 6.9
+
You can easily import it in NetBeans 6.9
 
+
 
+
Please don't forget to check my game projects (need feedback):
+
Queops, LunarPatrol & X-Rally.
+
Thank you.
+
 
+
Another yet is to come....maybe a new version of Space Impact...
+
 
+
 
+
Brought to you by George Roberto Peres (JavaMan)
+
                  reflexus@ig.com.br
+
 
+
 
+
/**********************************************************************************************/
+
 
+
  
 +
== Code Snippet ==
 +
<code java>
 
import java.io.IOException;
 
import java.io.IOException;
 
import javax.microedition.lcdui.Display;
 
import javax.microedition.lcdui.Display;
 
import javax.microedition.midlet.MIDlet;
 
import javax.microedition.midlet.MIDlet;
 
import javax.microedition.midlet.MIDletStateChangeException;
 
import javax.microedition.midlet.MIDletStateChangeException;
 
 
  
 
public class Main extends MIDlet {
 
public class Main extends MIDlet {
Line 47: Line 48:
 
   private Display display;
 
   private Display display;
  
 
+
   public Main() { }
 
+
   public Main() {
+
    //
+
  }
+
 
+
 
+
  
 
   public void startApp() {
 
   public void startApp() {
 
     if (canvas==null) canvas = new ParallaxScrollingCanvas();
 
     if (canvas==null) canvas = new ParallaxScrollingCanvas();
 
     display = Display.getDisplay(this);
 
     display = Display.getDisplay(this);
    //Display.getDisplay(this).setCurrent(canvas);
+
 
 
     try {
 
     try {
 
       canvas.init();
 
       canvas.init();
Line 67: Line 62:
 
   }
 
   }
  
 
+
   public void pauseApp() { }
 
+
   public void pauseApp() {
+
    //
+
  }
+
 
+
 
+
  
 
   public void destroyApp(boolean destroy) throws MIDletStateChangeException {
 
   public void destroyApp(boolean destroy) throws MIDletStateChangeException {
Line 81: Line 70:
 
     notifyDestroyed();
 
     notifyDestroyed();
 
   }
 
   }
 
 
 
 
 
}
 
}
 +
</code>
  
 
+
<code java>
 
+
/**********************************************************************************************/
+
 
+
 
+
 
+
 
/*
 
/*
 
  * This class demonstrate how to use LayerManager/TiledLayer.
 
  * This class demonstrate how to use LayerManager/TiledLayer.
Line 103: Line 84:
 
import javax.microedition.lcdui.game.LayerManager;
 
import javax.microedition.lcdui.game.LayerManager;
 
import javax.microedition.lcdui.game.TiledLayer;
 
import javax.microedition.lcdui.game.TiledLayer;
 
  
 
/**
 
/**
Line 114: Line 94:
 
   private Image back, front, solo;
 
   private Image back, front, solo;
 
   protected TiledLayer layerBack, layerFront, layerSolo;
 
   protected TiledLayer layerBack, layerFront, layerSolo;
   // fonte
+
 
   private Image imgFont;  // imagem da fonte.png
+
   // font
 +
   private Image imgFont;  // font image font.png
 
   protected int charLarg, charAlt;
 
   protected int charLarg, charAlt;
 
 
  
 
   protected Design() {
 
   protected Design() {
Line 129: Line 108:
 
   }
 
   }
  
 
+
   // the order is important. The last added represents the most deep layer
 
+
   // ordem e' importante. o ultimo a ser anexado representa a camada mais profunda
+
 
   protected void updateLayerManager(LayerManager lm) throws IOException {
 
   protected void updateLayerManager(LayerManager lm) throws IOException {
 
     lm.append(layerSolo);
 
     lm.append(layerSolo);
Line 137: Line 114:
 
     lm.append(layerBack);
 
     lm.append(layerBack);
 
   }
 
   }
 
 
  
 
   protected TiledLayer defineCenario(TiledLayer layer, Image image, int rows) throws IOException {
 
   protected TiledLayer defineCenario(TiledLayer layer, Image image, int rows) throws IOException {
Line 154: Line 129:
 
     return layer;
 
     return layer;
 
   }
 
   }
 
 
  
 
   private Image getBack() throws IOException {
 
   private Image getBack() throws IOException {
Line 163: Line 136:
 
     return back;
 
     return back;
 
   }
 
   }
 
 
  
 
   private Image getFront() throws IOException {
 
   private Image getFront() throws IOException {
Line 172: Line 143:
 
     return front;
 
     return front;
 
   }
 
   }
 
 
  
 
   private Image getSolo() throws IOException {
 
   private Image getSolo() throws IOException {
Line 181: Line 150:
 
     return solo;
 
     return solo;
 
   }
 
   }
 
 
  
 
   protected Image getFont() {
 
   protected Image getFont() {
Line 194: Line 161:
 
     return imgFont;
 
     return imgFont;
 
   }
 
   }
 
 
 
 
 
}
 
}
 +
</code>
  
 
+
<code java>
 
+
/**********************************************************************************************/
+
 
+
 
+
 
+
 
/*
 
/*
 
  * This class demonstrate how to get randomNumber/randBoolean.
 
  * This class demonstrate how to get randomNumber/randBoolean.
Line 214: Line 173:
 
import java.util.Random;
 
import java.util.Random;
 
import javax.microedition.lcdui.Graphics;
 
import javax.microedition.lcdui.Graphics;
 
  
 
public final class Tools {
 
public final class Tools {
  
 +
  private static final Random RAND = new Random();
  
  private static final Random RAND = new Random();
 
  //static { RAND = new Random(); }
 
 
   protected static final int GRAPHICS_TOP_LEFT = Graphics.LEFT | Graphics.TOP;
 
   protected static final int GRAPHICS_TOP_LEFT = Graphics.LEFT | Graphics.TOP;
   // Dimensoes da tela Game Canvas
+
 
   protected static final int LARG = 240;   // largura da tela (x)
+
   // Screen size Game Canvas
   protected static final int ALT = 320;   // altura da tela (y)
+
   protected static final int LARG = 240;// screen width (x)
   protected static final int Y = 200;  // altura da canvas principal game
+
   protected static final int ALT = 320; // screen height (y)
   protected static final boolean TELA_CHEIA = true;   // tela cheia (full screen)
+
   protected static final int Y = 200;  // the height of the main canvas game
   // codigos dos softkey variam dependendo do modelo do celular
+
   protected static final boolean TELA_CHEIA = true; // fullscreen
   // -6 e -7 sao valores validos para telefones Nokia. Consultar para outros modelos.
+
 
 +
   // each manufacture have its own softkey code
 +
   // -6 and -7 are the correct values for the Nokia Devices
 
   protected static final int LEFT_SOFTKEY_CODE = -6;
 
   protected static final int LEFT_SOFTKEY_CODE = -6;
 
   protected static final int RIGHT_SOFTKEY_CODE = -7;
 
   protected static final int RIGHT_SOFTKEY_CODE = -7;
  
 
+
   /*********************************************************************************
   /****************************************************************************
+
   * Random number generator                                                      *
   * gerador de numero aleatorio inteiro                                      *
+
   * @param max the generated number is greater or equals to zero or less than max *
   * @param max numero gerado e' maior ou igual a zero e menor que max       *
+
   * @return  r, a pseudo-random number                                            *
   * @return  r, um numero pseudo-randomico                                  *
+
   *********************************************************************************/
   ****************************************************************************/
+
 
   protected static int randomNumber(int max) {
 
   protected static int randomNumber(int max) {
     return Math.abs(RAND.nextInt() % max);  // valor absoluto de -(max-1) ate' max-1
+
     return Math.abs(RAND.nextInt() % max);  // abs value from -(max-1) to max-1
 
   }
 
   }
  
 
   /****************************************************************************
 
   /****************************************************************************
   * gerador de booleano aleatorio                                            *
+
   * boolean random number generator                                          *
   * @return boolean                                                         *
+
   * @return boolean                                                         *
 
   ****************************************************************************/
 
   ****************************************************************************/
 
   protected static boolean randBoolean() {
 
   protected static boolean randBoolean() {
 
     return (randomNumber(2)==1);
 
     return (randomNumber(2)==1);
 
   }
 
   }
 
 
  /*// numero randomico inteiro entre min e max
 
  protected static int getRand(int min, int max) {
 
    return (Math.abs(RAND.nextInt()) % (max - min)) + min;
 
  }*/
 
 
 
 
 
}
 
}
 +
</code>
  
 
+
<code java>
 
+
/**********************************************************************************************/
+
 
+
 
+
 
+
 
/*
 
/*
 
  * This is a simple ParallaxScrolling example.
 
  * This is a simple ParallaxScrolling example.
Line 277: Line 222:
  
 
import java.io.IOException;
 
import java.io.IOException;
//import javax.microedition.lcdui.Font;
 
 
import javax.microedition.lcdui.Graphics;
 
import javax.microedition.lcdui.Graphics;
 
import javax.microedition.lcdui.game.GameCanvas;
 
import javax.microedition.lcdui.game.GameCanvas;
Line 283: Line 227:
  
 
/**
 
/**
  * @author George Roberto Peres
+
  * @author George Roberto Peres
 
  * @version 1.0
 
  * @version 1.0
 
  */
 
  */
  
 
public class ParallaxScrollingCanvas extends GameCanvas implements Runnable {
 
public class ParallaxScrollingCanvas extends GameCanvas implements Runnable {
 
  
 
   private final Graphics g = getGraphics();
 
   private final Graphics g = getGraphics();
Line 298: Line 241:
 
   private boolean pausa;
 
   private boolean pausa;
 
   private byte cont;  // timing
 
   private byte cont;  // timing
   private int a;  // auxiliar geral
+
   private int a;  // general helper
 
   private boolean isRunning;
 
   private boolean isRunning;
 
   private boolean showFPS = true;
 
   private boolean showFPS = true;
   // ciclos = frames por segundo mostrado na tela
+
   // frames per second shown on the screen
 
   private int fps;
 
   private int fps;
 
   private int cyclesThisSecond;
 
   private int cyclesThisSecond;
 
   private long lastFPSTime;
 
   private long lastFPSTime;
  
 
+
   // overwrite the javax.microedition.lcdui.Canvas method
 
+
   // sobrescreve o metodo de javax.microedition.lcdui.Canvas
+
 
   public void keyPressed(int keyCode) {
 
   public void keyPressed(int keyCode) {
 
     if (keyCode==Tools.RIGHT_SOFTKEY_CODE) {
 
     if (keyCode==Tools.RIGHT_SOFTKEY_CODE) {
Line 319: Line 260:
 
     else
 
     else
 
     if (keyCode == this.KEY_NUM0) {
 
     if (keyCode == this.KEY_NUM0) {
       showFPS = !showFPS;   // inverte boolean
+
       showFPS = !showFPS;
 
     }
 
     }
 
   }
 
   }
 
  
 
   /** Creates a new instance of theCanvas */
 
   /** Creates a new instance of theCanvas */
Line 328: Line 268:
 
     super(true);
 
     super(true);
 
     setFullScreenMode(Tools.TELA_CHEIA);
 
     setFullScreenMode(Tools.TELA_CHEIA);
    //g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL));
 
 
     design = new Design();
 
     design = new Design();
 
     g.setColor(0,0,0);
 
     g.setColor(0,0,0);
 
     g.fillRect(0, 0, getWidth(), getHeight());
 
     g.fillRect(0, 0, getWidth(), getHeight());
 
   }
 
   }
 
 
  
 
   protected void init() throws IOException {
 
   protected void init() throws IOException {
     // gerenciador de camadas
+
     // layer manager
 
     lm = new LayerManager();
 
     lm = new LayerManager();
 
     design.updateLayerManager(lm);
 
     design.updateLayerManager(lm);
Line 343: Line 280:
 
     design.layerFront.setPosition(0, 80);
 
     design.layerFront.setPosition(0, 80);
 
     design.layerSolo.setPosition(0, 140);
 
     design.layerSolo.setPosition(0, 140);
    //System.out.println("lm size = "+lm.getSize());
 
 
   }
 
   }
 
 
  
 
   public void start() {
 
   public void start() {
 
     isRunning = true;
 
     isRunning = true;
 
     t = new Thread(this);
 
     t = new Thread(this);
    //t.setPriority(Thread.MAX_PRIORITY);
 
 
     t.start();
 
     t.start();
 
   }
 
   }
 
 
  
 
   public void stop() {
 
   public void stop() {
Line 361: Line 292:
 
     t = null;
 
     t = null;
 
   }
 
   }
 
 
  
 
   private void tarefas() {
 
   private void tarefas() {
     // cenario do fundo. move mais devagar
+
     // background scene. slower move
 
     if (cont%5==0) {
 
     if (cont%5==0) {
 
       design.layerBack.move(-1, 0);
 
       design.layerBack.move(-1, 0);
       // empacota para repetir os mesmos graficos novamente
+
       // pack to repeat the same graphics again
 
       if (Math.abs(design.layerBack.getX())>255) design.layerBack.setPosition(0, 56);
 
       if (Math.abs(design.layerBack.getX())>255) design.layerBack.setPosition(0, 56);
 
     }
 
     }
     // cenario da frente. move mais depressa
+
 
 +
     // foreground scene. fastest move
 
     if (cont%3==0) {
 
     if (cont%3==0) {
 
       design.layerFront.move(-1, 0);
 
       design.layerFront.move(-1, 0);
      // empacota para repetir os mesmos graficos novamente
 
 
       if (Math.abs(design.layerFront.getX())>255) design.layerFront.setPosition(0, 80);
 
       if (Math.abs(design.layerFront.getX())>255) design.layerFront.setPosition(0, 80);
 
     }
 
     }
     // move layerSolo
+
 
 +
     // moves the layerSolo
 
     design.layerSolo.move(-1, 0);
 
     design.layerSolo.move(-1, 0);
    // empacota para repetir os mesmos graficos novamente
 
 
     if (Math.abs(design.layerSolo.getX())>255) design.layerSolo.setPosition(0, 140);
 
     if (Math.abs(design.layerSolo.getX())>255) design.layerSolo.setPosition(0, 140);
 
   }
 
   }
 
 
  
 
   private void renderiza() {
 
   private void renderiza() {
Line 389: Line 316:
 
     g.setColor(0, 0, 0);
 
     g.setColor(0, 0, 0);
 
     g.fillRect(0, 0, Tools.LARG, Tools.Y);
 
     g.fillRect(0, 0, Tools.LARG, Tools.Y);
     lm.paint(g, 0, 0);  // desenha layer manager
+
     lm.paint(g, 0, 0);  // draws. layer manager
 
     if (showFPS) {
 
     if (showFPS) {
 
       drawString(FPS, 0, 0);
 
       drawString(FPS, 0, 0);
Line 395: Line 322:
 
     }
 
     }
 
     drawScoreInt(Math.abs(design.layerSolo.getX()), 3, 120, 0);
 
     drawScoreInt(Math.abs(design.layerSolo.getX()), 3, 120, 0);
     flushGraphics(0, 0, Tools.LARG, Tools.Y);  // descarrega graficos
+
     flushGraphics(0, 0, Tools.LARG, Tools.Y);  // unload graphics
 
   }
 
   }
  
 
+
   // draws a character based in the ASCII code table
   // desenha caracter de acordo com o codigo da tabela ASCII
+
   // helpful to add customized special characters
   // util para acrescentarmos caracteres especiais customizados
+
 
   private void drawCharASCII(int ASCII, int x, int y) {
 
   private void drawCharASCII(int ASCII, int x, int y) {
     // caractere espaco ou nao imprimivel ou o caractere>255 nao sao desenhados
+
     // the space character and 'not printable' or with ASCII code  > 255 are drawn
 
     if (ASCII < 33  ||  ASCII > 255) return;
 
     if (ASCII < 33  ||  ASCII > 255) return;
     g.clipRect(x, y, design.charLarg, design.charAlt);   // altera clip pra tamanho do caractere
+
     g.clipRect(x, y, design.charLarg, design.charAlt); // change the clip area to character size
     // desenha o caractere dentro do retangulo. (cIndex - 32) * charLarg = posicao do caractere
+
     // draw the character inside the rectangle. (cIndex - 32) * charLarg = the character position
 
     g.drawImage(design.getFont(), x - ((ASCII - 32) * design.charLarg), y, Tools.GRAPHICS_TOP_LEFT);
 
     g.drawImage(design.getFont(), x - ((ASCII - 32) * design.charLarg), y, Tools.GRAPHICS_TOP_LEFT);
     g.setClip(0, 0, Tools.LARG, Tools.ALT);   // reset o clip - full screen, ou seja, volta o normal
+
     g.setClip(0, 0, Tools.LARG, Tools.ALT); // reset the clip to back to fullscreen (normal clip size)
 
   }
 
   }
  
 +
  private void drawString(byte []s, int x, int y) {
 +
    int cx = x; // start position
  
 
+
     // loop among all the string character
  private void drawString(byte []s, int x, int y) {
+
    int cx = x;  // posicao inicial
+
     // loop atraves de todos os caracteres na string
+
 
     for (a = 0; a < s.length; a++) {
 
     for (a = 0; a < s.length; a++) {
 
       drawCharASCII(s[a], cx, y);
 
       drawCharASCII(s[a], cx, y);
       cx += design.charLarg;   // va para a proxima posicao para desenhar
+
       cx += design.charLarg; // go to the next position to draw
 
     }
 
     }
 
   }
 
   }
  
  
   // desenha score int em x,y (ASCII de 48~57).  ex: 000777 (6 digitos)
+
   // draw the score int at x,y (ASCII de 48~57).  ex: 000777 (6 digits)
 
   private void drawScoreInt(int score, int digitos, int x, int y) {
 
   private void drawScoreInt(int score, int digitos, int x, int y) {
 
     if (digitos<1 || digitos>8) return;
 
     if (digitos<1 || digitos>8) return;
 
     int d = 1;
 
     int d = 1;
 
     for (a=1; a<digitos; a++)  d *= 10;
 
     for (a=1; a<digitos; a++)  d *= 10;
     a = x;  // posicao inicial
+
     a = x;  // start position
 
     for (int i=0; i<digitos; i++) {
 
     for (int i=0; i<digitos; i++) {
       drawCharASCII(score/d + 48, a, y);  // +48 pra coincidir com tabela ASCII
+
       drawCharASCII(score/d + 48, a, y);  // +48 to match the ASCII table
       a += design.charLarg;   // va para a proxima posicao para desenhar
+
       a += design.charLarg;  
 
       score -= d*(score/d);
 
       score -= d*(score/d);
 
       d /= 10;
 
       d /= 10;
 
     }
 
     }
 
   }
 
   }
 
 
  
 
   public void hideNotify() {
 
   public void hideNotify() {
Line 442: Line 365:
 
   }
 
   }
  
 
+
   public void showNotify() { }
  // nada e' feito, porque despausa e' feito manualmente
+
   public void showNotify() {
+
    //
+
  }
+
 
+
 
+
  
 
   protected void pausa() {
 
   protected void pausa() {
Line 457: Line 374:
 
             design.charLarg*5, design.charAlt);
 
             design.charLarg*5, design.charAlt);
 
   }
 
   }
 
 
  
 
   protected void resume() {
 
   protected void resume() {
Line 464: Line 379:
 
     pausa = false;
 
     pausa = false;
 
   }
 
   }
 
 
  
 
   public void run() {
 
   public void run() {
 
     while(isRunning) {
 
     while(isRunning) {
       // metodo pra conseguir uma medida do FPS mostrado na tela
+
       // calculate the FPS
 
       if (System.currentTimeMillis() - lastFPSTime > 1000) {
 
       if (System.currentTimeMillis() - lastFPSTime > 1000) {
 
         lastFPSTime = System.currentTimeMillis();
 
         lastFPSTime = System.currentTimeMillis();
Line 479: Line 392:
 
       cont++;
 
       cont++;
 
       if (cont==60) cont=0;
 
       if (cont==60) cont=0;
      //
 
 
       tarefas();
 
       tarefas();
 
       renderiza();
 
       renderiza();
       // dorme um pouco
+
       // sleep a little
 
       try { Thread.sleep(0); }
 
       try { Thread.sleep(0); }
 
       catch (InterruptedException e) { }
 
       catch (InterruptedException e) { }
 
     }
 
     }
 
   }
 
   }
 
 
 
 
 
}
 
}
 
+
</code>
 
+
/**********************************************************************************************/
+

Latest revision as of 09:32, 20 July 2012

SignpostIcon Palette 52.png
Article Metadata

Article
Created: reflexus@ig.com.br (22 Jun 2011)
Last edited: hamishwillee (20 Jul 2012)

This article illustrates how to use parallex scrolling in Java ME.

Introduction

Parallax Scrolling is something that I use in my game. I decided to release the code because I thought it could be useful to somebody.

This article also demonstrates how to:

  • pause/unpause an app (RIGHT SOFT KEY / incoming phone call)
  • get high frames por second (fps)
  • get randomNumbers / randomBoolean
  • use custom fonts (bitmap fonts)
  • use LayerManager/TiledLayer.

Go to my projects and grab JavaMEParallaxScrolling project (with all resources and full source code). You can easily import it in NetBeans 6.9

Code Snippet

import java.io.IOException;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
 
public class Main extends MIDlet {
 
private ParallaxScrollingCanvas canvas;
private Display display;
 
public Main() { }
 
public void startApp() {
if (canvas==null) canvas = new ParallaxScrollingCanvas();
display = Display.getDisplay(this);
 
try {
canvas.init();
canvas.start();
}
catch (IOException e) { }
display.setCurrent(canvas);
}
 
public void pauseApp() { }
 
public void destroyApp(boolean destroy) throws MIDletStateChangeException {
display = null;
if (canvas!=null) canvas.stop();
System.gc();
notifyDestroyed();
}
}
/*
* This class demonstrate how to use LayerManager/TiledLayer.
* by George Roberto Peres
* reflexus@ig.com.br
*/

 
import java.io.IOException;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.TiledLayer;
 
/**
*
* @author George Roberto Peres
*/

public final class Design {
 
// Tiled Layers
private Image back, front, solo;
protected TiledLayer layerBack, layerFront, layerSolo;
 
// font
private Image imgFont; // font image font.png
protected int charLarg, charAlt;
 
protected Design() {
try {
layerBack = defineCenario(layerBack, getBack(), 4);
layerFront = defineCenario(layerFront, getFront(), 4);
layerSolo = defineCenario(layerSolo, getSolo(), 2);
}
catch (IOException ex) { }
}
 
// the order is important. The last added represents the most deep layer
protected void updateLayerManager(LayerManager lm) throws IOException {
lm.append(layerSolo);
lm.append(layerFront);
lm.append(layerBack);
}
 
protected TiledLayer defineCenario(TiledLayer layer, Image image, int rows) throws IOException {
short c=1, l=0;
layer = new TiledLayer(32, rows, image, 16, 16);
for (byte lin=0; lin<rows; lin++) {
for (byte col=0; col<32; col++) {
layer.setCell(col, lin, c);
c++;
if ((c-1)%(l+16)==0) c = (byte)(l+1);
}
l+=16;
c+=16;
}
return layer;
}
 
private Image getBack() throws IOException {
if (back == null) {
back = Image.createImage("/back.png");
}
return back;
}
 
private Image getFront() throws IOException {
if (front == null) {
front = Image.createImage("/front.png");
}
return front;
}
 
private Image getSolo() throws IOException {
if (solo == null) {
solo = Image.createImage("/solo.png");
}
return solo;
}
 
protected Image getFont() {
if (imgFont == null)
try {
imgFont = Image.createImage("/fonts.png");
charLarg = imgFont.getWidth() / 96; //9
charAlt = imgFont.getHeight(); //12
}
catch (IOException e) { }
return imgFont;
}
}
/*
* This class demonstrate how to get randomNumber/randBoolean.
* brought to you by George Roberto Peres
* reflexus@ig.com.br
*/

 
import java.util.Random;
import javax.microedition.lcdui.Graphics;
 
public final class Tools {
 
private static final Random RAND = new Random();
 
protected static final int GRAPHICS_TOP_LEFT = Graphics.LEFT | Graphics.TOP;
 
// Screen size Game Canvas
protected static final int LARG = 240;// screen width (x)
protected static final int ALT = 320; // screen height (y)
protected static final int Y = 200; // the height of the main canvas game
protected static final boolean TELA_CHEIA = true; // fullscreen
 
// each manufacture have its own softkey code
// -6 and -7 are the correct values for the Nokia Devices
protected static final int LEFT_SOFTKEY_CODE = -6;
protected static final int RIGHT_SOFTKEY_CODE = -7;
 
/*********************************************************************************
* Random number generator *
* @param max the generated number is greater or equals to zero or less than max *
* @return r, a pseudo-random number *
*********************************************************************************/

protected static int randomNumber(int max) {
return Math.abs(RAND.nextInt() % max); // abs value from -(max-1) to max-1
}
 
/****************************************************************************
* boolean random number generator *
* @return boolean *
****************************************************************************/

protected static boolean randBoolean() {
return (randomNumber(2)==1);
}
}
/*
* This is a simple ParallaxScrolling example.
* It also demonstrate how to: pause/unpause an app (RIGHT SOFT KEY / phone call);
* use custom fonts; get high frames por second (fps): smaller painted screen area,
* no threads (only canvas thread, of course), no timers, no synchronized.
* The code presented here is easy to understand (clean code).
* brought to you by George Roberto Peres
* reflexus@ig.com.br
*/

 
import java.io.IOException;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.LayerManager;
 
/**
* @author George Roberto Peres
* @version 1.0
*/

 
public class ParallaxScrollingCanvas extends GameCanvas implements Runnable {
 
private final Graphics g = getGraphics();
private LayerManager lm;
private Thread t;
private Design design;
private static final byte[] PAUSE = { 80, 65, 85, 83, 69 };
private static final byte[] FPS = { 70, 80, 83, 58 };
private boolean pausa;
private byte cont; // timing
private int a; // general helper
private boolean isRunning;
private boolean showFPS = true;
// frames per second shown on the screen
private int fps;
private int cyclesThisSecond;
private long lastFPSTime;
 
// overwrite the javax.microedition.lcdui.Canvas method
public void keyPressed(int keyCode) {
if (keyCode==Tools.RIGHT_SOFTKEY_CODE) {
if (!pausa) pausa(); else resume();
}
else
if (keyCode==Tools.LEFT_SOFTKEY_CODE) {
if (pausa) resume();
}
else
if (keyCode == this.KEY_NUM0) {
showFPS = !showFPS;
}
}
 
/** Creates a new instance of theCanvas */
public ParallaxScrollingCanvas() {
super(true);
setFullScreenMode(Tools.TELA_CHEIA);
design = new Design();
g.setColor(0,0,0);
g.fillRect(0, 0, getWidth(), getHeight());
}
 
protected void init() throws IOException {
// layer manager
lm = new LayerManager();
design.updateLayerManager(lm);
design.layerBack.setPosition(0, 56);
design.layerFront.setPosition(0, 80);
design.layerSolo.setPosition(0, 140);
}
 
public void start() {
isRunning = true;
t = new Thread(this);
t.start();
}
 
public void stop() {
isRunning = false;
t = null;
}
 
private void tarefas() {
// background scene. slower move
if (cont%5==0) {
design.layerBack.move(-1, 0);
// pack to repeat the same graphics again
if (Math.abs(design.layerBack.getX())>255) design.layerBack.setPosition(0, 56);
}
 
// foreground scene. fastest move
if (cont%3==0) {
design.layerFront.move(-1, 0);
if (Math.abs(design.layerFront.getX())>255) design.layerFront.setPosition(0, 80);
}
 
// moves the layerSolo
design.layerSolo.move(-1, 0);
if (Math.abs(design.layerSolo.getX())>255) design.layerSolo.setPosition(0, 140);
}
 
private void renderiza() {
// background
g.setColor(0, 0, 0);
g.fillRect(0, 0, Tools.LARG, Tools.Y);
lm.paint(g, 0, 0); // draws. layer manager
if (showFPS) {
drawString(FPS, 0, 0);
drawScoreInt(fps, 2, design.charLarg*4, 0);
}
drawScoreInt(Math.abs(design.layerSolo.getX()), 3, 120, 0);
flushGraphics(0, 0, Tools.LARG, Tools.Y); // unload graphics
}
 
// draws a character based in the ASCII code table
// helpful to add customized special characters
private void drawCharASCII(int ASCII, int x, int y) {
// the space character and 'not printable' or with ASCII code > 255 are drawn
if (ASCII < 33 || ASCII > 255) return;
g.clipRect(x, y, design.charLarg, design.charAlt); // change the clip area to character size
// draw the character inside the rectangle. (cIndex - 32) * charLarg = the character position
g.drawImage(design.getFont(), x - ((ASCII - 32) * design.charLarg), y, Tools.GRAPHICS_TOP_LEFT);
g.setClip(0, 0, Tools.LARG, Tools.ALT); // reset the clip to back to fullscreen (normal clip size)
}
 
private void drawString(byte []s, int x, int y) {
int cx = x; // start position
 
// loop among all the string character
for (a = 0; a < s.length; a++) {
drawCharASCII(s[a], cx, y);
cx += design.charLarg; // go to the next position to draw
}
}
 
 
// draw the score int at x,y (ASCII de 48~57). ex: 000777 (6 digits)
private void drawScoreInt(int score, int digitos, int x, int y) {
if (digitos<1 || digitos>8) return;
int d = 1;
for (a=1; a<digitos; a++) d *= 10;
a = x; // start position
for (int i=0; i<digitos; i++) {
drawCharASCII(score/d + 48, a, y); // +48 to match the ASCII table
a += design.charLarg;
score -= d*(score/d);
d /= 10;
}
}
 
public void hideNotify() {
if (!pausa) pausa();
}
 
public void showNotify() { }
 
protected void pausa() {
pausa = true;
stop();
drawString(PAUSE, Tools.LARG/2 - (design.charLarg*5)/2, Tools.Y/2 - design.charAlt/2);
flushGraphics(Tools.LARG/2 - (design.charLarg*5)/2, Tools.Y/2 - design.charAlt/2,
design.charLarg*5, design.charAlt);
}
 
protected void resume() {
start();
pausa = false;
}
 
public void run() {
while(isRunning) {
// calculate the FPS
if (System.currentTimeMillis() - lastFPSTime > 1000) {
lastFPSTime = System.currentTimeMillis();
fps = cyclesThisSecond;
cyclesThisSecond = 0;
} else
cyclesThisSecond++;
// timing base 60. why? it divides by 1,2,3,4,5,6,10,12,15,20,30
cont++;
if (cont==60) cont=0;
tarefas();
renderiza();
// sleep a little
try { Thread.sleep(0); }
catch (InterruptedException e) { }
}
}
}
This page was last modified on 20 July 2012, at 09:32.
180 page views in the last 30 days.
Nokia Developer aims to help you create apps and publish them so you can connect with users around the world.

京ICP备05048969号  © Copyright Nokia 2013 All rights reserved