J2ME游戏开发教程:初级动作闯关类-《混血王子与梦幻国度》(一)

原文及资源请访问:www.yinowl.com

标题:
和我三年前写的两篇教程一样,这仍就是一篇J2ME的入门教程,只是游戏的类型变了,代码的结构也许会比之前的两个游戏要复杂一些,但算法的难度甚至不如双人扫雷来的巧妙,也正因如此,大家可以在这篇文章中了解一下这类游戏的一种结构的实现方法。关于游戏名字,我要声明和我一点没有关系,纯粹是公司的营销行为,过去几年在业内工作过的朋友一定能了解,呵呵。

我:
三年前,也就是2004年底2005年初,我在学习J2ME的过程中写了拙作两篇《J2ME-MIDP1.0小游戏入门-五子棋》和《J2ME-MIDP1.0游戏完整实现-双人扫雷》,之后进了一家当时在业内很有业绩但没有名声的SP+CP公司,《混血王子与梦幻国度》是我在那的第一个游戏,我自己的第三个游戏。游戏很简单,给了我一套图和一套关卡设计,其他的全部自己来。

文章:
其实很早就想继续写几篇游戏开发教程,总有这样那样的原因是我犹豫,一来之前还在原来公司,即使是很早的游戏也不方便写出来,二来游戏中还有美术和策划内容,这些不属于我的版权,我无权使用。现在好了,我已经离开原来公司,并且公司早已转型其他领域,不存在利益关系;至于第二点,这个游戏应该没有关系,我甚至不知道是谁,我想在教程中用,即使他看到了也无大碍吧。
这篇文章依旧采用前两篇的形式,更具结构和功能,附带解释和讲解,一点点写全所有代码。在写的过程中,我会在IDE中新建一个工程,和文章同步把代码从原有工程copy到新工程,尽量做到代码的完整且可运行。由于游戏是2005年写的,以现在的经验看,肯定会显得幼稚和落后,为了保证当时代码的想法和完整性,我就不做修改了。

正文:
结构:
代码一共有5个类文件和一堆的资源文件,根据不同IDE的不同设置,可以把资源放在代码相同目录下,或是不同目录下,只要能正确加载就可以,代码中资源都是从跟目录读取(也就是"/xxx.png")。我使用的是eclipse,并且在J2ME的设置项New Midlet Suite中勾选了Automatically Use Resources Directory in New ProjectsResources Directory我填写的是res,因此我的资源都在res目录下,但其实作用如同和代码在一个目录下一样,详细的可以查阅eclipse相关文档。另外最重要的一点是,但是首先开发的是在Moto V300机型上,所以这个代码要用模拟器跑的话,需要下载Moto的SDK,用WTK2.0的模拟器应该也能跑吧

工程目录结构
src
|-com.eshouji.theball
|-GameInfo.java
|-Spirit.java
|-TheBallCanvas.java
|-TheBallMIDlet.java
|-Util.java
res
|-0.png
|-...
|-window.png

GameInfo:是游戏的数据类,存放所有关卡数据,人物数据,图片数据,用法以后用到的时候再详细解释
Spirit:怎么说呢,类似于midp2.0的精灵类吧,人物的封装类
TheBallCanvas:游戏Canvas类,包含了所有的绘图和AI
TheBallMIDlet:当然就是MIDlet类了,作用就不用说了吧,就像没有人会不知道C/C++的main函数一样
Util:工具类,有一些常用工具函数,主要是为了积累以便可以拿到以后的项目中使用


TheBallMIDlet类:
首先是MIDlet主类TheBallMIDlet,继承自MIDlet,我们需要实现MIDlet的几个抽象方法,这几个方法系统会在游戏启动,暂停,和推出是自动调用,应此我们可以在这些方法中加入游戏的初始化,游戏暂停,退出清理资源等处理,我们的TheBallMIDlet现在应该是这样:
package com.eshouji.theball;

import javax.microedition.midlet.MIDlet;

public class TheBallMIDlet extends MIDlet {

protected void startApp(){
}
protected void pauseApp(){
}
protected void destroyApp(boolean unconditional){
}

}

TheBallCanvas类:
这是我们的游戏的核心类,包含了所有的绘图和算法,继承自Canvas类,同样我们必须实现父类的抽象方法:
package com.eshouji.theball;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

public class TheBallCanvas extends Canvas {

protected void paint(Graphics g) {
}

}

在有了Canvas类后,就可以稍微的完善一下我们的MIDlet类了,在TheBallMIDlet类中增加TheBallCanvas类的实例的声明,并且增加一个构造函数来初始化;我们还需要创建一个Display对象把我们的主Canvas画在屏幕上
TheBallMIDlet类增加:
TheBallCanvas theBallCanvas;
Display display;
public TheBallMIDlet(){
display=Display.getDisplay(this);
theBallCanvas=new TheBallCanvas(this);
}
TheBallMIDlet类的startApp方法中增加
display.setCurrent(theBallCanvas);
这样,游戏运行后,系统创建MIDlet实例,在构造方法中初始化Canvas,并调用startApp把我们的Canvas通过display画在屏幕上

线程结构
接下来我们要建立Canvas的线程结构,我们都已经了解,一个游戏其实是一个不断循环的线程,在每次循环进行逻辑的计算,并不断把新的内容绘制到屏幕上,我们让TheBallCanvas实现Runnable接口,是他成为我们的核心线程
在extends Canvas后添加implements Runnable,并且添加实现Runnable的抽象方法run()
public void run() {
}

要让这个线程跑起来,我们要给Canvas类添加一个构造函数,在构造函数中启动线程,也就是说,当MIDlet类创建Canvas时就启动了这个线程
添加类对象
Thread thread;
TheBallMIDlet theBallMIDlet;
public TheBallCanvas(TheBallMIDlet theBallMIDlet) {
this.theBallMIDlet=theBallMIDlet;
thread=new Thread(this);
thread.start();
}

来看一下我们的run函数的结构:
while(RunGame){
starttime = System.currentTimeMillis();
......
repaint();
serviceRepaints();
takentime = System.currentTimeMillis()-starttime;
if(takentime<TIME_PER_FRAME){
try{
Thread.sleep(TIME_PER_FRAME-takentime);
}catch(InterruptedException e){};
}
repaint();
serviceRepaints();
}

一个while循环,省略部分是我们以后要完善的游戏逻辑和绘制运算,在运算前后我们都记录了当前时间,如果所用的时间小于一个定值,就让游戏线程暂停(sleep)和这个定制相差的时间,也就是说我们会让每次刷新间隔的时间相同,而不会出现一会儿快一会儿慢的情况,当然,中间的运算不是时间不能超过这个定值,否则还是会变慢。整个循环用一个RunGame开关控制,用这个开关我们可以使游戏暂停和退出
同样我们要添加如下类变量:
boolean RunGame=true;
long starttime=0;
long takentime=0;
static int TIME_PER_FRAME = 30;
当然我们游戏一开始就要把RunGame开关打开,同样游戏被暂停的时候,要把游戏线程也暂停,顺便我们再完善一下MIDlet类
在startApp中添加
theBallCanvas.RunGame=true;
在pauseApp中添加
theBallCanvas.RunGame=false;
在destroyApp中添加
notifyDestroyed();

按键响应
作为核心结构,我们还差一部分,就是用户按键的响应,这是系统级的,当用户有按键操作的时候,会向调用系统函数并传递按键的键值,当然,前提是我们实现这个方法
添加方法和一些代码:
public void keyPressed(int keyCode){
if(RunGame){
TheBallCanvas.keyCode=keyCode;
TheBallCanvas.keyAction=getGameAction(keyCode);
}
else
RunGame=true;
......
}
省略部分是对响应按键的操作,我们以后慢慢完善。我们用两个变量来记录用户的按键和对应的gameaction值,同样添加声明
static int keyCode,keyAction;

未完待续.....

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭