`
- 浏览:
673395 次
- 性别:
- 来自:
太原
-
不久前我曾用J2ME开发了一个MotoT720下的彩色游戏?宝石方块(GridOne)。开发过程中积累了一些经验,现在写出来与大家分享。
使用双缓冲避免屏幕闪烁
双缓冲技术是编写J2ME游戏程序的关键技术之一。实际上,双缓冲技术是计算机动画的一项传统技术。造成屏幕闪烁的主要原因在于,画面在显示的同时,程序又在改变它,于是画面闪烁。解决办法就是在内存中开辟一片区域作为后台画面,程序对它更新,修改,完成后再显示它。这样被显示的图像永远是已经完全画好的图像,程序修改的将不是正在被显示的图像。当然还有其它方法可以解决屏幕闪烁问题,但使用双缓冲技术是一种值得推荐的解决方案。具体方法可参见如下代码:
public class BlocksCanvas extends Canvas implements Runnable
{
Graphics bg;
Image buf;
public BlocksCanvas()
{
......
height = getHeight();
width = getWidth();
//按屏幕大小建立缓冲对象
buf = Image.createImage(width, height);
//将缓冲对象的Graphics附给bg
bg = buf.getGraphics();
......
}
public void run()
{......
for(i=0;i {
for(j=0;j {//画方块
drawBlock(x,y);
}
}
repaint();
}
private void drawBlock(int block_x, int block_y)
{
//取得方块的坐标
int x = getLeft(block_x);
int y = getTop(block_y);
//取得方块的颜色
int c= board[block_x][block_y];
bg.drawImage(imgs[c], x, y, Graphics.TOP | Graphics.LEFT);
}
public void paint(Graphics g)
{
g.drawImage(buf, 0, 0, Graphics.TOP | Graphics.LEFT);
}
}
由上面代码可见,双缓冲思想体现在程序上就是要依次完成以下几步工作:
1. 定义一个Graphics对象bg和一个Image对象buf,按屏幕大小建立一个缓冲对象附给buf,然后取得buf的Graphics对象附给bg。在这里,Graphics对象可以理解为缓冲的屏幕,Image对象则可当成缓冲屏幕上的图片。
2. 在bg(缓冲屏幕)上用drawImage()和drawString等语句画图,相当于在缓冲屏幕上画图。
3. 调用repaint()语句,它的功能是告知系统调用paint()来完成真实屏幕的显示。这里需要注意的是,paint()是一个系统调用语句,不能手工调用,只能通过paint()语句来调用。
4. 在paint(Graphics g)函数里,将buf(缓冲屏幕上的图片)画到真实屏幕上。
以上的步骤虽然看似繁琐,但是效果还是很不错的。如果想要在屏幕上显示什么东西,只管画在bg上,然后调用repaint()将其显示出来就可以了。
编写自己的断点函数
图1 断点测试
在开发J2ME程序过程中,最困扰人的问题就是程序容易莫名其妙地死机。当使用JBuilder或者CodeWarrior设置断点功能来查找程序错误时,死机的概率就更大了。即使不死机,也会担心程序受到了意外的干扰,所以一般不推荐使用开发工具自带的断点功能。但有时候又需要一个功能来显示当前各变量的值,以便查错时做出正确的判断。于是我想了一个办法,就是编写自己的断点函数。具体代码如下:
public class BlocksCanvas extends Canvas implements Runnable
{
private boolean stopFlag=false;//调试标志
......
public void run()
{
//断点位置1
testFun(“x:”+x+“y:”+y);
......
//断点位置2
testFun(“”);
......
}
private void testFun(String str)
{
stopFlag=true;
//画一个白色长方形
bg.setGrayScale(255);
bg.fillRect(0,0, fontW, fontH);
//在白色长方形上显示str的内容
bg.setGrayScale(0);
bg.drawString(str, 0,0, Graphics.TOP | Graphics.LEFT);
repaint();
while(stopFlag){}
}
public void keyPressed(int keyCode)
{
stopFlag=false;
}
}
首先定义一个boolean类型的stopFlag变量来记录调试标志。一开始它的值为false,进入testFun()函数后,值设为true。显示完str的内容后,因为stopFlag的值为true,所以while语句进入了死循环,程序停了下来。这时可以仔细地看清楚变量的值。然后当按下任意键时,keyPressed()函数捕捉到这一事件,将stopFlag设为false,死循环自动解开。使用此方法非常方便,只要在需要断点的地方放置testFun()语句即可,一个程序可以放置多个testFun()语句,在循环语句中也可以放置testFun()语句。程序运行到testFun()语句会自动停下显示变量值,按任意键程序又会自动运行,程序也不会受到意外的干扰。图1是调试时的截图。
还有一点需要说明,此方法的testFun()语句必须放在run()函数中或者run()函数运行时调用的函数中,否则就会因为while()占用了所有CPU时间而导致keyPressed()函数无法捕捉按键事件,最后导致死机。
此方法只要稍加修改,就可以用做游戏的暂停功能,而且比sleep()方法好,毕竟理论上sleep()方法不能无限期暂停下去。下面给出相应的代码:
public class BlocksCanvas extends Canvas implements Runnable
{
private boolean stopFlag=false;//暂停标志
......
public void run()
{......
testFun();
......
}
private void testFun()
{
while(stopFlag){}
}
public void keyPressed(int keyCode)
{
int action = getGameAction(keyCode);
if(action== FIRE)stopFlag=!stopFlag;
}
}
该程序段的功能为,当使用者按下FIRE键时,游戏暂停;再次按下FIRE键,游戏继续运行。
编写自己的工具类
因为手机内存和功能的限制,J2ME只提供了部分的J2SE工具类供使用者调用。所以有时我们不得不编写自己的工具类来实现一些特殊的功能。下面给出的kSet类就类似于J2SE中Set工具类的功能。它用来记录游戏中被删去的方块集合,同时保证集合中没有相同元素。
/**
*
Description: Set类在J2ME上的实现
*
Date:2003.2.28
*
Author:TomJava
*
email:tomjava@sohu.com
*/
public class kSet
{//用单链表实现
private kSetNode head;
public kSet()
{
head=null;
}
//将kSet清空
public void clear()
{
head=null;
}
//向kSet中添加元素
public boolean add(int x,int y)
{
kSetNode node=new kSetNode(x,y);
return add(node);
}
//向kSet中添加元素
public boolean add(kSetNode node)
{
if(!contains(node))
{
node.next=head;
head=node;
return true;
}else
{
return false;
}
}
//判断kSet是否为空
public boolean isEmpty()
{
if(head==null)
return true;
else
return false;
}
//摘下链表头元素并返回此元素
public kSetNode getFirst()
{
kSetNode p=head;
head=p.next;
return p;
}
//遍历kSet,如果有相同元素返回true,否则返回false
public boolean contains(kSetNode node)
{
kSetNode p = head;
while (p != null) {
if(p.equals(node))return true;
p=p.next;
}
return false;
}
}
//kSet中的元素
public class kSetNode
{
public int x,y;
public kSetNode next;
public kSetNode(int x,int y)
{
this.x=x;
this.y=y;
next=null;
}
public boolean equals(kSetNode node)
{
if(node.x==x&&node.y==y)
return true;
else
return false;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
}
kSetNode类负责记录被删除方块的坐标,它重载equals()方法用来判断两个方块是否是同一个方块。kSet类是由kSetNode对象组成的没有相同元素的集合,用单链表实现,并且提供了 getFirst()、add()、clear()、isEmpty()、contains()等方法供其它类调用。编写和使用一些这样的工具类,将大大加快编程的速度,也使程序变得更加清晰。
矫正屏幕坐标
GridOne这个游戏是专门为MotoT720开发的,也就是说游戏背景图片大小和MotoT720型手机的大小是相等的。如果它在那些屏幕比MotoT720大的手机上运行,游戏背景图片会显示在屏幕左上角而影响美观,这时就要用到屏幕矫正技术,使得游戏背景图片居中显示。矫正屏幕坐标代码如下:
public class BlocksCanvas extends Canvas implements Runnable
{
private final int addX;//坐标矫正
private final int addY;
private final int SCREEN_X;//屏幕顶点
private final int SCREEN_Y;
private final int WAITBLOCK_X;//等待方块顶点
private final int WAITBLOCK_Y;
private final int SCORES_X;//分数顶点
private final int SCORES_Y;
private final int STAR_X;//五角星的顶点
private final int STAR_Y;
public BlocksCanvas()
{
//取得当前手机屏幕的高度和宽度
height = getHeight();
width = getWidth();
//坐标矫正量
addX = (width-120)/2;
addY = (height-142)/2;
//初始化屏幕参数
SCREEN_X = addX + 48;//屏幕顶点
SCREEN_Y = addY + 10;
WAITBLOCK_X = addX + 19;//等待方块顶点
WAITBLOCK_Y = addY + 103;
SCORES_X = addX + 36;//分数顶点
SCORES_Y = addY + 34;
STAR_X=addX+4;//五角星的顶点
STAR_Y=addY+70;
}
}
首先把所有有关屏幕的参数都定义成private final int型变量。这里之所以加上final 修饰符,是因为不希望变量附初值后,它们的值会发生变化;之所以不加static修饰符,是因为要在其函数中初始化变量,而不是在定义时就初始化好了。先用getHeight()和getWidth()函数取得当前手机屏幕的高度和宽度,再计算出需要的偏移量addX和addY,然后加到各屏幕参数上,这样游戏内容就会居中显示了。图2与图3是效果比较图。
图2 矫正前
图3 矫正后
还有一点需要注意,用getHeight()取得的并不是手机屏幕的真实高度,而是手机屏幕的高度减去Command标签高度,因为屏幕需要留出地方显示Command标签。
合理使用内存
本来使用Java编程是不需要关心内存使用的,因为Java有它引以为豪的垃圾处理机制。但到了J2ME里,情况发生了变化,因为手机的内存只有屈指可数的几百K,再也不能像在J2SE里那样大手大脚了。否则就会发现,即使程序没有任何语法和逻辑错误,也不能在模拟器中运行。下面给出合理使用内存的几个建议:
1. 尽可能使用本地变量代替类成员,减少对象的创建,最好能重新利用对象;
2. 不要试图在初始化的时候把所有Form或者Canvas对象都读入内存中,而应该在需要的时候再创建,虽然这样在显示上会有一些延迟,但是总比程序不能运行或者内存溢出要好;
3. 一旦对象不需要使用就及时将其置为null,以便能够被垃圾处理器回收,适当的时候调用System.gc()语句提示虚拟机调用垃圾处理器;
4.必须记住Java的内存管理是有向边机制,所以对于不使用的对象,千万不要让正在使用的对象指向它,以免内存得不到回收;
5.尽量使图片占有的字节数小一点,可以使用Fireworks在保证图片质量同时减小图片的大小;
即使做到上面几点,也不能保证程序不会发生内存泄漏,因为手机内存毕竟那么少。所以我提出最后一个建议,就是先完成游戏的主体部分,使它能够正常运行并没有内存泄漏,再慢慢扩展游戏,给它加上封面和其它功能。一旦发现内存不足,再去掉部分功能。
使游戏更有魅力
编写游戏当然希望它能吸引人,我觉得下面几个地方值得大家注意:
1. 注意控制游戏的节奏
原来我在削除方块的时候,什么都不做就直接删除,然后开始一个新的循环,让等待的方块往下掉。在实际运行的时候感觉效果不是很好,因为削得越快,上面的方块也掉得越快,让游戏者有一种措手不及的感觉。后来我在删除方块的时候,用空循环停顿了几秒钟,这样就给了游戏者一个反应时间,感觉就好些了,而且如果连削的话,反应时间会更长,这样使得游戏者在玩游戏时有一种轻松的感觉。再后来,我将空循环改成对屏幕上的方块遍历三次,让被删的方块闪烁,使得游戏者能够看清楚被删除的方块,欣赏到自己的成果,这样又增加了游戏的吸引力。
2. 利用图片实现丰富多彩的表达效果
在J2ME中如果不能控制文字的大小和字体,那么这将使游戏的效果大打折扣。不过,可以通过把各种特殊的文字做成图片的方法来解决这个问题。有些地方我们也可以用图片来取代文字,使得游戏更加生动,比如在等级栏用五角星来表示游戏的难度。使用图片还有一个好处就是增加游戏的通用性,使得游戏在不同手机上的显示基本相同。另外,如果出现字体颜色在模拟器中显示正常,而在手机上显示不正常的情况,也可以用这种方式解决。
3. 让游戏能够自动调整难度
我使用如下函数,使得游戏难度不断加大。
private void giveLevel()
{
if(level<=10)
{
levelSleep=600-(level - 1) * 50;
if(levelSleep<200)
levelSleep=200;
levelDelTask=200+(level-1)*100;
if(levelDelTask>1000)
levelDelTask=1000;
//画等级--五角星
paintStar();
}else
{
gameWin();
}
}
level表示游戏等级,levelSleep表示方块下落一个的等待时间,levelDelTask表示过一关需要删除的方块数,也可以理解为过一关需要完成的任务。上面的计算公式可以保证游戏会越来越难,增加了游戏的吸引力。
分享到:
Global site tag (gtag.js) - Google Analytics
相关推荐
总之,j2ME游戏开发涉及到多方面的技术和技巧,从基础的MIDP API学习,到游戏设计、图形动画和音频处理,再到性能优化和分发部署,每一个环节都是成功开发游戏的关键。通过深入理解和实践,开发者可以创造出丰富的...
本书涵盖了J2ME游戏开发的各个方面,从基础知识到高级技巧,旨在帮助读者掌握开发移动游戏的全过程。以下是一些关键知识点: 1. **J2ME架构**:讲解了J2ME的配置和 profiles,如MIDP(Mobile Information Device ...
这个压缩包包含的“J2ME游戏开发资源”是一份宝贵的资料库,对于想要学习或从事J2ME游戏开发的人员来说极具价值。 在J2ME游戏开发中,以下几个核心知识点至关重要: 1. **基础环境搭建**:首先,开发者需要安装...
通过深入学习和实践,开发者可以掌握J2ME游戏开发的技巧,创造出吸引人的移动游戏,尽管现代移动开发已经转向了更强大的平台如Android和iOS,但了解J2ME的历史和原理对于理解移动游戏开发的演变历程仍然有价值。
总的来说,J2ME游戏开发的高级优化技巧主要包括理解游戏类型的需求,选择正确的优化策略,使用Profiler工具定位性能瓶颈,以及谨慎地进行代码优化,确保在提升性能的同时保持代码的可读性和可维护性。通过这些方法,...
《J2ME游戏开发(第一版)》是针对Java Micro Edition(J2ME)平台进行游戏编程的专业指导书籍。J2ME是Java平台的一个子集,主要用于嵌入式设备和移动设备,如早期的智能手机和平板电脑。这本书的焦点在于教导开发者...
**J2ME游戏开发实例详解** J2ME(Java 2 Micro Edition)是Java平台的一个子集,专门用于开发在移动设备和嵌入式设备上的应用程序,包括游戏。本资源包含多个J2ME游戏的源代码,对于学习J2ME游戏开发的初学者来说,...
《J2ME游戏开发详解》这本书深入探讨了Java 2 Micro Edition(J2ME)平台上的游戏开发技术,为读者揭示了如何利用这一强大的移动开发框架来创建吸引人的手机游戏。J2ME作为早期智能手机和平板设备上的主流开发平台,...
本篇将深入探讨J2ME游戏开发的经典实例,揭示其核心技术和设计思路。 一、J2ME概述 J2ME由两部分构成:配置(Configurations)和 profiles(Profile)。配置定义了硬件和软件的基本能力,如 Connected Limited ...
### J2ME游戏开发知识点概览 #### 一、书籍简介 《J2ME游戏开发》是一本专注于Java 2 Micro Edition (J2ME) 平台上游戏开发的专业书籍。该书由Jason Lam编写,Deaboway Chou翻译成中文版本。本书旨在教授读者如何...
### J2ME游戏开发 #### 一、简介与目标 《J2ME游戏开发》一书由Jason Lam撰写,Deaboway Chou翻译。本书旨在为那些希望使用Java 2 Micro Edition (J2ME) 技术进行移动游戏开发的开发者提供指导。随着MIDP 2.0标准...
**二、J2ME游戏开发环境** 开发J2ME游戏通常需要一个集成开发环境(IDE),如NetBeans或Eclipse,它们提供了代码编辑、调试和模拟器等功能。此外,像MIDP API和Java Game API这样的库为游戏开发提供了必要的工具和类...
这本书深入浅出地介绍了J2ME游戏开发的核心概念和技术,对于初学者和有经验的开发者来说都是宝贵的资源。 首先,书中会讲解J2ME的基础知识,包括MIDP(Mobile Information Device Profile)和CLDC(Connected ...
这个压缩包“J2ME游戏开发.rar”包含了关于利用J2ME进行游戏开发的相关资料,主要以“J2ME游戏开发.pdf”的形式存在。以下是基于J2ME游戏开发的一些核心知识点: 1. **KVM (Java Virtual Machine)**: J2ME使用的是...
**J2ME游戏开发文档详解** Java 2 Micro Edition(J2ME)是Java平台的一个子集,专门设计用于资源有限的设备,如移动电话、PDA和家用电器。在移动游戏开发领域,J2ME因其跨平台能力和相对较低的硬件需求而受到广泛...
### J2ME游戏开发知识点详解 #### 一、概述与目标 **《J2ME游戏开发》**是一本专注于在移动设备上使用Java 2 Micro Edition (J2ME)进行游戏开发的专业指南。本书旨在为那些希望利用J2ME平台进行游戏开发的专业人士...
本资源提供了“J2ME手机游戏开发技术与实践”的PPT和源代码,由李政仪编著,旨在帮助开发者深入理解J2ME游戏开发的核心技术和实战技巧。 **1. J2ME基础** 在开始J2ME游戏开发之前,首先需要了解J2ME的基本架构,它...
通过深入分析这个J2ME游戏开发框架示例,开发者可以掌握创建J2ME游戏的基本步骤和技巧,为今后的移动游戏开发打下坚实基础。同时,这个示例也展示了如何将复杂的逻辑封装在框架中,使得游戏开发更为高效和模块化。...