WAP之家:为您提供最全最新的WAP技术,CP.SP.3G等行业资讯。 WAP之家交流论坛全新开放 点击进入>>
WAP资讯 | 3G动态 | SP动态 | 运营商动态 | 内容商动态 | 制造商动态 | 论坛讨论>> 每次自动访问
WAP技术 | WAP源码 | 手机编程 | 手机源码 | 无线技术 | J2ME技术 | 手机软件 添加到收藏夹
IVR技术 | SP资料 | SMS MMS技术 | 商业方案 | IVR下载 | 书籍教程 | 工具软件 语言:繁體中文

WAP之家技术文章J2ME技术程序开发一个J2ME拼图游戏的开发

一个J2ME拼图游戏的开发
作者:asklxf  来源:J2MEDV  发布时间:2005-9-7 12:54:58

MIDP规范的出现使得我们在手机上开发Java游戏成为可能。今天我们要实现的是一个简单的拼图游戏。这个拼图游戏是一个3x3的拼图,由9个分割的小图片构成。这样,在手机上,可以用按键1-9对应每个图片。需要移动某个图片时,只需按下对应的数字键即可,非常方便。(当然,对于键盘不规则的手机,就只能委屈了)当按下0键时,显示整个原始图片。

虽然MIDP提供了许多高级和低级的UI API接口,但是整个应用程序的结构设计仍然至关重要,一个灵活的框架能大大降低游戏开发的复杂度。

MVC模式几乎是UI应用开发的标准模式了,通过Model-View-Controller的分工合作,使得整个应用程序的不同功能部分被分离开来,从而降低开发难度。

MVC有MVC1和MVC2两种模式,其不同之处在于Model能否主动通知View。在窗口程序中,Model可以主动通知View是否需要Update,因此应使用MVC1;在Web程序中,由于http协议的限制,服务器端的Model无法主动调用View(如JSP页面),因此只能使用MVC2,由Controller取得Model并渲染View。

在窗口程序中,View通常仅有一个,但Model可能有很多;而在Web程序中,Model通常被放在Session中,每个JSP页面都是一个View,因此View有很多。

微软的MFC框架也是一个基于MVC模式的框架,其View-Document框架是专门针对桌面应用程序设计的,因此,我们在MIDP程序中也可借鉴其思想。

在MIDP程序中,MIDlet起着Controller的作用,每个Screen或者Canvas就是一个View,而Model可以用一个单独的类来表示,用于存储程序运行中的数据。对于这个拼图游戏来说,设计以下几个类:

PuzzleMIDlet:控制整个游戏的生命周期。
MainCanvas:绘制游戏的主窗口。
Document:存储游戏运行中的数据。

当用户通过MainCanvas输入命令后(例如,按下某个键),将可能引起Document数据的更新,如果需要更新屏幕,则Document应通知View更新显示,这是一个Observer模式的应用。

由于这个拼图游戏不需要频繁地更新画面,因此连多线程也不必了。

下面是运行在手机上的效果图:


由于公司发的手机还停留在CF62/MIDP1.0的水平,因此只好用MIDP1.0写这个拼图游戏了。不过好在我的重点不在如何绘制Canvas,因此MIDP2.0中的Game Package绝大部分都用不上。

下面我们开始设计每个类。

设计Document类

Document类需要保存游戏运行中所有的状态数据,对于这个拼图游戏来说,我们设计以下成员变量:

Updatable updatable;
int state;
Image[] images = new Image[9];
int[][] current = new int[3][3];
int hiddenX, hiddenY;
int steps; // 移动的步数


MainCanvas需要实现Updatable接口,因此,Document保存了一个View的引用,在恰当的时候,Document可以调用updatable.update()方法通知View需要重绘。这样,MainCanvas和Document就实现了Observer模式。

游戏中,state用于存储游戏状态,一共有3种状态:
PUZZLE_STATE:表示正在拼图;
IMAGE_STATE:表示正在查看原始图片;
FINISH_STATE:表示拼图完成。

images数组按次序存储原始图片,我们把这个90x90大小的原始图片<image>切割成9个30x30的小图片,并依次编号0-8:



current[3][3]是一个二维数组,存储Image在images[]数组中的索引号,这样就可以从current[][]中获得对应的Image对象。

hiddenX和hiddenY用来标识空白方格的位置。仅当位于(hiddenX, hiddenY)上下左右的方格可以移动。

初始化current

为了打乱一个拼好的方格,我们需要一个算法来随机打乱9个方格。在我们想出这个算法前,最简单的方法便是用一个可拼好的数据来写死current[][],使得我们能集中精力先把游戏的框架搭起来:

current = new int[][] {
{2, 7, 5},
{1, 0, 6},
{4, 3, 8}
}


然后设定hiddenX=2, hiddenY=2,使得右下角current[2][2]的方格被隐藏。

要取得某个方格对应的Image对象,我们用

public Image getCurrentImage(int x, int y) {
if( (x==hiddenX) && (y==hiddenY) )
return null;
return images[current[x][y]];
}


对于位于(hiddenX, hiddenY)位置的方格,返回null表示不显示该方格。

如何判断拼图是否完成?

当current[][]数组的内容按照{0, 1, 2}, {3, 4, 5}, {6, 7, 8}排列时,表示该拼图已经拼好,因此,判断代码非常简单:

public boolean isFinish() {
for(int i=0; i<3; i++) {
for(int j=0; j<3; j++) {
if(current[i][j]!=(i*3+j))
return false;
}
}
return true;
}


当用户移动某个方格时,Document接收方格位置(x, y)并负责判断能否移动,如果能,更新current[][]的数据和hiddenX, hiddenY,并返回true表示数据已更新,否则返回false表示不可移动。

public boolean move(int x, int y) {
// 如果用户试图移动隐藏方格,直接返回false:
if(hiddenX==x && hiddenY==y)
return false;

// 如果方格位于(hiddexX, hiddenY)的相邻位置,
// 交换该方格(x, y)和(hiddenX, hiddenY)的相关数据:
boolean moved = false;
if( ((x-1)==hiddenX) && (y==hiddenY) ) {
sweep(x, y);
moved = true;
}
if( ((x+1)==hiddenX) && (y==hiddenY) ) {
sweep(x, y);
moved = true;
}
if( (x==hiddenX) && ((y-1)==hiddenY) ) {
sweep(x, y);
moved = true;
}
if( (x==hiddenX) && ((y+1)==hiddenY) ) {
sweep(x, y);
moved = true;
}
if(moved) {
steps++;
if(isFinish()) {
// TODO...
}
updatable.update();
}
}

private void sweep(int x, int y) {
int temp = current[x][y];
current[x][y] = current[hiddenX][hiddenY];
current[hiddenX][hiddenY] = temp;
hiddenX = x;
hiddenY = y;
}


至此,Document类基本完成。Document不涉及任何显示功能,仅仅存储和更新数据,并在恰当的时候通知View更新显示。

实现View

在MIDP中,View就是Screen或者Canvas,在这个游戏中,我们应该使用Canvas,定义:

public class MainCanvas extends Canvas implements CommandListener, Updatable { ... }

在构造方法中,初始化Document:

public MainCanvas(String imageName) {
// 读图像:
Image[] images = new Image[9];
for(int i=0; i<9; i++) {
try {
images[i] = Image.createIm

[1] [2]  下一页

[] [返回上一页] [打 印]
文章评论

用户名: 查看更多评论

分 值:100分 85分 70分 55分 40分 25分 10分 0分

内 容:

         (注“”为必填内容。) 验证码: 验证码,看不清楚?请点击刷新验证码