如果问你个问题,小时候玩的最多的是什么游戏,我想,你肯定会立刻回答,俄罗斯方块,后来随着时间的推移,各种方块类游戏层出不穷,下面笔者将要介绍的一款游戏,也可以归结到俄罗斯方块类游戏的范畴里去。由于最近看这方面的代码比较多,所以参考了一下多种方案,自己也来了个创新。
笔者把这款游戏命名为开心药丸,下面开始做简单介绍:
游戏名:开心药丸
运行平台:MIDP1.0
游戏方法介绍:
游戏屏幕上方会随机掉下由两个方块组成的方块组,每个方块从红黄蓝绿四种颜色中随机产生一种,这样共有4*4=16种组合方式,(是不是很象我们感冒时吃的胶囊!这就是名字的由来),每4个相同的颜色组合在一起的方块会自动消去,随着游戏的不断发展,速度会不断提高,直到GAMEOVER......
在进行开发之前我们要画出程序的流程图:
笔者把这款游戏命名为开心药丸,下面开始做简单介绍:
游戏名:开心药丸
运行平台:MIDP1.0
游戏方法介绍:
游戏屏幕上方会随机掉下由两个方块组成的方块组,每个方块从红黄蓝绿四种颜色中随机产生一种,这样共有4*4=16种组合方式,(是不是很象我们感冒时吃的胶囊!这就是名字的由来),每4个相同的颜色组合在一起的方块会自动消去,随着游戏的不断发展,速度会不断提高,直到GAMEOVER......
在进行开发之前我们要画出程序的流程图:
JAVA手机网[www.cnjm.net]
下面我们就这个游戏来介绍以下类的结构:
笔者设计的是
SquareMIDlet:主程序,对整个游戏的生命周期进行控制。
JAVA手机网[www.cnjm.net]
Piece:存储各个方块组合的详细参数。
GameCanvas:这是精华所在,对这个画面的绘制和操作包含在这个类里,大家千万要注意,这是笔者自己写的GameCanvas,千万不要和MIDP2.0里的game包弄混淆。
具体实现详解:
首先从主程序入手: 在设计的时候我们不需要为这个类添加太多的功能,我们只需要在在这个类里面加入适当的控制机制,对整个游戏的生命周期进行控制,太多的代码会导致游戏结构的混乱。
我们这个系列文章将会围绕这三个关键类进行描述,先看一看主程序:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class SquareMIDlet extends MIDlet
{
public void SquareMIDlet()
{
GameCanvas:这是精华所在,对这个画面的绘制和操作包含在这个类里,大家千万要注意,这是笔者自己写的GameCanvas,千万不要和MIDP2.0里的game包弄混淆。
具体实现详解:
首先从主程序入手: 在设计的时候我们不需要为这个类添加太多的功能,我们只需要在在这个类里面加入适当的控制机制,对整个游戏的生命周期进行控制,太多的代码会导致游戏结构的混乱。
我们这个系列文章将会围绕这三个关键类进行描述,先看一看主程序:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class SquareMIDlet extends MIDlet
{
public void SquareMIDlet()
{
JAVA手机网[www.cnjm.net]
gc=new GameCanvas(this);
display=Display.getDisplay(this);
display.setCurrent(gc);
}
display=Display.getDisplay(this);
display.setCurrent(gc);
}
JAVA手机网[www.cnjm.net]
public void startApp()
{
gc.start();
}
public void pauseApp()
JAVA手机网[www.cnjm.net]
{
gc.pause();
}
public void destroyApp(boolean unconditional)
gc.pause();
}
public void destroyApp(boolean unconditional)
JAVA手机网[www.cnjm.net]
{}
void Exit()
{
try
void Exit()
{
try
JAVA手机网[www.cnjm.net]
{
destroyApp(false);
notifyDestroyed();
}catch(Exception e){}
destroyApp(false);
notifyDestroyed();
}catch(Exception e){}
JAVA手机网[www.cnjm.net]
}
private GameCanvas gc;
private Display display;
}
在此 我们给出相应的主程序的UML图 方便读者了解整个游戏的架构!~
很明显,我们通过调用GameCanvas里的开始(start)和暂停(pause)等等方法来控制程序的状态。
接着我们来设计 Piece 这个类,它的作用是什么呢,它是存储单个方块信息的类,(我们的药丸由两个方块组成,即两个 Piece 的随机组合)该类的核心之一便是如何判断在方块落下之后和左右上下相邻的方块之间的颜色是否相同,相同即消去之间的边界线,不相同即需要在它们之间描绘上一条边界线。这样一个设计需要 4 个布尔值来进行判断,还需要定义好方块的高度和宽度(不同的手机的屏幕大小不一,在实际开发过程当中要注意好这样的问题)。
在看代码之前 大家先看一下UML图对整个类有个大致的了解~
private GameCanvas gc;
private Display display;
}
在此 我们给出相应的主程序的UML图 方便读者了解整个游戏的架构!~
很明显,我们通过调用GameCanvas里的开始(start)和暂停(pause)等等方法来控制程序的状态。
接着我们来设计 Piece 这个类,它的作用是什么呢,它是存储单个方块信息的类,(我们的药丸由两个方块组成,即两个 Piece 的随机组合)该类的核心之一便是如何判断在方块落下之后和左右上下相邻的方块之间的颜色是否相同,相同即消去之间的边界线,不相同即需要在它们之间描绘上一条边界线。这样一个设计需要 4 个布尔值来进行判断,还需要定义好方块的高度和宽度(不同的手机的屏幕大小不一,在实际开发过程当中要注意好这样的问题)。
在看代码之前 大家先看一下UML图对整个类有个大致的了解~
JAVA手机网[www.cnjm.net]
JAVA手机网[www.cnjm.net]
核心代码如下:
/*
*
* @author 夏彦端
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
import javax.microedition.lcdui.*;
class Piece
{
int currentcolor=0x00ffffff;
/*
*
* @author 夏彦端
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
import javax.microedition.lcdui.*;
class Piece
{
int currentcolor=0x00ffffff;
JAVA手机网[www.cnjm.net]
/**
* 先定义四种基本颜色的常量,当然如果你认为让游戏更复杂一些才好玩,可以在这里适当的加上
* 其他的颜色 ~
*/
static final int red=0x00ff0000;
static final int green=0x0000ff00;
static final int blue=0x000000ff;
static final int yellow=0x00ffff00;
/**
* 下面需要定义我们的四个布尔函数值,来进行和周围方块的判别
*
*/
boolean isup =false;
boolean isdown=false;
boolean isleft=false;
boolean isright=false;
* 先定义四种基本颜色的常量,当然如果你认为让游戏更复杂一些才好玩,可以在这里适当的加上
* 其他的颜色 ~
*/
static final int red=0x00ff0000;
static final int green=0x0000ff00;
static final int blue=0x000000ff;
static final int yellow=0x00ffff00;
/**
* 下面需要定义我们的四个布尔函数值,来进行和周围方块的判别
*
*/
boolean isup =false;
boolean isdown=false;
boolean isleft=false;
boolean isright=false;
JAVA手机网[www.cnjm.net]
/**
* 下面需要定义方块的宽度和高度,注意这里的宽度和高度需要是可被你游戏实际屏幕的高度和宽度
* 整除的数字,否则会带来不必要的麻烦 ~
*
*/
JAVA手机网[www.cnjm.net]
static int width=12;
static int height=12;
void drawPiece(Graphics g,int x,int y)
static int height=12;
void drawPiece(Graphics g,int x,int y)
JAVA手机网[www.cnjm.net]
{
g.setColor(this.currentcolor);
g.fillRect(x,y,width,height);
g.setColor(this.currentcolor);
g.fillRect(x,y,width,height);
JAVA手机网[www.cnjm.net]
g.setColor(0,0,0);
if(!isup)
if(!isup)
JAVA手机网[www.cnjm.net]
{
g.drawLine(x,y,x+width,y);
}
if(!isdown)
{
g.drawLine(x,y+height,x+width,y+height);
}
if(!isright)
{
g.drawLine(x+width,y,x+width,y+height);
g.drawLine(x,y,x+width,y);
}
if(!isdown)
{
g.drawLine(x,y+height,x+width,y+height);
}
if(!isright)
{
g.drawLine(x+width,y,x+width,y+height);
JAVA手机网[www.cnjm.net]
}
if(!isleft)
{
g.drawLine(x,y,x,y+height);
}
}
if(!isleft)
{
g.drawLine(x,y,x,y+height);
}
}
JAVA手机网[www.cnjm.net]
}
这里我并没将 currentcolor 以及四个布尔值这些变量设置为封装访问,或许一些 OO 设计的 FANS 会质疑我的做法,但是因为我们这是在手机上写程序,而不是在 PC 上,有充足的处理机供你调度,我们如果另外再写个方法来给外部访问 currentcolor 的话,会给程序在手机上运行造成不必要的负担,所以我们没有对 currentcolor 这个变量进行任何额外的特殊处理。
这里我并没将 currentcolor 以及四个布尔值这些变量设置为封装访问,或许一些 OO 设计的 FANS 会质疑我的做法,但是因为我们这是在手机上写程序,而不是在 PC 上,有充足的处理机供你调度,我们如果另外再写个方法来给外部访问 currentcolor 的话,会给程序在手机上运行造成不必要的负担,所以我们没有对 currentcolor 这个变量进行任何额外的特殊处理。
JAVA手机网[www.cnjm.net]
现在我们进入本游戏最核心的设计部分, GameCanvas 类的设计!
毋庸质疑我们的 GameCanvas 会实现 Runnable,CommandListener 这两个接口,还必须定义好几个和游戏状态相关的常量,并对游戏的初始化进行处理,这里我想提一下初始化,这是曾经最让我头痛的地方,因为这里要设置好 N 多的变量,而且必须要对他们进行适当的初始化,否则整个程序都会出问题,拿这个游戏来说,我们必须定义好如下几个常量:
存储分数的变量, Piece 数组,方块组落下速度调整变量 speed, 方块组落下时间的变量 time, 落下次数 count, 循环标志 isstop, 判断是否需要下一个方块组落下的变量 isfall, 判断按键是否有效的变量 iskey 。
怎么样,是否头很大?):在进行游戏设计之前我们必须设计好一些必须的变量,并且对其初始化,从而实现对整个游戏的流程控制。
接下来,我们需要对游戏的命令处理部分进行设计,正如我们前面流程图所画的过程,我们的几个必须命令为开始命令 start, 离开命令 exit, 暂停命令 pause, 继续命令 resume, 还有一个离开命令 quit 。( exit 是在标题画面的是否和 start 配对使用,而 quit 则是对整个游戏的退出时起作用。)
毋庸质疑我们的 GameCanvas 会实现 Runnable,CommandListener 这两个接口,还必须定义好几个和游戏状态相关的常量,并对游戏的初始化进行处理,这里我想提一下初始化,这是曾经最让我头痛的地方,因为这里要设置好 N 多的变量,而且必须要对他们进行适当的初始化,否则整个程序都会出问题,拿这个游戏来说,我们必须定义好如下几个常量:
存储分数的变量, Piece 数组,方块组落下速度调整变量 speed, 方块组落下时间的变量 time, 落下次数 count, 循环标志 isstop, 判断是否需要下一个方块组落下的变量 isfall, 判断按键是否有效的变量 iskey 。
怎么样,是否头很大?):在进行游戏设计之前我们必须设计好一些必须的变量,并且对其初始化,从而实现对整个游戏的流程控制。
接下来,我们需要对游戏的命令处理部分进行设计,正如我们前面流程图所画的过程,我们的几个必须命令为开始命令 start, 离开命令 exit, 暂停命令 pause, 继续命令 resume, 还有一个离开命令 quit 。( exit 是在标题画面的是否和 start 配对使用,而 quit 则是对整个游戏的退出时起作用。)
JAVA手机网[www.cnjm.net]
命令部分的代码如下 :
private Command start = new Command("Start", Command.SCREEN, 2);
private Command exit = new Command("Exit", Command.SCREEN, 1);
private Command pause = new Command("Pause", Command.SCREEN, 2);
private Command resume = new Command("Resume", Command.SCREEN, 2);
private Command quit = new Command("Quit", Command.SCREEN, 1);
相应的命令处理部分为:
JAVA手机网[www.cnjm.net]
public void commandAction(Command c, Displayable s) {
if(c == start) {
doGameInit();
JAVA手机网[www.cnjm.net]
gameState = GAME_START;
doThreadStart();
}else if(c == exit) {
square.Exit();
doThreadStart();
}else if(c == exit) {
square.Exit();
JAVA手机网[www.cnjm.net]
}else if(c == pause) {
removeCommand(pause);
addCommand(resume);
doPauseOrResume();
}else if(c == resume) {
removeCommand(pause);
addCommand(resume);
doPauseOrResume();
}else if(c == resume) {
JAVA手机网[www.cnjm.net]
removeCommand(resume);
addCommand(pause);
doPauseOrResume();
}else if(c == quit) {
doGameStop();
removeCommand(pause);
removeCommand(resume);
removeCommand(quit);
doTitle();
}
}
addCommand(pause);
doPauseOrResume();
}else if(c == quit) {
doGameStop();
removeCommand(pause);
removeCommand(resume);
removeCommand(quit);
doTitle();
}
}
JAVA手机网[www.cnjm.net]
我们需要特别注意的是同一时刻能够在屏幕上同时显示的命令有哪几个,比如说当我们在按下 quit 后屏幕上就无须显示 pause,resume,quit ,因为此时我们已经基本上选择了离开游戏,还有在命令处理函数里面我们在每个命令按下后都会出发相应的处理函数,我们留在下一篇文章介绍这些函数的写法。