Monday, January 17, 2011

j2me 4-way scrolling game part 2:

Part 2:
         Tile layer class

Am really writing this stuff up as i go along so don't expect a detailed comprehensive coverage.

//source code//


    import java.io.IOException;
    import javax.microedition.lcdui.Image;
    import javax.microedition.lcdui.game.TiledLayer;
    /**
    *
    * @author kim
    */
    public class levelMaps {

    int[][] mapA =
            {                       
                            { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0},
                            { 0, 4, 4, 4, 4, 4, 4, 4, 4, 0},
                            { 0, 7, 7, 7, 7, 7, 7, 7, 7, 0},
                            {10, 0, 0, 0, 0, 0, 0, 0, 0, 2},
                            {10, 0, 0, 0, 0, 0, 0, 0, 0, 3},
                            {10, 0, 0, 0, 0, 0, 0, 0, 0, 8},
                            {10, 0, 0, 0, 0, 0, 0, 0, 0, 11},
                            { 0, 6, 6, 6, 6, 6, 0, 0, 0, 10},
                            { 0, 9, 9, 9, 9, 9, 0, 0, 0, 10},
                            {12,12,12,12,10,10,10,10,10, 10},
            };

    int[][] mapB =
            {                         
                            {0,0,0,0,0,0,0,0,0,0},
                            {0,0,0,0,0,0,0,0,0,0},
                            {0,0,0,0,0,0,0,0,0,0},
                            {0,2,2,2,2,2,2,2,2,0},
                            {0,2,2,2,2,2,2,2,2,0},
                            {0,2,2,2,2,2,2,2,2,0},
                            {0,2,2,2,2,2,2,2,2,0},
                            {0,0,0,0,0,0,0,0,0,0},
                            {0,0,0,0,0,0,0,0,0,0},
                            {0,0,0,0,0,0,0,0,0,0},                           
            };

    private int rows;
    private int columns;
    private int tileWidth;
    private int tileHeight;
  
    private TiledLayer tiledLayer;
  
    boolean collisionB4Scroll;

    private int [][] selMap;

    public levelMaps(int sel) throws IOException
    {
        addMap(sel);
    }

         /*row ########
          * column#
          *            #
          *            #
          *
          */

    public void addMap(int stage) throws IOException
    {
        Image tileImg = null;

        switch(stage)
        {
            case 1:  tileImg = Image.createImage("/h1.png");
            selMap = mapA;

            rows = 10;
            columns = 10;
            tileWidth = 88;
            tileHeight = 44;
       
            break;

            case 2:  tileImg = Image.createImage("/bg.png");
            selMap = mapB;

            rows = 10;
            columns = 10;
            tileWidth = 88;
            tileHeight = 44;

            break;

            default: tileImg = Image.createImage("/h1.png");
            selMap = mapA;
        }

         tiledLayer = new TiledLayer(rows, columns, tileImg, tileWidth, tileHeight);

         for(int row = 0;row < rows; row++)
         {
              for(int column = 0;column < selMap.length;column ++)
              {
                tiledLayer.setCell(row, column, selMap[column][row]);
              }
          }
        }
          
    public TiledLayer getMap(){
        return tiledLayer;
    }

}




mapA[][] is a 10 by 10 multidimensional array that holds integers that represent the tile to be displayed from the image. the other is an array for the background. Note the only difference is the parameter taken by the addMap(int) method.
A switch determines the map array to be used which is added to a new instance of the TiledLayer. The tile Layer takes five parameters (refer to the Game API ) .
 The getMap() function returns the TileLayer and is called from the GameManager class. Also the tileImg = Image.createImage("/bg.png"), this parameter should reflect the filepath i.e if your images are in a folder names res then it should read as  "/res/bg.png".

Thats about all there is to it  so next i will cover the sprite class which entails the players and enemies.

Saturday, January 15, 2011

J2ME 4 WAY SCROLLING GAME
   Part 1
   INTRODUCTION:
Truth be said,i really never had much interest in mobile games until very recently when i had a go at  the mobile version of the call of duty game. The four-way scrolling canvas instantly caught my attention and i decided to develop something similar and by similar i mean just the four-way scrolling concept. There are tons of resources on java me programming and most importantly the GameCanvas package API out there and almost all this content is available for free online.

Getting started is no problem for anyone with prior experience in java programming. I kicked off with the usual hello word!!. The reason i posted this blog is because i could not find a good tutorial anywhere that focused on a four-way scrolling tutorial where the player character walked around in a 2d world in all directions. (I think its called 2.5d ). I f there is such a tutorial maybe i never came across it.
Anyway after lots of trial and error, i have come up with a working example where the player can walk around in all directions in the game world. I used the GameCanvas classes which makes life so much easier...i can't help but wonder why in most commercial games the developers go out of there way to develop  complex custom code to do the same job, maybe its due to performance,compatibility etc. anyway for my purposes i do not think its worth the effort.
Here are some screen shots of the work in progress.
scrolling right    




scrolling up

scrolling left



scrolling down   

I will not go into the details of how to setup the details of how to setup the j2me development environment but for a beginner,it is best to use the netbeans IDE;it has a pretty user friendly mobility pack that is straight forward to use.

Any j2me project must have the startApp(){};pauseApp(){}; and destroyApp(){};
 
Its pretty straight forward and needs no explanation.

import java.io.IOException;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.midlet.*;

/**
 * @author kimlexson
 */
public class main extends MIDlet
    implements CommandListener {

/**
 * new instance of the GameManager class sets the display to the canvas
 */
   private GameManager game_manager;

    public void startApp() {

        if(game_manager == null)
        try
        {   
             game_manager = new GameManager();
             game_manager.init();

             Command exitCommand = new Command("Exit",Command.EXIT, 0);
             game_manager.addCommand(exitCommand);
             game_manager.setCommandListener(this);
            
        }catch (IOException e) {
        System.out.println(e);
      }
         Display.getDisplay(this).setCurrent(game_manager);
       
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional)
    {
       
    }

    public void commandAction(Command cmnd, Displayable dsplbl)
    {
       if (cmnd.getCommandType() == Command.EXIT) {
      destroyApp(true);
      notifyDestroyed();
    }
    }
}

the GameManager class will implement the Runnable interface meaning that it will have a single thread that will loop continuously as long as the game is alive and it will be alternating sleeping for a few milliseconds and then runs again. It also instantiates the sprites,the tile layer and the layer manager.


import java.io.IOException;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.TiledLayer;
/**
*
* @author kim
*/
public class GameManager extends GameCanvas implements Runnable {

    private int loop = 50;
    private int width;
    private int height;
    private int speed = 3;
   
    private int offsetx,offsety;

    private boolean isAlive;
    private Thread mainThread = null;
    private LayerManager Lman;
    private TiledLayer tileLay;
    private TiledLayer tileBackGround;

    private levelMaps maps;
    private PlayaSprite pSrite;
    private Enemy eSprite;

   private int []seq_Xaxis = { 0, 1, 2, 3, 4, 5};
   private int []seq_up    = { 6, 7, 8, 9,10,11};
   private int []seq_down  = {12,13,14,15,16,17,};
   private int p1x;
   private int p1y;


    public GameManager() throws IOException
    {
            super(true);
        
            width = getWidth();
            height = getHeight();
            Lman = new LayerManager();

             maps = new levelMaps(1);
             tileLay =  maps.getMap();

             maps = new levelMaps(2);
             tileBackGround = maps.getMap();
     
            pSrite = new PlayaSprite();
            eSprite = new Enemy();

            pSrite.InitPos(width >> 1,height >> 1);
            eSprite.InitPos(400, 250);

            offsetx = pSrite.getX() - width >> 3;
            offsety = pSrite.getY() - width >> 3;

            Lman.append(pSrite);
            Lman.append(eSprite);
            Lman.append(tileLay);
            Lman.append(tileBackGround);
          

    }

    public void init(){

            isAlive = true;

            mainThread = new Thread(this);
            mainThread.start();           
    }

    public void run() {

            Graphics g = getGraphics();
            while (mainThread.isAlive())
            {
            try {
                if (isShown()) {
                    if (isAlive) {
                        controls();
                    }
                    paint(g);
                }
                Thread.sleep(loop);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
                
            }
  }


    public boolean collisionState()
    {  
         return pSrite.collidesWith(tileLay,true);
    }

    public void dead_End()
    {
        if(pSrite.collidesWith(tileLay,true))
            pSrite.setPosition(p1x,p1y);

        if(!collisionState())
        {
            p1x = pSrite.getX();
            p1y = pSrite.getY();
        }
    }

      public void set_frame_seq(int[] seq2)
      {
         
          if(!pSrite.compare_Seq(seq2))
          {
             pSrite.setFrameSequence(seq2);
             pSrite.set_current_Seq(seq2);
  
          }else
         
          pSrite.anim();    
      }

    public void controls()
    {
       int keys = getKeyStates();
            dead_End();
            //left
            if((keys & LEFT_PRESSED) != 0)
            {
               set_frame_seq(seq_Xaxis);
               pSrite.moveLeft(speed * -1);

               if(!collisionState())
               offsetx += -3;
           
            }

            //right
            if((keys & RIGHT_PRESSED) != 0)
            {
                set_frame_seq(seq_Xaxis);
               pSrite.moveRight(speed);

                if(!collisionState())
                offsetx += speed;           
            }

           //up
           if((keys & UP_PRESSED) != 0)
           {
              set_frame_seq(seq_up);
             pSrite.moveUp(speed *-1);

             if(!collisionState())
             offsety += -3;
                
           }

           //down
           if((keys & DOWN_PRESSED) != 0)
           {
                set_frame_seq(seq_down);
                pSrite.moveDown(speed);

                if(!collisionState())
                offsety += speed;
           
           } 
    }

    public void paint(Graphics g){
            g.fillRect(0, 0, width, height);
            Lman.paint(g, 0, 0);
            g.setColor(0x0024B400);
            Lman.setViewWindow(offsetx,offsety, width, height);
            flushGraphics();
    }
}

 Both the terrain objects(buildings) and the background(ground) are maintained on two separate tiled Layers which are added to one LayerManager in order to create the game world. The tile layer class is discussed more in-depth in part two.
 The Sprite class also manages the player and the enemies but am still working on the enemies to be able to collide with player and maybe throw-in some little AI so that they can chase around the player.  For the sprites, i am using the frame sequence to animate the player and this will also be discussed in subsequent parts.