赛迪网 > IT技术 Java > (最新更新)Java基础
  IT资讯搜索
 
IT产品搜索
[程序开发][网管世界][网络安全][数据库技术]
[操作系统][嘉宾聊天·在线访谈][活动集锦]
[精彩专题][Symantec专区][订阅IT技术周刊]
[开发论坛][网管论坛][安全论坛][数据库论坛]
[操作系统论坛][Sybase专区][IBM dW技术专区]
[病毒求助][病毒与漏洞播报][文档·源码下载]

J2ME再现华容道 (3)

发布时间:2006.04.03 15:00     来源:www.0240.cn    作者:

看看时间还早,我在这里简单介绍一下MIDlet1类,这个类和前面介绍的"Hello World"中的内容大同小异,先看一下程序代码:

其中startApp().pauseApp()和destroyApp()三个函数时MIDlet类的三个抽象方法必须要被重载一边,他们控制着一个J2ME程序的开始.暂停和结束.而其中的Displayable1 就是我们前面提到的Displayable1的一个实例,用来负责显示程序的用户界面和控制程序逻辑.这个类一般都是写成这样.


两天的时间稍稍还有些富裕,今天可以早放工.


六.编码


整个项目共有五个类,有四个类的代码前面已经介绍过了,而且是在其他项目中使用过的相对成熟的代码.现在只需全力去实现Displayable1类.Displayable1类的代码如下:


package huarongroad;



import javax.microedition.lcdui.*;



public class Displayable1 extends Canvas implements CommandListener {



private int[] loc = new int[2]; file://光标的当前位置,0是水平位置,1是竖直位置


private int[] SelectArea = new int[4];//被选定的区域,即要移动的区域


private int[] MoveArea = new int[4];//要移动到的区域


private Map MyMap = new Map();//地图类


private boolean selected;//是否已经选中要移动区域的标志


private int level;//但前的关面


public Displayable1() {//构造函数


try {


jbInit();//JBuilder定义的初始化函数


}catch (Exception e) {


e.printStackTrace();


}


}


private void Init_game(){


//初始化游戏,读取地图,设置选择区域,清空要移动到的区域


this.loc = MyMap.read_map(this.level);//读取地图文件,并返回光标的初始位置


//0为水平位置,1为竖直位置


this.SelectArea[0] = this.loc[0];//初始化选中的区域


this.SelectArea[1] = this.loc[1];


this.SelectArea[2] = 1;


this.SelectArea[3] = 1;


this.MoveArea[0] = -1;//初始化要移动到的区域


this.MoveArea[1] = -1;


this.MoveArea[2] = 0;


this.MoveArea[3] = 0;


}


private void jbInit() throws Exception {//JBuilder定义的初始化函数


file://初始化实例变量


this.selected = false;//设置没有被选中的要移动区域


this.level = 1;


Images.init();//初始化图片常量


Init_game();//初始化游戏,读取地图,设置选择区域,清空要移动到的区域


setCommandListener(this);//添加命令监听,这是Displayable的实例方法


addCommand(new Command("Exit", Command.EXIT, 1));//添加“退出”按钮


}



public void commandAction(Command command, Displayable displayable) {


//命令处理函数


if (command.getCommandType() == Command.EXIT) {//处理“退出”


MIDlet1.quitApp();


}


}



protected void paint(Graphics g) {


//画图函数,用于绘制用户画面,即显示图片,勾画选中区域和要移动到的区域


try {


g.drawImage(Images.image_Frame, 0, 0,


Graphics.TOP | Graphics.LEFT);//画背景


MyMap.draw_map(g);//按照地图内容画图


if ( this.selected )


g.setColor(0,255,0);//如果被选中,改用绿色画出被选中的区域


g.drawRect(this.SelectArea[0] * Images.UNIT + Images.LEFT,


this.SelectArea[1] * Images.UNIT + Images.TOP,


this.SelectArea[2] * Images.UNIT,


this.SelectArea[3] * Images.UNIT);//画出选择区域,


file://如果被选中,就用绿色


file://否则,使用黑色


g.setColor(255,255,255);//恢复画笔颜色


if (this.selected) {//已经选中了要移动的区域


g.setColor(255, 0, 255);//改用红色


g.drawRect(this.MoveArea[0] * Images.UNIT + Images.LEFT,


this.MoveArea[1] * Images.UNIT + Images.TOP,


this.MoveArea[2] * Images.UNIT,


this.MoveArea[3] * Images.UNIT);//画出要移动到的区域


g.setColor(255, 255, 255);//恢复画笔颜色


}


}catch (Exception ex) {


}


System.out.println(Runtime.getRuntime().freeMemory());


System.out.println(Runtime.getRuntime().totalMemory());


}



private void setRange() {


//设置移动后能够选中的区域


//调整当前光标位置到地图的主位置,即记录人物信息的位置


if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFT) {


this.loc[0] -= 1;//向左调


}else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DUP) {


this.loc[1] -= 1;//向上调


}else if (this.MyMap.Grid[this.loc[1]][this.loc[0]] == Images.DLEFTUP) {


this.loc[0] -= 1;//向左调


this.loc[1] -= 1;//向上调


}


this.SelectArea[0] = this.loc[0];//设置光标的水平位置


this.SelectArea[1] = this.loc[1];//设置光标的竖直位置


//设置光标的宽度


if (this.loc[0] + 1 < Images.WIDTH) {


this.SelectArea[2] = this.MyMap.Grid[this.loc[1]][this.loc[0] + 1] != (byte) ′1′ ?


1 : 2;


}else {


this.SelectArea[2] = 1;


}


//设置光标的高度


if (this.loc[1] + 1 < Images.HEIGHT) {


this.SelectArea[3] = this.MyMap.Grid[this.loc[1] + 1][this.loc[0]] != (byte) ′2′ ?


1 : 2;


}else {


this.SelectArea[3] = 1;


}


}



private boolean setMoveRange() {


//设置要移动到的区域,能够移动返回true,否则返回false


for (int i = 0; i < this.SelectArea[2]; i++) {


for (int j = 0; j < this.SelectArea[3]; j++) {


if (this.loc[1] + j >= Images.HEIGHT ||


this.loc[0] + i >= Images.WIDTH ||


(!isInRange(this.loc[0] + i, this.loc[1] + j) &&


this.MyMap.Grid[this.loc[1] + j][this.loc[0] + i] !=


Images.BLANK)) {


return false;


}


}


}


this.MoveArea[0] = this.loc[0];


this.MoveArea[1] = this.loc[1];


this.MoveArea[2] = this.SelectArea[2];


this.MoveArea[3] = this.SelectArea[3];


return true;


}



private boolean isInRange(int x, int y) {


//判断给定的(x,y)点是否在选定区域之内,x是水平坐标,y是竖直坐标


if (x >= this.SelectArea[0] &&


x < this.SelectArea[0] + this.SelectArea[2] &&


y >= this.SelectArea[1] &&


y < this.SelectArea[1] + this.SelectArea[3]) {


return true;


}else {


return false;


}


}



private boolean isInRange2(int x, int y) {


//判断给定的(x,y)点是否在要移动到的区域之内,x是水平坐标,y是竖直坐标


if (x >= this.MoveArea[0] &&


x < this.MoveArea[0] + this.MoveArea[2] &&


y >= this.MoveArea[1] &&


y < this.MoveArea[1] + this.MoveArea[3]) {


return true;


}else {


return false;


}


}



protected void keyPressed(int keyCode) {


//处理按下键盘的事件,这是Canvas的实例方法


switch (getGameAction(keyCode)) {//将按键的值转化成方向常量


case Canvas.UP://向上


if (!this.selected) {//还没有选定要移动的区域


if (this.loc[1] - 1 >= 0) {//向上还有移动空间


this.loc[1]--;//向上移动一下


setRange();//设置光标移动的区域,该函数能将光标移动到地图主位置


repaint();//重新绘图


}


}else {//已经选定了要移动的区域


if (this.loc[1] - 1 >= 0) {//向上还有移动空间


this.loc[1]--;//向上移动一下


if (setMoveRange()) {//能够移动,该函数能够设置要移动到的区域


repaint();//重新绘图


}else {//不能移动


this.loc[1]++;//退回来


}


}


}


break;


case Canvas.DOWN://向下


if (!this.selected) {//还没有选定要移动的区域


if (this.loc[1] + 1 < Images.HEIGHT) {//向下还有移动空间


if (this.MyMap.Grid[this.loc[1] + 1][this.loc[0]] ==


Images.DUP){//该图片有两个格高


this.loc[1]++;//向下移动一下


if (this.loc[1] + 1 < Images.HEIGHT) {//向下还有


file://移动空间


this.loc[1]++;//向下移动一下


setRange();//设置光标移动的区域,


file://该函数能将光标移动到地图主位置


repaint();//重新绘图


}else {//向下没有移动空间


this.loc[1]--;//退回来


}


}else {//该图片只有一个格高


this.loc[1]++;//向下移动一下


setRange();//设置光标移动的区域,


file://该函数能将光标移动到地图主位置


repaint();//重新绘图


}


}else {


}


}else {//已经选定了要移动的区域


if (this.loc[1] + 1 < Images.HEIGHT) {//向下还有移动空间


this.loc[1]++;//向下移动一下


if (setMoveRange()) {//能够移动,该函数能够设置要移动到的区域


repaint();//重新绘图


}else {//不能移动


this.loc[1]--;//退回来


}


}


}


break;


case Canvas.LEFT://向左


if (!this.selected) {//还没有选定要移动的区域


if (this.loc[0] - 1 >= 0) {//向左还有移动空间


this.loc[0]--;//向左移动一下


setRange();//设置光标移动的区域,该函数能将光标移动到地图主位置


repaint();//重新绘图


}


}else {//已经选定了要移动的区域


if (this.loc[0] - 1 >= 0) {//向左还有移动空间


this.loc[0]--;//向左移动一下


if (setMoveRange()) {//能够移动,该函数能够设置要移动到的区域


repaint();//重新绘图


}else {//不能移动


this.loc[0]++;//退回来


}


}


}


break;


case Canvas.RIGHT://向右


if (!this.selected) {//还没有选定要移动的区域


if (this.loc[0] + 1 < Images.WIDTH) {//向右还有移动空间


if (this.MyMap.Grid[this.loc[1]][this.loc[0] + 1] ==


Images.DLEFT) {//该图片有两个格宽


this.loc[0]++;//向右移动一下


if (this.loc[0] + 1 < Images.WIDTH) {//向右还有


file://移动空间


this.loc[0]++;//向右移动一下


setRange();//设置光标移动的区域,


file://该函数能将光标移动到地图主位置


repaint();//重新绘图


}else {//向右没有移动空间


this.loc[0]--;//退回来


}


}else {//该图片只有一个格宽


this.loc[0]++;//向右移动一下


setRange();//设置光标移动的区域,


file://该函数能将光标移动到地图主位置


repaint();//重新绘图


}


}else {


}


}else {//已经选定了要移动的区域


if (this.loc[0] + 1 < Images.WIDTH) {//向右还有移动空间


this.loc[0]++;//向右移动一下


if (setMoveRange()) {//能够移动,该函数能够设置要移动到的区域


repaint();//重新绘图


}else {//不能移动


this.loc[0]--;//退回来


}


}


}


break;


case Canvas.FIRE:


if (this.selected) {//已经选定了要移动的区域


Move();//将要移动的区域移动到刚选中的区域


repaint();//重新绘图


this.selected = false;//清除已选定要移动区域的标志


if ( win()) {


System.out.println("win");


}


}else {//还没有选定要移动的区域


if (this.MyMap.Grid[this.loc[1]][this.loc[0]] ==


Images.BLANK) {//要移到的位置是一个空白


}else {//要移到的位置不是空白


this.selected = true;//设置已选定要移动区域的标志


}


repaint();//重新绘图


}


break;


}


}



private boolean win(){


file://判断是否已经救出了曹操


if ( this.MyMap.Grid[Images.HEIGHT - 2 ][Images.WIDTH - 3 ] == Images.CAOCAO )


return true;


else


return false;


}



private void PrintGrid(String a) {


file://打印当前地图的内容,用于调试


System.out.println(a);


for (int i = 0; i < Images.HEIGHT; i++) {


for (int j = 0; j < Images.WIDTH; j++) {


System.out.print( (char)this.MyMap.Grid[i][j]);


}


System.out.println("");


}


}



private void Move() {


file://将要移动的区域移动到刚选中的区域


if (this.MoveArea[0] == -1 || this.MoveArea[1] == -1 ||


this.SelectArea[0] == -1 || this.SelectArea[1] == -1) {//没有选中区域


}else {//已经选中了要移动的区域和要移动到的区域


byte[][] temp = new byte[this.SelectArea[3]][this.SelectArea[2]];


file://复制要移动的区域,因为这块区域可能会被覆盖掉


for (int i = 0; i < this.SelectArea[2]; i++) {


for (int j = 0; j < this.SelectArea[3]; j++) {


temp[j][i] =


this.MyMap.Grid[this.SelectArea[1] +j]


[this.SelectArea[0] + i];


}


}


file://PrintGrid("1"); // 调试信息


file://将要移动的区域移动到刚选中的区域(即要移动到的区域)


for (int i = 0; i < this.SelectArea[2]; i++) {


for (int j = 0; j < this.SelectArea[3]; j++) {


this.MyMap.Grid[this.MoveArea[1] + j]


[this.MoveArea[0] + i] = temp[j][i];


}


}


file://PrintGrid("2");// 调试信息


file://将要移动的区域中无用内容置成空白


for (int i = 0; i < this.SelectArea[3]; i++) {


for (int j = 0; j < this.SelectArea[2]; j++) {


if (!isInRange2(this.SelectArea[0] + j,


this.SelectArea[1] + i)) {//该点是不在要移动到


file://的区域之内,需置空


this.MyMap.Grid[this.SelectArea[1] + i]


[this.SelectArea[0] + j] = Images.BLANK;


}else {


}


}


}


file://PrintGrid("3");// 调试信息


this.SelectArea[0] = this.MoveArea[0];//重置选中位置的水平坐标


this.SelectArea[1] = this.MoveArea[1];//重置选中位置的竖直坐标


this.MoveArea[0] = -1;//清空要移动到的位置


this.MoveArea[1] = -1;//清空要移动到的位置


this.MoveArea[2] = 0;//清空要移动到的位置


this.MoveArea[3] = 0;//清空要移动到的位置


}


}


}


代码的相关分析,在详细设计阶段已经讲过,代码中有比较相近的注释,请读者自行研读分析.将全部的代码写好,用wtk2.0自带的Ktoolbar工具建立一个工程,接下来把去不源文件放到正确位置下,然后点击build,再点run,就完成了程序的编写.当然如果有错误还要修改和调试.


经过两天的痛苦煎熬,程序终于有了眉目,编码阶段初战告捷.


七、测试


作为一个真正的产品要经过单体测试、结合测试和系统测试。由于项目本身简单,而且大部分代码已经是相对成熟的,我们跳过单体测试;又由于笔者的实际环境所限,无法搞到Java手机,无法架设OTA服务器,因此我们也只能放弃系统测试。那么就让我们开始结合测试吧。测试之前要先出一个测试式样书,也就是测试的计划。我们将它简化一下,只测试如下几种情况:第一、对各种形状的区域的选择和移动;第二、临近边界区域的选择和移动;第三、同一区域的反复选择和反复移动;第四、非法选择和非法移动。有了测试的目标,接下来的工作就是用wtk2.0自带的Run MIDP Application工具进行测试。打开这个工具,加载huarongRoad的jad文件,程序就会自动运行,选择launch上MIDlet1这个程序,华容道游戏就会跃然屏幕之上,接下来的工作就是左三点.右三点,拇指扭扭,来做测试。测试过程中发现任何的问题,立刻发一个bug票给自己,然后就又是痛苦的调试和修正bug,如此如此。


两日过后,程序日渐成熟起来,笔者也日渐消瘦下去,还好熬了过来。


八.发布


谈到发布,其实是个关键,再好的产品不能很好的发布出去也只是个产品而已,变不成商品也就得不到回报.由于笔者的条件所限,这里只能是纸上谈兵,不过还是希望能够使读者对这一过程有所了解(网上的资料也很多)。


J2ME的程序发布一般都是通过OTA(Over The Air),你只需要一台有公网IP的主机和一个普通的web Server就可以了(尽管要求很低,但笔者还是没有),这里我们以apache为例介绍一下OTA服务的配置,首先是安装好了apache服务器,然后在conf目录下找到mime.types文件,在该文件中加入如下两行


application/java-archive jar


text/vnd.sun.j2me.app-descriptor jad


然后重起apache服务器就可以了。接下来的工作就是修改jad文件中MIDlet-Jar-URL:后面的参数,将它改为URL的绝对路径,即http://***/huarongroad.jar(其中***是你的域名或IP地址)。在下面就是用java手机下载jad文件,它会自动部署相应的jar文件并加载它。剩下的工作就和在模拟器上操作是一样的了。


<<上一页 1 2 3


[ 发表评论 ] 字体[  ] [ 打印 ] [ 进入博客 ] [ 进入论坛 ]  [ 推荐给朋友 ]
  相关文章
· J2ME游戏开发技巧 (04-03) · J2ME平台简介 (04-03)
· NetBeans 4.0创建J2ME手机RSS阅读器 (04-03) · J2ME开发站点资源 (04-03)
· 使用J2ME与MIDP进行手机开发的全工略 (04-03) · 用简单的J2ME程序测试MIDlet生命周期 (04-03)
· J2ME中使用记录存储系统(RMS)存储信息 (04-03) · MVC模式在J2ME项目中的实际应用 (04-03)
· 在J2ME手机编程中内存的优化三招 (04-03) · J2ME开发中记录管理系统的详细介绍 (04-03)
  客户需求反馈表
* 姓  名:
更多资料  了解方案  认识厂商
* 单位名称:
* 联系电话:
* 电子邮件:
  赛迪推荐  
  手机·资费 ·新品·导购·评测·手机资费·宽带
手机搜索  诺基亚 N73 MOTO Z6
  IT产品 ·笔记本·台式机·服务器·打印·投影
IT产品搜索 
  IT技术 ·开发·网管·安全·数据库·操作系统
  信息化 ·热点·专题·访谈·周刊·方案案例
· 北京新规不能霸王硬上弓 网店牌照缓期执行
· 软件外包之变的新台阶: 提高全球交付能力
· ERP案例分析 SaaS带来冲击 IT服务商面临挑战
· 通方期货CRM解决方案 房地产行业CRM解决方案
  IT博客 ·曾剑秋·项立刚·Java学习·网管
  IT技术论坛 ·开发·网管·安全·数据库·系统