J2me手机游戏编程初体验
出发
学习J2me已经有一段时间了,按书上说的例子也做了无数,虽然基本理解了J2me的整体编程思想,但做游戏程序却仍然感到毫无头绪。
本想试着照扒游戏【魔塔】,反复考虑了很长时间,感觉其中复杂度较高,而且部分细节如关卡的设置、与敌人对战等程序也都没有接触过,所以决定做一个简易的推箱子游戏,有两关即可。
虽说是简单很多,但真正想要做起来的时候却无从下手;想了好久,脑袋里仍然是乱糟糟的,反正也没有思路,不如静下来,做个简单的设计吧。
设计
由于需求简易,就直接进入设计吧。^_^
首先,一定要有个主应用程序类,相信大家都应改知道;其次,不可避免,一定要有画布,为了把程序的画面呈现出来;其中,我觉得还是把地图跟画布分开,这样对地图管理比较容易,而且增加或修改地图比较方便;然后一定要有主角对吧,总要找个推箱子的人;说到箱子,也许箱子也需要管理吧。
暂时先这样,按照上面的分析画个简易的类图:
这样看起来好像简单多了吧,谁知道在添加每个类的时候还会出什么问题^_^ ,先不管它了,还有重要的事要做。
制作图片
我一向认为我自己没有什么审美观点,不过做程序总要些图片,没办法,只有映着头皮做吧,多亏前一阵学了些简单的PhotoShop处理,做起来也不是十分困难,只不过选择的图片稍微差了点,对付着用吧。
开工
所谓万事具备只欠东风,虽然我们的设计虽然简单,总可以对付着用吧^_^。
绘制背景
先抛开箱子(BoxSprite)和推箱子的人(PlayerSprite)两个类,把全部经历集中到绘制地图上(其实不过是第一幅地图)。
这其中需要先了解几个类,GameCanvas 、LayerManager和TiledLayer等几个类。我们这里主要用TiledLayer这种方法构造背景。
GameCanvas 类:GameCanvas实际上就是屏幕上一个可绘制区域。但每个GameCanvas类都有一个独立的buffer,从而不但减少了堆的使用率,也可以使用单独的堆控制程序。
LayerManager 类:这个类用来管理图像的各个层,它将按正确的位置和次序渲染所有在它控制下的土层。
TiledLayer 类:通过使用这个函数可以定义游戏背景的特定区域,并且可以重复利用它们生成一个完整的图像。
具体参造相关资料。
主程序
import javax.microedition.lcdui.*; import javax.microedition.midlet.MIDlet;
public class myBox extends MIDlet implements CommandListener { private BoxCanvas boxCanvas; protected Display display;
public void startApp() { display = Display.getDisplay(this); try{ boxCanvas = new BoxCanvas(this); boxCanvas.start();
Command exitCommand = new Command("Exit", Command.EXIT, 1); boxCanvas.addCommand(exitCommand); boxCanvas.setCommandListener(this); }catch(Exception e){ } display.setCurrent(boxCanvas); }
public Display getDisplay() { return display; }
public void pauseApp(){ }
public void destroyApp(boolean unconditional){ System.gc(); notifyDestroyed(); }
public void commandAction(Command c, Displayable s) { if (c.getCommandType() == Command.EXIT) { destroyApp(true); notifyDestroyed(); } } } |
BoxCanvas类
import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; import java.util.*;
public class BoxCanvas extends GameCanvas implements Runnable { private myBox midlet; private BoxMaps boxMaps;
private Thread gameThread = null; private LayerManager layerManager; private TiledLayer tl_ground;
private static final int MILLIS_PER_TICK = 50;
public BoxCanvas(myBox midlet) throws Exception { super(true); this.midlet = midlet;
boxMaps = new BoxMaps(); tl_ground = boxMaps.getTiled();
layerManager = new LayerManager(); layerManager.append(tl_ground); }
public void start() { gameThread = new Thread(this); gameThread.start(); }
public void stop() { gameThread = null; }
public void run() { Graphics g = getGraphics();
Thread currentThread = Thread.currentThread(); try{ while (currentThread == gameThread) { long startTime = System.currentTimeMillis(); if (isShown()) { //tick(); //input(); render(g); } long timeTake = System.currentTimeMillis() - startTime; if (timeTake < MILLIS_PER_TICK) { synchronized (this) { wait(MILLIS_PER_TICK - timeTake); } } else { currentThread.yield(); } } }catch (InterruptedException ex) { // won't be thrown } }
private void render(Graphics g) { //g.setColor(0xF8DDBD); int w = getWidth(); int h = getHeight();
int x = (w - 192) / 2; int y = (h - 192) / 2;
g.setColor(boxMaps.getGroundColor()); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(0x0000ff);
tl_ground = boxMaps.getTiled();
layerManager.paint(g,x,y); flushGraphics(); } } |
BoxMaps类
import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*;
public class BoxMaps { private static final int[][] map1 = { {0,0,0,0,1,1,1,0,0,0,0,0}, {0,0,0,0,4,0,2,0,0,0,0,0}, {0,0,0,0,4,0,2,0,0,0,0,0}, {0,0,0,0,4,0,1,1,1,1,1,2}, {0,0,0,0,4,0,0,0,0,0,0,2}, {4,1,1,1,1,0,0,0,3,3,3,2}, {4,0,0,0,0,0,0,0,2,0,0,0}, {4,3,3,3,3,3,3,0,2,0,0,0}, {0,0,0,0,0,0,4,0,2,0,0,0}, {0,0,0,0,0,0,4,0,2,0,0,0}, {0,0,0,0,0,0,4,0,2,0,0,0}, {0,0,0,0,0,0,3,3,3,0,0,0} };
private static final int TILE_WIDTH = 16; private static final int TILE_HEIGHT = 16;
private int[][] currentMap; private TiledLayer tl_BoxGround; private int groundColor;
public BoxMaps() throws Exception{ setMap(1); }
public void setMap(int level) throws Exception { Image tileImages = Image.createImage("/wall.png");
switch(level) { case 1: currentMap = map1; groundColor = 0xF8DDBE; break; default: groundColor = 0xF8DDBE; break; } tl_BoxGround = new TiledLayer(12,12,tileImages,TILE_WIDTH,TILE_HEIGHT);
for (int row=0; row<12; row++) { for (int col=0; col<12; col++) { tl_BoxGround.setCell(col,row,currentMap[row][col]); } } }
public TiledLayer getTiled() { return tl_BoxGround; }
public int getGroundColor() { return groundColor; } } |
运行一下,看看效果,哈哈,效果出来了,怎么样?比较简单吧