游戏引擎的结构很多,不过基本上都是在一个游戏主循环内实现。程序里面的主循环包含了程序框架的最主要的结构体。J2me的程序一般都包含两个class文件,一个是MIDlet,一个是Displayable。一般我都是把游戏的主要代码放在Displayable这个类里面。这个类是基于事件驱动的程序,有三个主要相应函数
voidpaint(Graphicsg),voidkeyPressed(intkeyCode),voidkeyReleased(intkeyCode)。
1.使用Runnable和创建线程的主循环
一般主体的做法就是让Displayable这个类实现Runnable这个接口,然后在其构造函数中创建一个线程,启动其run()函数,而run函数里面就包含了游戏的主循环。下面是我在仙剑里面的片断代码。
publicclassGameMIDletextendsMIDlet{
staticGameMIDletinstance;
Displaydisplay;
GameDisplayabledisplayable=null;
publicGameMIDlet(){
instance=this;
display=Display.getDisplay(this);
displayable=newGameDisplayable();
}
publicvoidstartApp(){
display.setCurrent(displayable);
}
publicvoidpauseApp(){
}
publicvoiddestroyApp(booleanunconditional){
displayable.running=false;
}
publicstaticvoidquitApp(){
instance.destroyApp(true);
instance.notifyDestroyed();
instance=null;
}
}
publicclassGameDisplayableextendsFullCanvasimplementsRunnable{
/**主控制线程*/
ThreadMainThread=null;
/**游戏时钟间隔毫秒为单位*/
publicstaticlongtimeinterval=20;
publicstaticbooleanIsstable=true;
/*用于游戏时钟的变量*/
publicstaticlongtimeold=0;
publicstaticlongtimenow=0;
publiclonginterval=0;
publicstaticlongframes_per_second=0;
intcount=0;
longsecond=0;
publicstaticbooleanrunning=true;
publicGameDisplayable(){
//开始主线程
ThreadMainThread=newThread(this);
MainThread.start();
}
publicvoidrun(){
while(running){
timenow=System.currentTimeMillis();
interval=timenow-timeold;
if(interval>=timeinterval){
timeold=timenow;
Game_Process();
if(second!=(System.currentTimeMillis()/1000)){
second=System.currentTimeMillis()/1000;
frames_per_second=count;
count=1;
}
else
count++;
}
lib.sleep(30);
}
}
其中关于控制主循环速度的代码可以不要,但是lib.sleep(30)必须保留,因为在Nokia60的手机上,如果去除了sleep(30),那么游戏将无法切换回来。同时,在游戏中任何一个内部循环中,也必须加入sleep(30)这个等待,才能让游戏可以切换回来,至于为什么这样做,我暂时还不清楚。30ms是我测试过没有问题的数值,可能比30ms还小的值也是没有问题的。
同时,在MOTO的手机上,必须将游戏的主循环放在一个线程中,游戏才能切换回来,不过可以不加上面说的sleep(30)延时。
2.不使用线程的主循环办法
这个办法只能在Nokia的平台上实现,而我只建议在Nokia40的平台上做,这样不需要线程,道理上来说节约了一些内存,如果不是内存很紧张的机型,那么最好还是使用上一种办法。
游戏的主循环放在MIDlet的class里面,具体做法如下:
publicclassGameMIDletextendsMIDlet{
GameDisplayabledisplayable=null;
/**游戏时钟间隔毫秒为单位*/
publicstaticlongtimeinterval=0;
//用于游戏时钟的变量
publicstaticlongtimeold=0;
publicstaticlongtimenow=0;
publiclonginterval=0;
publicstaticlongframes_per_second=0;
intcount=0;
longsecond=0;
publicstaticbooleanrunning=false;
staticbooleanexitApp=false;
publicGameMIDlet(){
displayable=newGameDisplayable();
running=true;
}
publicvoidstartApp(){
running=true;
Display.getDisplay(this).setCurrent(displayable);
while(running){
timenow=System.currentTimeMillis();
interval=timenow-timeold;
if(interval>=timeinterval){
timeold=timenow;
displayable.Game_Process();
if(second!=(System.currentTimeMillis()/1000)){
second=System.currentTimeMillis()/1000;
frames_per_second=count;
count=1;
}else
count++;
}
}
if(exitApp){
destroyApp(true);
notifyDestroyed();
}
}
publicvoidpauseApp(){
running=false;
}
publicvoiddestroyApp(booleanunconditional){
running=false;
}
publicstaticvoidquitApp(){
running=false;
exitApp=true;
}
}