项目报告
基于Java ME无线网络移动端的俄罗斯方块游戏的实现
本系统是一个基于Java ME平台的无线网络移动端的俄罗斯方块游戏,利用Java ME Wireless Toolkit(WTK)开发包工具在无线网络移动端上实现经典的俄罗斯方块游戏。论文开始部分对无线网络移动系统开发中常使用几种开发语言和环境作了比较,说明了选择Java ME Wireless Toolkit作为开发环境的的原因并对它作了相关的介绍。并展示了在WTK中打开一个项目、把源文件打包成JAR包、产生混淆包的方法和过程。在系统设计时,遵循了无线网络移动端程序的startApp、pauseApp、destroyApp的开发生命周期。在设计与实现方面,分成难度选择、游戏规则、方块处理这几个模块进行实现。在开发与实现的同时也讲解了俄罗斯方块这款古老而经典游戏的游戏背景、规则以及相关特性。最终展示了无线网络移动端的游戏开发的基本开发过程和设计思路。
无线网络移动端;Java ME;俄罗斯方块;游戏
- 引言
- 系统综述
综合运用以前所学专业知识,在Java ME开发平台上实现无线网络移动端的俄罗斯方块游戏。其研究主要包括以下内容:第一,克服有限的可视屏幕尺寸,使游戏正常显示;第二,解决有限的可用内存调用问题,实现游戏流畅运行;第三,俄罗斯方块游戏规则算法在Java ME平台的实现,保证游戏可玩性;第四,游戏开始、结束等逻辑在游戏进行中的判断。本系统在Windows XP的操作系统下,Java Micro Edition Wireless Toolkit 2.1为开发工具,用中文版UltraEdit做为代码编辑器而实现的。
-
- Java ME游戏开发背景
游戏开发是艺术与编程技术相结合的完美表现。利用Java的“Write once,run anywhere”特性,可以真正达到程序只写一次,在任何平台都可以执行。同时Java语言对面向对象的良好支持,使开发具有高效性。所以Java ME(Java Micro Edition)是广大无线网络移动端游戏开发厂商和游戏开发爱好者的首选平台。
-
- 无线网络移动端游戏发展现状
纵观IT产业的历史,计算机游戏已经成为技术创新背后的动力之一。计算机游戏者渴望更加强大的硬件计算能力,渴望不受不同的软件的限制——无论是将图形强制在人工智能(AI)上还是网络安全性。而无线网络移动端游戏已成为IT产业中增长最快的部分之一。
无线网络移动端是一个崭新的游戏开发平台。在众多种类的游戏当中,只有几种游戏类型是适合开发成无线网络移动端游戏的。低激烈程度的游戏;简单街机游戏;运动类“情景”游戏;简单的运动类游戏;解谜或简单的匹配游戏;主题测试游戏。在上面的游戏种类中,我选择了经典的方块匹配游戏:俄罗斯方块。俄罗斯方块有着举世闻名的游戏性且非常直观。某些与坠落的玩具碎片和它们的形状有关的东西,使得哪怕新手也会很自然地企图把它们排列起来,并加以适当组合,就好似俄罗斯方块触动了玩家某些内在的感官,使得哪怕是我们当中最杂乱无章的人也要把事情整理妥当。在操控性方面,只需方向键就可完成对游戏的全盘控制,这也适合无线网络移动端游戏的基本特性。
俄罗斯方块要比过去二十年间出现的任何东西都要浪费人们的时间。它被GameSpot评选为历史上最伟大游戏之一。它的起源实际上要追溯到八十年代中期,尽管它的人气一直到几年后才开始显露出来。游戏的概念十分简单,如今已经成为一种公认的规则:屏幕顶部以随机顺序落下形状各异的碎块,玩家要试图用它们拼成没有空隙的行列。玩家是没法打赢它的,因为坚持得时间越长,游戏速度也就变得越来越快,而游戏的吸引力就在于使玩家顶住碎块的进攻,支撑的时间比上一次更长。俄罗斯方块举世闻名的游戏性,在该游戏新鲜出炉时就显得非常直观。某些与坠落的玩具碎片和它们的形状有关的东西,使得哪怕新手也会很自然地企图把它们排列起来,并加以适当组合,就好似俄罗斯方块触动了玩家某些内在的感官,使得哪怕是最杂乱无章的玩家也要把事情整理妥当。
- 开发环境介绍
- 编程环境的选择
目前,移动开发有以下四种主流平台。Java Micro Edition(Java ME),Binary Runtime Environment for Wireless(BREW),Symbian和Window Mobile Smartphone。其中:
Binary Runtime Environment for Wireless(BREW)
BREW是基于高通公司的Code Division Multiple Acces(CDMA)技术的手机为开发平台。它使用C或C++结合BREW API来开发BREW设备上面的程序。和Java ME一样BREW能够作为游戏和地磁手机操作系统之间的一个中介。和Java ME不同,BERW也支持本地代码,能够专门针对某一手机的处理器而编译。本地代码通常比对应的解释版本要快很多,但在设备之间移植会花费很多技巧。在北美和亚洲有部分无限通信服务提供商。
Symbian
Symbian是一种开放的操作系统,任何设备制造商都能获得使用许可。Symbian支持C++、Java和Visual Basic等编程语言。但大多数商业Symbian游戏都是用C++开发并作为本地Symbian应用程序,这使得它们和Java开发的游戏相比更快一些。
Window Mobile Smartphone
在Window Mobile Smartphone平台上,可以使用在编写Pocket PC游戏时所用的一样的工具和API。这意味着要使用C、C++或C#编程语言并结合使用Window Mobile API。
这里我选用Java Micro Edition(Java ME)作为开发平台。
Sun Microsystem公司在1999年6月推出Java ME。Java ME用于为信息家电市场提供应用服务,这些信息家电包括传呼机、移动电话、个人商务助理(PDA)、电视机顶盒、POS终端以及其他消费电子设备。Java ME体系结构采用模块化、可扩展的设计。这种设计通过一个3层软件模型来实现。
由于无线移动设备比桌面计算机具有更弱的计算能力和更小的屏幕,Java ME代表着Java SE的一个简化功能集,Java ME是Java SE的一个子集,它支持一个较小的功能集,这些功能适用于无线和有线的移动设备。Java ME包括一组可以灵活调用的开发工具和丰富的应用程序接口(API)。依靠通用的字节码而不是本地应用程序代码,其程序不需要费多大力气就可以移植到不同的手机。同时全球手机制造商中,Java ME有着最广泛的工业支持。
Java ME也是目前最占据优势的移动软件开发技术。并且所有的迹象表明它将保持并可能继续扩展它的市场份额。2007年约有4.5亿支持Java的手机销售出去,占据整个手机市场的75%。
按照MIDP规范开发的Java ME应用程序叫做MIDlet。因此,用Java ME MIDP创建的任何游戏实际上都是MIDlet。MIDlet类存储在Java字节码文件中,扩展文件名.class。而MIDlet类必须在发布之前进行验证,以确保它们不会执行任何非法操作。进行这个预验证步骤的原因和移动设备所使用的虚拟机的限制有关。为了保证虚拟机尽可能地小且高效,在一个运行时MIDlet类上所执行的验证被最小化。预验证在编译之后发生,并生成一个新的class文件,这个文件是通过验证后等待测试或发布的。最后MIDlet打包成JAR文件以便发布。应用程序描述符(JAD文件)提供了和一个JAR文件中包含的多个MIDlet相关的描述信息。一个MIDlet套件中的JAR文件,能够提供安装和访问单个MIDlet的相应的信息。
Java SDK是用Java进行开发的一个标准开发工具包。Java ME Wireless Toolkit(JWT)的作用相当于一个用来和Java SDK协同工作的插件,它包括用来验证和测试MIDlet的一个字节码验证器和几个Java ME模拟器。
Java ME技术架构分为:简表(Profile)、配置(Configuration)和Java虚拟机(Java Virtual Machine)3层,它们都构建在本地操作系统之上。
其中,简表层定义了特定系列设备上可用的应用程序编程接口(API)的最小子集;配置层面对的是大量各种不同的小型嵌入式设备,通过定义其配置可以描述硬件的功能;Java虚拟机层是针对在本地操作系统定制的虚拟运行平台。其架构图如下:
简表层(Profile) |
配置层(Configuration) |
Java虚拟机(JVM) |
图1 Java ME架构图
按照MIDP规范开发的Java ME应用程序叫做MIDlet。用Java ME MIDP创建的任何游戏实际上都是MIDlet。MIDlet类存储在Java字节码文件中,扩展文件名.class。而MIDlet类必须在发布之前进行验证,以确保它们不会执行任何非法操作。进行这个预验证步骤的原因和移动设备所使用的虚拟机的限制有关。为了保证虚拟机尽可能地小且高效,在一个运行时MIDlet类上所执行的验证被最小化。预验证在编译之后发生,并生成一个新的class文件,这个文件是通过验证后等待测试或发布的。最后MIDlet打包成JAR文件以便发布。应用程序描述符(JAD文件)提供了和一个JAR文件中包含的多个MIDlet相关的描述信息。一个MIDlet套件中的JAR文件,能够提供安装和访问单个MIDlet的相应的信息。
本系统的编译环境选用Java ME Wireless Toolkit(JWT)version 2.1,这样对于游戏中包含的类,字节码验证器在打包前对它们进行验证。Java ME模拟器可以用来在PC上测试,而不必下载到移动设备上。
-
- Java ME Wireless Toolkit(WTK)简介
Java ME Wireless Toolkit(WTK) 的全称是:Java ME无线开发工具包。这一工具包的设计目的是为了帮助开发人员简化Java ME的开发过程。它的功能包括了编译、打包、模拟执行MIDP应用程序。其中包括了字节码验证器、Java ME模拟器、KToolBar、预配置服务器(provisioning server)等很有用的工具。
该工具箱包含的生成工具、实用程序以及设备仿真器。现在共推出有四个版本,分别是1.0.4, 2.0, 2.1和2.2。每个版本都包括英语,日语,简体中文,繁体中文4个语种包。它的功能包括了编译、打包、模拟执行MIDP应用程序。1.0.4版只能够开发MIDP1.0 应用程序,2.0版只能够开发MIDP2.0应用程序,2.1版则可以同时开发MIDP1.0、JTWI(CLDC1.0,MIDP2.0,WMA1.1)可改用CLDC1.1或加入MMAPI1.1)、自定义(随机组合Configuration、Profile以及Optional Package)三种环境下的应用程序。2.2版中,WTK全面的支持JTWI规范。即MIDP 2.0、CLDC 1.1、 WMA 2.0、 MMAPI 1.1、Web Services(JSR 172)、File and PIM APIs(JSR 75)、Bluetooth and OBEX APIs(JSR 182)和3DGraphics(JSR 184),同时也可以使用该版本开发面向CLDC1.0 和MIDP1.0的应用程序。
WTK工具包中的KToolBar是一个可视化的开发环境,可以通过一个图形用户界面来创建、编译、打包和测试Java ME应用程序。它也提供了直接的方法来管理MIDlet项目并生成设置。
这里我选用WTK 2.1作为开发环境。
安装WTK 2.1后,将得到一个包括多种实用工具的开发包。以下是安装显示的菜单项,见下图:
图2 WTK文件结构
无论哪个版本的WTK 都会包括以下几个目录:
appdb 目录: RMS 数据库信息
apps 目录: WTK 自带的demo 程序
bin 目录: Java ME 开发工具执行文件
docs 目录: 各种帮助与说明文件
lib 目录: Java ME 程序库,Jar 包与控制文件
session 目录:性能监控保存信息
wtklib 目录: JWTK 主程序与模拟器外观
-
- Java ME Wireless Toolkit(WTK)开发环境的简介
打开WTK下的KTookBar。选择打开项目,WTK 会把自身apps目录下的应用项目全部显示出来,选择“打开项目”后,能够对apps目录下的MIDlet项目进行开发更改, 见下图:
图3 打开一个项目
直接运行MIDP应用程序可以在程序组中直接选择Run MIDP Application…。在弹出的对话框中选择其它路径中的JAD程序运行。JAD描述文件与其指定的JAR文件需在同一个目录下。同时运行目录路径中不能包含中文。KToolBar的生成功能只能帮将源代码编译并预先审核并不会帮产生JAR 文件,如果要发布MIDP程序,除了JAD描述文件,还必须打包成JAR文件。
在KToolbar选中Project->Package->Create Package,可以把整个程序,包括资源文件打包成JAR文件。形成的JAR保存在项目对应的bin目录下,如下图:
图4 创建一个包
KToolBar除了“产生包”,另外还有“产生混淆包”功能。为了防止别人反编译后读取源代码,将程序(.class 文件)进行混淆,经过混淆的Java Byte Code可以增加反编译源代码的时间。在KToolBar的Edit->Preferences里面提供很多实用的功能,如下图:
图5 选择Preferences菜单
KToolBar除了“产生包”,另外还有“产生混淆包”功能。为了防止别人反编译后读取源代码,将程序(.class 文件)进行混淆,经过混淆的Java Byte Code可以增加反编译源代码的时间。
在需要监视程序性能的时候,可以在Edit->Preferences里选中“Enable Memory Monitor”,在下一次模拟器执行的时候,就可读出程序运行时的内存消耗均值,消耗峰值以及具体产生对象的个数使用情况。
除了内存监视,还可以执行网络监视,设定存储区大小和堆栈大小,设定安全签名和蓝牙操作属性,以尽可能模拟手机实际运行环境。
- 游戏设计
- 俄罗斯方块游戏的背景
俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫(Alexey Pazhitnov)发明。人们一开始并没预料到它将会有如此广泛的吸引力。实际上,在游戏发明后的数年间,俄罗斯方块成了无数场专利官司和法律纠纷的目标,而许多公司也不遗余力地上阵厮杀,想要将游戏的创意据为己有。一个最初的版本是Spectrum Holobyte为IBM兼容机开发的游戏。1988年,俄罗斯方块在街机上也变得非常流行,这归功于Atari,因为他们发布了一个能让两名玩家同时游戏的版本。
俄罗斯方块经常被称为拼图游戏。玩家需要找出如何能把各块积木最好的拼在一起的方法。俄罗斯方块相当于直角的智力拼图游戏,或者其它一种“在这有限空间内组织几何体”的拼图。俄罗斯方块为了创造真正引人入胜的游戏,它巧妙的平衡了拼图游戏与动作游戏的机制。因而每个人玩这个游戏都会有一次不同的体验。俄罗斯方块所用到的一种动作游戏机制是越来越逼近的威胁感,留给玩家的时间总是非常有限。俄罗斯方块中积木是从上面落下来。如果玩家不在积木落到屏幕底下或翻转它,不能给它找一个最有利的位置,这块积木就可能会堵住某处,而它下面的几行也就没有办法拼接完整,玩家也就离游戏结束又靠近了一行或几行。在游戏进程中,积木落下来的速度越来越快,这样对玩家的挑战也就越来越大,游戏的难度也逐步增加。
-
- 俄罗斯方块游戏的规则
俄罗斯方块游戏的玩法非常简单易学,游戏界面是一个很高的长方形2D盒子,方块出现在盒子的上方,这些方块都由四个小方块组成,并按照各种方式排列,其中每一个方块都至少和另一个方块相连。然后,这些积木慢慢地落向盒子底部,玩家可以把这些方块左右移动或旋转。一旦这个方块碰到阻碍,比如盒底或者另一个方块,它就会停止,而玩家可以对之加以操作。当屏幕底端的方块拼满一横行时,这个层的方块就会消失,而这一行以上的所有方块都会下降一层。而当那些没有拼完的横行填满整个长方形盒子,新的方块无法再出现时,游戏就结束了。
-
- 俄罗斯方块游戏的特性
(1)单屏游戏:
俄罗斯方块全部反映在一个屏幕上。玩家可以在同一时间看到整个游戏环境,在此基础上决定怎么处理手上的这块积木。这个游戏当中没有任何探险成分在内,它不会让玩家真正大吃一惊,玩家能够看到让游戏顺利进行下去的所有信息,所以玩家输了的话只能怪他自己。
(2)无限游戏:
只要积木还没有堆到盒顶,俄罗斯方块就允许玩家一直玩下去,不管他做出了多少错误的决定。每次游戏都以失败而告终,没有人真正能打败这个游戏。玩家们总是能找到提高玩俄罗斯方块技艺的方法,这就是俄罗斯方块和传统拼图游戏的根本不同。一旦玩家拼好了一幅拼图,只要他还记得他是怎么拼的,那么这个拼图就对他再也无挑战了。所以人们通常不会多次玩一个拼图,但一个设计精巧的游戏却总能让人玩上一遍又一遍。俄罗斯方块正是这样一个游戏。
(3)多条生命:
和大多数的街机游戏不同,最早的俄罗斯方块只给玩家一条生命。积木一堆到盒子顶部,玩家就输了。但是游戏的设计允许玩家出现错误,同时还不会立即败下阵来。当积木叠在长方盒子的底部时,玩家可以看到自己所犯的错误,在游戏结束前,他还是有时间想一想如何把后面的积木拼放得更合理些。这样,俄罗斯方块虽然没有给玩家多条生命,但却在玩家重新开始前,给玩家一个改善游戏技巧、获得一些小小成就的机会。
(4)最高分机制:
俄罗斯方块引入一个计分模式,它给玩家计分并把分数记录在高分排行榜上。实际上,因为玩家不可能击败这个游戏,所以,取得一个更高分数的可能性就成为玩家反复玩这个游戏真正的动力所在。
(5)简单易学,容易操作:
俄罗斯方块的真正杰出之处在于它的游戏机制简单平朴,浅显易懂。玩好这个游戏只需极少的键位,所有操作都在屏幕上一览无余。这意味着,不论是否熟悉计算机游戏,任何人都可以走过来并立即开始玩它。然而,玩家永远不可能完全掌握这个游戏,因为这个游戏的难度与是递增并且它在理论上可以玩无限长的时间。
- 游戏系统分析设计
- 系统解决方案
本系统在Windows XP的操作系统下,以Java Micro Edition Wireless Toolkit 2.1为开发工具,用中文版UltraEdit做为代码编辑器而实现的。在KToolBar开发包的DefaultColorPhone模拟器下进行调试。
-
- 系统总体结构
系统开发的主要任务是俄罗斯方块游戏在无线移动端的实现。本系统的主要实现功能模块分为:难度选择模块、方块处理模块、游戏规则模块。
-
-
- 难度选择模块
-
用户在title屏按键数字键选择0-9种游戏难度,进入相对应游戏关卡。
进入游戏 按键输入(0-9)选择关卡难度 |
处理输入 选择关卡难度 |
进入关卡0 |
进入关卡1 |
进入关卡2 |
进入关卡3 |
。。。。。。 |
判断游戏是否结束 |
图6 Title屏选择关卡模块图
-
-
- 方块处理模块
-
方块处理模块定义方块的7种状态,每种状态都是由四个小方块组合而成,如下:
图7 方块形状模块图
-
-
- 游戏规则模块
-
游戏规则模块主要实现俄罗斯方块游戏基本规则。比如,积满一行后消减;能够快速直接的下落;记录游戏最高分;方块翻转;分数计算;随机生成方块,见下图:
游戏规则 |
消减积满行 |
快速下落 |
方块翻转 |
分数计算 |
随机生成方块 |
图8 游戏规则模块图
-
- 游戏中断处理流程
中断处理是移动设备程序生命周期的重要组成特性,包括下图三种阶段:
运行阶段(startApp) |
挂起阶段(pauseApp) |
结束阶段(destroyApp) |
唤醒 |
挂起 |
结束 |
结束 |
图9 系统生命周期图
- 系统实现与测试
- 系统源文件结构
本系统由10个类组成并实现全部功能。项目名字为TetrisMidlet,其项目文件结构如下图:
图10 项目结构图
在项目源文件中,src文件夹下为实现系统的源文件。建了两个包作为功能划分,分别为:ui包和model包。
-
- 难度选择模块
- 难度选择模块结构
- 难度选择模块
ui包里包含以下类:
InfoBox.java 用于显示数字的信息框
TitleBox.java 显示title屏,包含当前高分提示选择一个难度
NextPieceBox.java 显示下一个激活方块
TetrisCanvas.java 处理程序的所有UI
DisplayBox.java 在屏幕上显示Box
其结构图如下:
ui包 |
InfoBox |
TitleBox |
NextPieceBox |
TetrisCanvas |
DisplayBox |
图11 ui包结构图
其中核心类DisplayBox.java的方法图如下:
图12 类DisplayBox的方法图
在DisplayBox.java中方法paint()实现了title屏的显示,其代码如下:
public final void paint(Graphics g) {
g.setColor(this.bgColor);
g.fillRect(x, y, width, height); // box的背景
g.setColor(this.fgColor);
g.drawRect(x, y, width, height); // 边框
this.paintBoxContents(g);}
下面是TerisCanvas.java中绘制方块paintBlock()方法的实现代码:
private void paintBlock(int x, int y, int blockType, Graphics g) {
int blockX = this.boardX + (this.blockSize * x);
int blockY=this.boardY+(this.blockSize* (y - TetrisConstants.TOP_VISIBLE_ROW));
if(TetrisConstants.BLOCK_EMPTY != blockType) {
// 绘制下落时的阴影
g.setColor(TetrisConstants.COLOR_BLACK);
g.fillRect(blockX + 1, blockY + 1, this.blockSize - 1, this.blockSize - 1);
// 绘制一个实际的方块覆盖在阴影上
this.setColor(blockType, g);
g.fillRect(blockX, blockY, this.blockSize - 1, this.blockSize - 1);
} else {
//绘制颜色
g.setColor(TetrisConstants.COLOR_WHITE);
g.fillRect(blockX, blockY, this.blockSize, this.blockSize);}}
其中,TOP_VISIBLE_ROW为TetrisConstants下定义,Y坐标的从行0开始索引的位置,初始值为2。
BLOCK_EMPTY为TetrisConstants下定义的空方块,初始值为-1。
COLOR_BLACK为TetrisConstants下定义的预设RGB颜色,初始值为0x00000000。
COLOR_WHITE为TetrisConstants下定义的预设RGB颜色,初始值为0x00ffffff。
-
-
- 难度选择模块功能
-
模拟器程序运行,在应用程序列表里显示可以载入运行的模拟程序,如下图:
图13 载入程序
点击运行程序后,在title屏显示游戏名称、作者、最高分记录和按键提示,点击数字键输入0-9中的一个数字,以选择不同难度的关卡,如下图:
图14 运行游戏
在title屏,也可以点击左软键退出程序。
-
- 游戏规则模块功能
- 游戏规则模块结构
- 游戏规则模块功能
游戏规则模块包含3个类:
DropThread.java 处理方块下落问题
TetrisConstants.java 常数定义
TetrisMidlet.java 游戏规则和对键盘输入的捕捉,以及中断的处理
其结构图如下:
TetrisMidlet |
Ui包 |
Model包 |
DropThread |
TetrisConstants |
TetrisMidlet |
图15 游戏规则模块结构图
其中核心类DropThread.java实现了方块的下落,它的方法图如下:
图16 类DropThread方法图
其中run()方法实现循环下落,代码如下:
public void run() { //运行方法
while(this.running) {
// 当前下落的方块
if(this.skipNextTick) {
this.skipNextTick = false;
} else {
this.game.tick();
}
try {
Thread.sleep(this.game.getTickSpeed()); // 线程睡眠
} catch(InterruptedException ie) {
}}}
-
-
- 游戏规则模块功能
-
游戏规则模块实现俄罗斯方块游戏的主要功能包括,消减积满的行、快速下落、方块翻转、分数计算、下落碰撞检测、随机生成方块。
下面是消减积满行功能代码,如下:
private int clearCompletedRows(TetrisPiece piece) {
TetrisBoard board = this.getBoard();
// 检查方块的每一行,看是否以完成
for(int i = 0; i < TetrisConstants.FOUR_BLOCKS; i++) {
int rowY = piece.getBlockY(i);
// 如果一行被填充满,则标记为完成
if(board.checkRowCompleted(rowY)) {
this.markRowCompleted(rowY, true);
}
}
int numClearedRows = 0;
for(int y = TetrisConstants.HEIGHT - 1; y >= 0; y--) { //从下到上重复
if(numClearedRows > 0) {
board.dropRow(y, numClearedRows);
}
if(this.isRowCompleted(y)) {
numClearedRows++;
this.markRowCompleted(y, false); // 为下一次重置
}
}
// 清除最上面的完成行数
for(int i = 0; i < numClearedRows; i++) {
board.clearRow(i);
}
return numClearedRows;
}
为了增加玩家在游戏过程中的游戏性,下落的方块设置成随机生成,这里利用rand.nextInt方法得到随机数,下面是随机生成方块功能的部分代码,如下:
private int getRandomPieceType() {
return Math.abs(rand.nextInt() % TetrisConstants.NUM_PIECE_TYPES) + 1;
}
首先用rand.nextInt()方法得到随机数后,用随机数除以TetrisCanstants中定义的表示方块类型数的常量NUM_PIECE_TYPE,其值初始值为7,取余后加1取其绝对值。实现效果如下图:
图17 游戏进行状态图
在前面4.3部分通过图9的系统生命周期流程图,已经了解了游戏中断处理的过程。在游戏运行时可以按右软键调用程序生命周期中pauseApp()方法暂停游戏,方块会停在暂停位置,直到玩家再次点击右软键恢复游戏,pauseApp()方法代码如下:
protected void pauseApp() {
// 挂起程序使游戏进入暂停状态
if(TetrisConstants.RUNNING_STATE == this.gameState) {
this.pauseGame();
} }
在pauseApp方法中调用了pauseGame()方法,其实现代码如下:
private void pauseGame() {
// 把暂停命令替换成恢复命令
this.gameCanvas.removeCommand(this.pauseCommand);
this.gameCanvas.addCommand(this.resumeCommand);
// 进入暂停状态并停止下落
this.setGameState(TetrisConstants.PAUSED_STATE);
this.dropThread.stopThread();}
游戏暂停阶段画面如下:
图18 游戏暂停状态图
当点击右软件恢复游戏后,方块从暂停位置继续下落,这里用了resumeGame()来实现此功能,代码如下:
private void resumeGame() {
// 把恢复命令替换成暂停命令
this.gameCanvas.removeCommand(this.resumeCommand); this.gameCanvas.addCommand(this.pauseCommand);
// 进入运行状态并下落
this.setGameState(TetrisConstants.RUNNING_STATE);
this.runDropThread();}
游戏恢复阶段状态,如下图:
图19 游戏恢复状态图
-
- 方块处理模块
- 方块处理模块结构
- 方块处理模块
俄罗斯方块游戏中出现的七种方块是由4个小块组合而成。方块处理模块包含在model包中:
TetrisPiece.java 当前下落方块的处理
TetrisBoard.java 定义方块格子的状态
其类结构图如下:
Model |
TetrisPiece |
TetrisBoard |
图20 方块处理模块结构图
核心类TetrisPiece中实现了七种方块下落时翻转方式的下落,方块翻转方式分三种方式:自由翻转(Free)、两面翻转(Toggle)、不能翻转(None),下图是判断图示:
两面翻转(Toggle) |
自由翻转(Free) |
无翻转(None |
图21 方块翻转方式判断图示
在四个组成的方块的小块中,有一个中心点小块(1,1)在翻转的时候坐标是不会变化的,这个坐标在参数设置类TetrisConstants.java中,名称为:PIVOT_INDEX,其初始值为1。
下面用方块I举例说明其进行翻转判断的代码:
private void setAsNewIPiece(int x, int y) {
this.pieceType = TetrisConstants.I_PIECE;
this.rotationType = TetrisConstants.ROTATION_TYPE_TOGGLE;//只能进行两个方向的旋转,设置类型为TOGGLE
this.rotationToggle = true; // 设置TOGGLE标志为TURE
this.setBlockCoords(0, x - 1, y);
this.setBlockCoords(1, x , y);
this.setBlockCoords(2, x + 1, y);
this.setBlockCoords(3, x + 2, y);}
下图是类TetrisPiece的方法图:
图22 类TetrisPiece方法图
其中rotate()方法实现了方块的旋转,(x,y)为小方块坐标,其翻转实现算法如
(x,y) |
(-y,-x) |
如向左旋转:(y,-x) |
如向右旋转:(-y,x) |
(-y+1,x+1) |
(y+1,-x+1) |
图23 方块翻转算法流程图
方块翻转算法流程实现代码如下:
public void rotate(int pivotX, int pivotY, boolean rotateDirection) {
if(TetrisConstants.ROTATION_TYPE_TOGGLE == this.rotationType) {
// 如果翻转类型为TOGGLE
rotateDirection = this.rotationToggle; //判断翻转方向
this.rotationToggle = !this.rotationToggle; // 如果与canRotate匹配,中心点方块将被使用
}
// 重构四个小块,每个都转动
for(int i = 0; i < TetrisConstants.FOUR_BLOCKS; i++) {
int blockX = this.getBlockX(i);
int blockY = this.getBlockY(i);
// 左旋转:交换x和y坐标,x坐标取反
// 右旋转:交换x和以坐标,y坐标取反
int dx = blockY - pivotY;
int dy = blockX - pivotX;
if(rotateDirection) {
// 如向左旋转
dx *= -1;
} else {
// 如向右旋转
dy *= -1;
}
int rotateX = pivotX + dx;
int rotateY = pivotY + dy;
this.setBlockCoords(i, rotateX, rotateY);//得到翻转后的新坐标
}
}
-
-
- 方块处理模块功能
-
对当前下落方块的处理,主要功能是及时刷新图像,保证方块状态及时更新。核心类TetrisBoard.java实现了此功能,其方法图如下:
图24 类TetrisBoard方法结构图
当下落方块顶端积满后,游戏系统判断游戏结束。在TetrisBoard.java中的checkRowCompleted()方法实现了此功能,其代码如下:
public boolean checkRowCompleted(int rowY) {
for(int x = 0; x < TetrisConstants.WIDTH; x++) {
if(TetrisConstants.BLOCK_EMPTY == this.getBlockType(x, rowY)) {
// 有空方块,行不被填充
return false;
}
}
return true;
}
如下图:
图25 方块下落游戏图像刷新状态图
当游戏结束时立即显示title屏,计算并显示出这次游戏的最高分。同时等待玩家键入数字,选择游戏难度开始新的游戏。其实现由init()方法控制,其代码如下:
private void init() {
this.board = new TetrisBoard();
this.gameCanvas = new TetrisCanvas(this);
this.activePiece = new TetrisPiece(); //方块处理
this.completedRows = new boolean[TetrisConstants.HEIGHT]; //初始化数组
this.hiScore = this.openAndReadHiScore(); // 从RMS得到当前存储的高分
this.nextPieceType = TetrisConstants.UNINITIALIZED;
this.rand = new Random();
// 设置exit/pause/resume命令
this.setupCommands();
this.gameCanvas.addCommand(this.exitCommand);
// 显示title屏
this.setGameState(TetrisConstants.TITLE_STATE);}
Title屏将显示如下图:
图26 结束并重新开始游戏状态图
结 论
本系统是一个基于Java ME平台的无线网络移动端的俄罗斯方块游戏,利用Java ME Wireless Toolkit(WTK)开发包工具在无线网络移动端上实现经典的俄罗斯方块游戏。论文开始部分对无线网络移动系统开发中常使用几种开发语言和环境作了比较,说明了选择Java ME Wireless Toolkit作为开发环境的的原因并对它作了相关的介绍。并展示了在WTK中打开一个项目、把源文件打包成JAR包、产生混淆包的方法和过程。在系统设计时,遵循了无线网络移动端程序的startApp、pauseApp、destroyApp的开发生命周期。在设计与实现方面,分成难度选择、游戏规则、方块处理这几个模块进行实现。在开发与实现的同时也讲解了俄罗斯方块这款古老而经典游戏的游戏背景、规则以及相关特性。最终展示了无线网络移动端的游戏开发的基本开发过程和设计思路。
和桌面电脑游戏以及家用游戏系统游戏开发一样,无线网络移动端游戏开发必须要掌握和组合应用各种软件开发技术。同时它也是计算机科学技术与艺术结合的产物,也许正是艺术和技术技能的这种独特混合,使游戏开发具有独特魅力。种种调查数据可以证明无线网络移动端游戏市场的繁荣,如今没有人会怀疑它的美好未来。在Java ME这种面向对象、高移植性的语言平台进行开发是大多数无线网络移动端游戏开发者的首选。它一定会随着无线网络移动端游戏的创新不断发展壮大。
参考文献
[1] Michael Morrsion.J2ME手机游戏编程入门[M].北京:人民邮电出版社,2005。
[2] 李振鹏,龚剑.J2ME手机游戏开发技术详解[M].北京:清华大学出版社,2006。
[3] Richard Rouse.游戏设计原理与实践[M].北京:电子工业出版社,2004。
[4] 王森.Java手机/PDA程序设计入门[M].北京:电子工业出版社,2005。
[5] 刘斌.J2ME手机开发入门[M].北京:人民邮电出版社,2006。
[6] Qusay H. Mabmoud.无线Java入门[M].北京:清华大学出版社,2002。
[7] Joshua Bloch,Neal Gafter.Java解惑[M].北京:人民邮电出版社,2006。
[8] Joshua Bloch.Effective Java[M].北京:机械工业出版社,2005。
[9] 殷兆麟.Java语言程序设计[M].北京:高等教育出版社,2004。
[10] 黄斐.MS Project2002项目管理与应用[M].北京:科学出版社,2004。