《J2ME手机游戏开发技术》实验报告实验名称:益智类游戏——炸弹人一. 实验目的 利用J2ME有关知识,设计一款益智类(PUZ)炸弹人(Bombman)游戏程序,是我们能够掌握JavaME游戏开发的基本技巧二. 实验环境 Windows 7操作系统,Eclipse,WTK2.5.1,JDK1.6三. 实验内容 利用自己所学的J2ME知识,进行游戏开发,该游戏的创意是游戏主角在一个随机生存的地图中放置炸弹,以消灭地图中所有的敌人为目的游戏地图被设计成一个多行多列的棋盘,游戏中的主角和敌人每次都只能按照棋盘中相邻的棋盘格进行移动,而且在地图中还存在不同的障碍物,用来阻挡游戏主角和敌人的移动游戏主角可以在没有障碍物的地方防止炸弹来引爆敌人或障碍物来获得去路从中有以下是几个元素的详细功能:(1) 空白区:是游戏主角和敌人可以移动的位置及放置炸弹的位置2) 岩石:地图中的障碍物,用来阻止游戏主角和敌人的且不能被炸弹摧毁3) 砖墙:也是用来阻止的,不过能被炸弹摧毁变成空白区4) 敌人:是消灭游戏主角的一方,它需要游戏主角用炸弹将其炸死,其所处 的地方也会变为空白区,敌人在空白区来去自如,一旦碰到游戏主 角,游戏主角会被杀死。
5) 游戏主角:游戏中由玩家控制的一方,在空白区移动,可以放置炸弹四. 实验步骤(代码分析) 该游戏是一个11*11的棋盘,用一个char型的二维数组来表示该棋盘,二维数组中的每一个数组元素就代表了游戏棋盘中的一个棋盘格该游戏采用面向对象的程序设计方法,主要的功能都封装到不同的类中,定义了以下几个类:1.Board类:该类作为程序的模型定义类,在其中定义了游戏中所使用的数 据结构以及对这些数据结构中的数据进行设置和获取的方法2.BoardView类:该类作为程序的视图定义类,也是游戏的画布屏幕类,在 该类中定义了如何根据用户的游戏动作绘制对应的游戏运 行画面的方法3. Bomb类:该类表示游戏中的炸弹,定义了如何显示炸弹的爆炸效果以及炸 弹爆炸后对其他相关元素的影响的方法4.Enemy类:该类表示游戏中的敌人,具体定义了敌人如何移动以及判断敌 人是否死亡的方法5.Player类:该类表示游戏中的主角,定义了游戏主角如何移动、如何防止 炸弹以及判断游戏是否死亡的方法。
6.Img类:该类定义了游戏中各种图像的构造方法7.jBombMan类:该类是程序的MIDlet类1)jBombMan.java private Display oDisplay; //屏幕对象 private BoardView oBoardView; //棋盘视图对象 private Board oBoard; //棋盘对象 private Player oPlayer; //主角对象 private Enemy oEnemy; //敌人对象(2) Board.java //定义棋盘的二维数组 public char[ ][ ] chBoard; /* N - None 表示什么也没有 W - Wall 表示砖墙 L - Pillar 表示岩石 P - Player 表示游戏主角 E - Enemy 表示敌人 B - Bomb 表示炸弹 U - Bomb under player 表示主角正在放置炸弹 X - Exploding 表示炸弹爆炸 */ //声明一个随机数对象 private Random random; //声明棋盘的行和列数 public int iCols, iRows; //声明判断游戏是否结束的标识 public volatile boolean isGameOver; //声明判断是否玩家胜利的标识 public volatile boolean isWin; //构造函数,初始化棋盘的行数和列数,并构造随机数对象 public Board( int cols, int rows ) //定义棋盘的初始化方法 public void init() //判断某个棋盘格中是否是给定的元素 public boolean isElement( char ch, int x, int y ) //获取指定的某个棋盘格中的元素 public char getElement( int x, int y ) //设置指定的某个棋盘格中的元素 public void setElement( char ch, int x, int y ) //判断给定的位置是否在敌人的攻击范围内 public boolean near( char ch, int x, int y ) //判断给定的位置是否可以向某个方向移动2步 public boolean near2( char ch, int x, int y ) (3)BoardView.javaprivate Board oBoard;private Player oPlayer;private Enemy oEnemy;//定义背景色private final int BackgroundColor = 0xffffff;//定义每个棋盘格的大小private final int iCellSize = 20;//声明内部边框距离坐标原点的横坐标距离private final int iLeft = 10;//声明内部边框距离坐标原点的纵坐标距离private final int iTop = 10; public BoardView( Board board )public void setPlayer( Player player )public void setEnemy( Enemy enemy )//绘制游戏屏幕public void paint( Graphics g )//定义绘制游戏结束的方法private void paintGameOver( Graphics g )//定义绘制游戏玩家获胜的方法private void paintWin( Graphics g )//绘制游戏棋盘边框的方法private void paintFrame( Graphics g )//定义绘制棋盘的方法private void paintBoard( Graphics g )//定义响应按键按下的事件处理方法public void keyPressed( int code )//定义游戏结束或者玩家胜利时的事件处理方法private void keyForInit( int action )//定义游戏过程中的事件处理方法private void keyForPlay( int action )//定义重新绘制棋盘格的方法public void repaintCells( int x, int y, int w, int h ) (4)Player.javaprivate Board oBoard;private BoardView oBoardView;private Enemy oEnemy;private Bomb oBomb;private Random random; private int iX, iY;//游戏主角的构造函数public Player( Board board, BoardView boardview )//游戏主角的初始化方法public void init()public void setEnemy( Enemy enemy )//清除炸弹对象的方法public void clearBomb()//判断游戏主角能否移动到给定的棋盘格上private boolean canGo( int x, int y )//定义放置炸弹的方法public void fire()//定义游戏主角向左移动的方法public void left()//定义游戏主角向右移动的方法public void right()//定义游戏主角向上移动的方法public void up()//定义游戏主角向下移动的方法public void down()//定义游戏主角死掉的方法public void die() (5)Enemy.java private Board oBoard; private BoardView oBoardView; public Player oPlayer; //设置敌人每次移动的间隔时间 private final int iMoveTime = 500; private Random random; //声明游戏中敌人的数量 private int iNumbers; //声明所有敌人所在位置的二维数组 private int[][] arrPositions; private volatile boolean stopThread = false; //初始化敌人对象的构造函数 public Enemy( Board board, BoardView boardview, Player player, int numbers ) //敌人对象的初始化方法 public void init()public void stopThread()//定义线程的方法体,在该方法中将定义敌人如何进行移动public void run()//定义敌人的移动方法private void move( int i )//判断能否移动到指定棋盘格位置上的方法private boolean canGo( int x, int y )//定义给定位置上的敌人死亡的方法public void die( int x, int y )//定义游戏中的所有敌人对象全部死亡的方法public void dieAll() (6) Bomb.java private Board oBoard; private BoardView oBoardView; private Player oPlayer; private Enemy oEnemy; //定义炸弹爆炸前等待的时间 private final int iExplodingTime = 4000; //定义爆炸效果显示的时间 private final int iDisapearTime = 1000; private int iX, iY; private volatile boolean stopThread = false; //炸弹类的构造方法 public Bomb( Board board, BoardView boardview, Player player, Enemy enemy, int x, int y )public void stopThread()//根据给定的单元格判断炸弹爆炸后的结果的方法private void explode( int x, int y )//清空给定的单元格中的元素private void clear( int x, int y )//定义线程的方法体,在该方法中将定义炸弹爆炸的效果public void run() (7) img.java //创建游戏中炸弹图像的方法,其余图像方法一样 public static Image imgBomb = Image.createImage(new byte[] {{...}, (int)0, (int)163} );五. 实验结果与分析(包括代码和实验总结)程序代码:1. 游戏的模型类实现(1) Board.javapackage com.mot.j2me.midlets.jbombman;import java.util.*;//定义游戏的模型的类,可以将其看做一个棋盘public class Board { //定义棋盘的二维数组 public char[][] chBoard; /* N - None 表示什么也没有 W - Wall 表示砖墙 L - Pillar 表示岩石 P - Player 表示游戏主角 E - Enemy 表示敌人 B - Bomb 表示炸弹 U - Bomb under player 表示主角正在放置炸弹 X - Exploding 表示炸弹爆炸 */ //声明一个随机数对象 private Random random; //声明棋盘的行和列数 public int iCols, iRows; //声明判断游戏是否结束的标识 public volatile boolean isGameOver; //声明判断是否玩家胜利的标识 public volatile boolean isWin; //构造函数,初始化棋盘的行数和列数,并构造随机数对象 public Board( int cols, int rows ) { //构造随机数对象 random = new Random(); iCols = cols; iRows = rows; //构造表示棋盘的二维数组 chBoard = new char[iCols][iRows]; //调用棋盘的初始化方法 init(); } //定义棋盘的初始化方法 public void init() { //表示游戏结束的标识设置为false isGameOver = false; //表示玩家获胜的标识设置为false isWin = false; //遍历二维数组,为数组的每个元素设置值为'N',表示游戏中每个棋盘格上都为空 for( int i=0; i= iCols ) return false; if( y < 0 ) return false; if( y >= iRows ) return false; return( chBoard[x][y] == ch ); } //获取指定的某个棋盘格中的元素 public char getElement( int x, int y ) { if( x < 0 ) return '?'; if( x >= iCols ) return '?'; if( y < 0 ) return '?'; if( y >= iRows ) return '?'; return chBoard[x][y]; } //设置指定的某个棋盘格中的元素 public void setElement( char ch, int x, int y ) { if( ch == '?' ) return; if( x < 0 ) return; if( x >= iCols ) return; if( y < 0 ) return; if( y >= iRows ) return; chBoard[x][y] = ch; } //判断给定的位置是否在敌人的攻击范围内 public boolean near( char ch, int x, int y ) { return isElement( ch, x-1, y )||isElement( ch, x, y-1 ) ||isElement( ch, x+1, y )||isElement( ch, x, y+1 ); } //判断给定的位置是否可以向某个方向移动2步 public boolean near2( char ch, int x, int y ) { return ( isElement( ch, x-1, y )&&isElement( ch, x-2, y ) ) ||( isElement( ch, x, y-1 )&&isElement( ch, x, y-2 ) ) ||( isElement( ch, x+1, y )&&isElement( ch, x+2, y ) ) ||( isElement( ch, x, y+1 )&&isElement( ch, x, y+2 ) ); }}2. 游戏的视图类实现(1) BoardView.javapackage com.mot.j2me.midlets.jbombman;import javax.microedition.lcdui.*;//游戏的画布屏幕类public class BoardView extends Canvas { private Board oBoard; private Player oPlayer; private Enemy oEnemy; //定义背景色 private final int BackgroundColor = 0xffffff; //定义每个棋盘格的大小 private final int iCellSize = 20; //声明内部边框距离坐标原点的横坐标距离 private final int iLeft = 10; //声明内部边框距离坐标原点的纵坐标距离 private final int iTop = 10; public BoardView( Board board ) { oBoard = board; } public void setPlayer( Player player ) { oPlayer = player; } public void setEnemy( Enemy enemy ) { oEnemy = enemy; } //绘制游戏屏幕 public void paint( Graphics g ) { //声明同步块,对Graphics对象g进行同步 synchronized( g ) { //如果游戏结束,则绘制游戏结束的界面 if( oBoard.isGameOver ) paintGameOver( g ); //如果玩家获胜,则绘制玩家获胜的界面 else if( oBoard.isWin ) paintWin( g ); //否则绘制当前游戏运行的界面 else paintBoard( g ); } } //定义绘制游戏结束的方法 private void paintGameOver( Graphics g ) { g.drawImage( Img.imgGameOver, 60, 100, Graphics.LEFT|Graphics.TOP ); } //定义绘制游戏玩家获胜的方法 private void paintWin( Graphics g ) { g.drawImage( Img.imgCongratulation, 60, 100, Graphics.LEFT|Graphics.TOP ); } //绘制游戏棋盘边框的方法 private void paintFrame( Graphics g ) { g.drawRect( 0, 0, 239, 239 ); g.drawRect( 1, 1, 237, 237 ); g.drawRect( 2, 2, 235, 235 ); g.drawRect( 3, 3, 233, 233 ); g.drawRect( 7, 7, 225, 225 ); g.drawRect( 8, 8, 223, 223 ); } //定义绘制棋盘的方法 private void paintBoard( Graphics g ) { //判断画布屏幕的工作区的原点是否在坐标轴的原点上,如果是则直接绘制游戏棋盘的边框 if( g.getClipX() == 0 ) paintFrame( g ); //设置画布屏幕的工作区的左上角坐标以及高度和宽度 int x = ( g.getClipX() - iLeft ) / iCellSize; int y = ( g.getClipY() - iTop ) / iCellSize; int w = g.getClipWidth() / iCellSize; int h = g.getClipHeight() / iCellSize; System.out.println( "paint: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h ); //如果画布屏幕的工作区的高度超过了棋盘的高,则将工作区的高度设置为棋盘的高度 if( h>oBoard.iRows ) h = oBoard.iRows; //根据工作区的位置,开始绘制棋盘中的元素 for( int i=x; i= oBoard.iCols ) x = oBoard.iCols - 1; if( x + w > oBoard.iCols ) w = oBoard.iCols - x; if( y < 0 ) y = 0; if( y >= oBoard.iRows ) y = oBoard.iRows - 1; if( y + h > oBoard.iRows ) h = oBoard.iRows - y; repaint( iLeft + x*iCellSize, iTop + y*iCellSize, w*iCellSize, h*iCellSize ); }}3. 游戏的主角类实现(1) Player.javapackage com.mot.j2me.midlets.jbombman;import java.util.*;//游戏中的主角类public class Player { private Board oBoard; private BoardView oBoardView; private Enemy oEnemy; private Bomb oBomb; private Random random; private int iX, iY; //游戏主角的构造函数 public Player( Board board, BoardView boardview ) { oBoard = board; oBoardView = boardview; random = new Random(); //调用游戏主角的初始化方法 init(); } //游戏主角的初始化方法 public void init() { while( true ) { //获取游戏主角初始化的随机位置 iX = Math.abs( random.nextInt() ) % oBoard.iCols; iY = Math.abs( random.nextInt() ) % oBoard.iRows; //如果随机位置上不为空,则跳出当前本次循环,再重新获取随机位置 if( oBoard.chBoard[iX][iY] != 'N' ) continue; //如果随机位置在敌人的攻击范围内,则跳出当前本次循环,再重新获取随机位置 if( oBoard.near( 'E', iX, iY ) ) continue; //如果随机位置不能够向任何方向移动2步,则跳出当前本次循环,再重新获取随机位置 if( !oBoard.near2( 'N', iX, iY ) ) continue; //如果获得一个合适的随机位置,则跳出死循环,继续向下执行 break; } //在棋盘中根据获取的随机位置设置对应的棋盘格中的元素为游戏主角 oBoard.chBoard[iX][iY] = 'P'; } public void setEnemy( Enemy enemy ) { oEnemy = enemy; } //清除炸弹对象的方法 public void clearBomb() { oBomb = null; System.out.println( "delete Bomb" ); } //判断游戏主角能否移动到给定的棋盘格上 private boolean canGo( int x, int y ) { //如果要移动到的棋盘格中没有元素,则返回true if( oBoard.isElement( 'N', x, y ) ) return true; //如果要移动到的棋盘格中是敌人,则游戏主角死掉 if( oBoard.isElement( 'E', x, y ) ) die(); //如果上述条件都不成立,则不能移动到给定的单元格中,返回false return false; } //定义放置炸弹的方法 public void fire() { //构造一个炸弹对象 oBomb = new Bomb( oBoard, oBoardView, this, oEnemy, iX, iY ); //启动炸弹对象中的线程方法体 oBomb.start(); System.out.println( "new Bomb: x=" + iX + ", y=" + iY ); } //定义游戏主角向左移动的方法 public void left() { //如果不能向左移动,则返回 if( !canGo( iX-1, iY ) ) return; //如果移动之前的棋盘格中的元素是游戏主角放置炸弹,则移动之前的棋盘格中放置炸弹元素 if( oBoard.chBoard[iX][iY] == 'U' ) oBoard.chBoard[iX][iY] = 'B'; else //否则的话,移动之前的棋盘格中设置为空 oBoard.chBoard[iX][iY] = 'N'; //游戏主角的列数减1 iX--; //设置移动后的棋盘格中的元素为游戏主角 oBoard.chBoard[iX][iY] = 'P'; //在画布屏幕上重绘指定的区域 oBoardView.repaintCells( iX, iY, 2, 1 ); } //定义游戏主角向右移动的方法 public void right() { //如果不能向右移动,则返回 if( !canGo( iX+1, iY ) ) return; //如果移动之前的棋盘格中的元素是游戏主角放置炸弹,则移动之前的棋盘格中放置炸弹元素 if( oBoard.chBoard[iX][iY] == 'U' ) oBoard.chBoard[iX][iY] = 'B'; else //否则的话,移动之前的棋盘格中设置为空 oBoard.chBoard[iX][iY] = 'N'; //游戏主角的列数加1 iX++; //设置移动后的棋盘格中的元素为游戏主角 oBoard.chBoard[iX][iY] = 'P'; //在画布屏幕上重绘指定的区域 oBoardView.repaintCells( iX-1, iY, 2, 1 ); } //定义游戏主角向上移动的方法 public void up() { //如果不能向上移动,则返回 if( !canGo( iX, iY-1 ) ) return; //如果移动之前的棋盘格中的元素是游戏主角放置炸弹,则移动之前的棋盘格中放置炸弹元素 if( oBoard.chBoard[iX][iY] == 'U' ) oBoard.chBoard[iX][iY] = 'B'; else //否则的话,移动之前的棋盘格中设置为空 oBoard.chBoard[iX][iY] = 'N'; //游戏主角的行数减1 iY--; //设置移动后的棋盘格中的元素为游戏主角 oBoard.chBoard[iX][iY] = 'P'; //在画布屏幕上重绘指定的区域 oBoardView.repaintCells( iX, iY, 1, 2 ); } //定义游戏主角向下移动的方法 public void down() { //如果不能向上移动,则返回 if( !canGo( iX, iY+1 ) ) return; //如果移动之前的棋盘格中的元素是游戏主角放置炸弹,则移动之前的棋盘格中放置炸弹元素 if( oBoard.chBoard[iX][iY] == 'U' ) oBoard.chBoard[iX][iY] = 'B'; else //否则的话,移动之前的棋盘格中设置为空 oBoard.chBoard[iX][iY] = 'N'; //游戏主角的行数加1 iY++; //设置移动后的棋盘格中的元素为游戏主角 oBoard.chBoard[iX][iY] = 'P'; //在画布屏幕上重绘指定的区域 oBoardView.repaintCells( iX, iY-1, 1, 2 ); } //定义游戏主角死掉的方法 public void die() { System.out.println( "Player die: x=" + iX + ", y=" + iY ); //杀死游戏中搜有的敌人 oEnemy.dieAll(); //设置游戏结束的标识为true oBoard.isGameOver = true; //重新绘制画布屏幕 oBoardView.repaint();}}4. 游戏的敌人类实现(1) Enemy.javapackage com.mot.j2me.midlets.jbombman;import java.util.*;//游戏中的敌人类public class Enemy extends Thread { private Board oBoard; private BoardView oBoardView; public Player oPlayer; //设置敌人每次移动的间隔时间 private final int iMoveTime = 500; private Random random; //声明游戏中敌人的数量 private int iNumbers; //声明所有敌人所在位置的二维数组 private int[][] arrPositions; private volatile boolean stopThread = false; //初始化敌人对象的构造函数 public Enemy( Board board, BoardView boardview, Player player, int numbers ) { oBoard = board; oBoardView = boardview; oPlayer = player; iNumbers = numbers; arrPositions = new int[iNumbers][2]; random = new Random(); //调用敌人对象的初始化方法 init(); } //敌人对象的初始化方法 public void init() { int x, y; //随机将游戏中的敌人放置在棋盘中 for( int i=0; i