资源描述
石家庄科技信息职业学院
毕 业 论 文
题目: 基于J2ME的小球快跑游戏
学 号: 090124014
姓 名: 马振东
专业班级:软件技术(游戏方向)09-24 班
指导教师: 刘永伟
完成日期: 2011-12-18
基于J2ME的小球快跑游戏
摘要:手机是人们日常生活中所用的非常频繁的通信工具。随着JAVA技术的不断更新提高,J2ME技术的出现,使得手机游戏越来越成为我们关注的焦点。J2ME技术目前最流行的就是在制作手机游戏方面,JAVA手机的出现使得这一技术更有它的用武之地,发挥着他灵活、轻便、快捷的作用。J2ME平台被是最杰出的手机游戏手机游戏平台,它一些非常重要的特征对开发者都有很大益处。因为J2ME应用在不同设备上都是便携式的,他们常常可以在网络上下载和执行。
本设计通过DriftBall和 GameView等类进行小球快跑游戏设计,最后编程实现了全过程。
关键词:J2ME DriftBall GameView
目录
一、 设计内容及过程…………………………………………………………… 4
(1)游戏策划………………………………………………………………… 4
(2)设计背景……………………………………………………………….. 4
(3)游戏框架设计…………………………………………………………… 5
二、 游戏主菜单的开发………………………………………………………… 5
(1)WelcomeView类的代码框架……………………………….....………… 5
(2)WelcomeView类的主要成员方法.……………………………………… 6
(3)WelcomeThread类的开发………...............................……………… … 8
(4)菜单界面的用户交互事件处理…………..................…………….…… 9
三、 游戏界面模块的开发…………………………………………………… 11
(1)GameView的成员变量.......................................................................... 11
(2)GameThread类的代码框架.................................................................. 13
(3)GameMenuThread类的开发 ................................................................... 13
四、 游戏中各个图层的开发……………………………………………………..15
(1)地图图层的开发............…………………………………………………. 15
(2)其他图层的开发与实现………………………………………………… 18
五、 游戏后台逻辑的开发………………………………………………….. .. 21
(1)小球的运动控制 .................................................................................... 21
(2)小球的碰撞检测 .................................................................................... 25
六、 传感器计算模块的开发 ............................................................................ 27
(1)BallListener类的开发 .......................................................................... 27
(2)RotateUtil类的开发 ............................................................................. 28
七、 设计总结
参考文献………………………………………………………………………… 31
一. 设计内容及过程
本设计针对小球快跑实现了新游戏、选关、恭喜过关,继续或冲完等过程。可以清楚的演示各个画面的切换和一些游戏开发的类库。
(1) 游戏策划
本游戏从类型上看属于动作类通关游戏,因此在游戏开发前进行的策划中需要考虑到诸如剧情规划、关卡设计等内容
剧情规划:由于本游戏主要是以玩法取胜,而不是靠游戏情节来吸引玩家,所以游戏的剧情的规划可以尽量简单或者干脆没有
关卡设计:关卡设计是本游戏的一个重点,在关卡设计的时候,如何保证难易程度的循环渐进和关卡之间的互异性以及关卡的可玩性是需要重视的问题。
目标受众:本游戏的操作方式十分简单,各个年龄阶段的玩家都可以快速掌握。
目标平台:本游戏的目标平台为MTK。
呈现技术:本游戏的游戏画面采用了图元技术,所以地图的设计也是一个重点,同时增强了游戏的空间感。
(2)设计背景
游戏中,首先必须要有个主应用程序类,其次,为了把程序的画面呈现出来,就是要有画布;为了比较容易管理地图、增加或修改地图比较方便,应该把地图和画布分开。
这其中需要先了解游戏中应用到的类。
WelcomeView类继承自SurfaceView类,其主要负责播放欢迎动画和显示游戏主菜单。
GameView类继承自SurfaceView,其主要负责游戏主画面的渲染。
GameMenuThread负责实现游戏中菜单的逐行的效果。
GameMap类负责负责提供游戏中的地图信息,GameMap中存储了所有关卡的信息,并对外提供了方法用于获得指定关卡的地图信息。
DriftBall类继承自Activity,其主要负责在不同的View之间进行切换,同时也负责处理用户单击屏幕事件。
BaiiListener类继承自SensorListener类,气质要负责监听手机姿态的变化并将捕获到的数据传递给RotateUtil进行分析计算。
RotateUtil类主要负责接收手机姿态的变化数据,并根据一系列算法计算出在这种姿态下的小球的运动方向。
(3) 游戏框架设计
游戏基本框架图:
图1 小球快跑游戏基本框架
二. 游戏主菜单的开发
(1) WelcomeView类的代码框架
代码如下:
package wyf.wpf; //声明包语句
import android.content.Context; //引入相关类
import android.content.res.Resources; //引入相关类
import android.graphics.Bitmap; //引入相关类
import android.graphics.BitmapFactory; //引入相关类
import android.graphics.Canvas; //引入相关类
import android.graphics.Color; //引入相关类
import android.graphics.Matrix; //引入相关类
import android.graphics.Paint; //引入相关类
import android.view.SurfaceHolder; //引入相关类
import android.view.SurfaceView; //引入相关类
/*
* 该类继承自View,负责欢迎界面的绘制
*/
public class WelcomeView extends SurfaceView implements SurfaceHolder.Callback{
DriftBall father;
WelcomeThread wt;
WelcomeDrawThread wdt;
Bitmap [] bmpBackScreen; //后台背景的动画帧
Bitmap [] bmpStartOrQuit; //开始和退出的两个大球图片
Bitmap [] bmpSoundOption; //声音选项的两个大球图片
int status = -1; //状态值,为0表示待命,1表示开始或退出按钮按下,2为显示加载中
int selectedIndex = -1; //被选中的命令,只能是开始或退出
int backIndex; //后台帧动画的索引
Matrix m; //Matrix对象,负责
int [][] planetCoordinate={ //三个球的位置数组
{60,120},
{120,300},
{180,220}
};
//构造器,初始化成员变量
public WelcomeView(DriftBall father) {
super(father);
wt = new WelcomeThread(this);
getHolder().addCallback(this);
wdt = new WelcomeDrawThread(this,getHolder());
initBitmap(father); //初始化图片
this.father = father;
status = 0;
m = new Matrix();
}
(2) WelcomeView类主要成员方法
代码如下:
package wyf.wpf; //声明包语句
import org.openintents.sensorsimulator.hardware.SensorManagerSimulator;//引入相关类
import android.app.Activity; //引入相关类
import android.graphics.Rect; //引入相关类
import android.hardware.SensorManager; //引入相关类
import android.media.MediaPlayer; //引入相关类
import android.os.Bundle; //引入相关类
import android.os.Handler; //引入相关类
import android.os.Message; //引入相关类
import android.view.KeyEvent; //引入相关类
import android.view.MotionEvent; //引入相关类
import android.view.View; //引入相关类
import android.view.Window; //引入相关类
import android.view.WindowManager; //引入相关类
/*
* 该类为游戏的主类,所有的View对象在这里有所引用,主要的功能是实现游戏
* 的流程控制,提供游戏需要的常量,在视图之间进行切换。
*/
public class DriftBall extends Activity {
public static final int STATUS_PLAY = 0; //游戏进行中
public static final int STATUS_PAUSE = 1; //游戏暂停
public static final int STATUS_WIN = 2; //通过一关
public static final int STATUS_LOSE = 3; //丢掉一条命
public static final int STATUS_OVER = 4; //送完命了,游戏结束
public static final int STATUS_PASS = 5; //通全关
public static final int MAX_LIFE = 5; //最大生命数
public static final int MAX_LEVEL = 5; //最大关卡数
int level = 1; //初始状态等级为1
int life = MAX_LIFE; //初始状态生命数最大
Rect rectStart; //开始圆球按钮的矩形框
Rect rectSoundOption; //声音选项圆球按钮的矩形框
Rect rectQuit; //推出圆形按钮的矩形框
Rect rectContinue; //继续游戏菜单项的矩形框
Rect rectSoundAlter; //声音选项菜单项的矩形框
Rect rectHelp; //帮助菜单项的矩形框
Rect rectBackToMain; //回到主菜单菜单项的矩形框
Rect rectGameMsgBox; //屏幕中间提示消息的矩形框
MediaPlayer mpGameMusic; //游戏背景音乐
MediaPlayer mpPlusLife; //加命的音乐
MediaPlayer mpMissileHit; //导弹打中的音乐
MediaPlayer mpGameWin; //通过了一关的音乐
MediaPlayer mpGameLose; //损失一条命的音乐
MediaPlayer mpBreakOut; //显示菜单和掉入陷阱以及被吃掉的音乐
boolean wantSound = true; //标志位,记录是否播放音乐
View currView; //记录当前显示的View
GameView gv; //游戏视图的引用
WelcomeView wv; //欢迎视图的引用
BallListener bl; //继承自SensorListener的监听器
HelpView hv; //帮助视图
//@1======对源代码进行如下修改以连接SensorSimulator
// SensorManager mySensorManager;
SensorManagerSimulator mySensorManager;
Handler myHandler = new Handler(){
public void handleMessage(Message msg) { //重写handleMessage方法
switch(msg.what){
case 0: //0为收到来自WelcomeView的开始游戏命令
gv = new GameView(DriftBall.this);
setContentView(gv); //设置当前View
currView = gv; //记录当前View
startSensor(); //开启传感器
图2 游戏开始界面
(3) WelcomeThread的开发
代码如下:
package wyf.wpf; //声明包语句
/*
* 该类继承自Thread,为欢迎界面的后台线程,
* 负责修改相关数据,达到动画效果
*/
public class WelcomeThread extends Thread{
WelcomeView father; //WelcomeView引用
int sleepSpan = 100; //休眠时间
boolean flag = false;
//构造器,接收WelcomeView对象引用
public WelcomeThread(WelcomeView father){
this.father = father;
this.flag = true;
}
}
(4) 菜单界面的用户交互事件处理
代码如下:
//重写的方法,用于接收和处理用户点击屏幕事件
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
int x=(int)event.getX();
int y=(int)event.getY();
if(currView == wv){ //当前为欢迎界面
if(rectStart.contains(x, y)){ //点下开始的圆球
wv.status = 1; //设置状态为1,有按钮按下
wv.selectedIndex = 0; //设置被选中的按钮为开始按钮
}
else if(rectSoundOption.contains(x, y)){ //点下切换声音的圆球
wantSound = !wantSound; //切换标志位
if(!wantSound){ //如果当前在播放声音,停
if(mpGameMusic.isPlaying()){
try {
mpGameMusic.pause(); //暂停游戏背景音乐
} catch (Exception e) {}
}
}
else if(wantSound){ //如果当前没有播放声音,播放
if(!mpGameMusic.isPlaying()){
try {
mpGameMusic.start(); //播放游戏背景音乐
} catch (Exception e) {}
}
}
}
else if(rectQuit.contains(x, y)){ //点下退出的圆球
wv.status = 1; //设置状态为1,有按钮按下
wv.selectedIndex = 1; //设置被选中的按钮为退出按钮
}
}
else if(currView == gv){ //当前为游戏界面在显示
if(gv.status == STATUS_PAUSE){
if(rectContinue.contains(x,y)){ //点下继续游戏菜单
gv.gmt.isOut = true; //菜单开始退出屏幕
}
else if(rectSoundAlter.contains(x, y)){ //点下切换声音菜单
wantSound = !wantSound;
if(!wantSound){ //判断记录值的真假
if(mpGameMusic.isPlaying()){
try {
mpGameMusic.pause(); //暂停声音
} catch (Exception e) {}
}
}
else if(wantSound){
if(!mpGameMusic.isPlaying()){
try {
mpGameMusic.start(); //播放声音
} catch (Exception e) {}
}
}
gv.gmt.isOut = true;
}
else if(rectHelp.contains(x, y)){ //点下帮助菜单
gv.gmt.isOut = true; //淡出菜单
gv.pauseGame(); //暂停游戏
hv = new HelpView(this); //创建HelpView对象
setContentView(hv); //切屏
currView = hv;
}
else if(rectBackToMain.contains(x, y)){ //点下回主菜单
gv.gmt.isOut = true; //淡出菜单
wv = new WelcomeView(this); //创建欢迎界面
setContentView(wv); //切屏
currView = wv; //记录当前View
pauseSensor(); //暂停Sensor
gv.shutAll(); //关闭gv的附属线程
gv = null;
}
}
else if(gv.status == STATUS_WIN){ //闯过一关
if(rectGameMsgBox.contains(x, y)){
gv.initGame();
gv.resumeGame(); //开始下一关的游戏
}
}
else if(gv.status == STATUS_PASS || gv.status == STATUS_OVER){ //当前状态为通全关或死完了
if(rectGameMsgBox.contains(x, y)){ //判断点击的位置
wv = new WelcomeView(this); //创建欢迎界面
setContentView(wv); //切屏
currView = wv; //记录View
pauseSensor(); //暂停监听器
gv.shutAll(); //关闭gv附属线程
gv = null;
}
}
}
}
return true;
}
三. 游戏界面模块的开发
(1) GameView的成员变量
代码如下:
package wyf.wpf; //声明包语句
import java.util.ArrayList; //引入相关类
import android.content.res.Resources; //引入相关类
import android.graphics.Bitmap; //引入相关类
import android.graphics.BitmapFactory; //引入相关类
import android.graphics.Canvas; //引入相关类
import android.view.SurfaceHolder; //引入相关类
import android.view.SurfaceView; //引入相关类
import android.view.SurfaceHolder.Callback; //引入相关类
import static wyf.wpf.DriftBall.*; //引入相关类
/*
* 该类继承自SurfaceView,主要功能是绘制游戏屏幕,对后台的绘制或其他线程
* 进行控制。
*/
public class GameView extends SurfaceView implements Callback{
int screenWidth = 320; //屏幕宽度
int screenHeight = 480; //屏幕高度
int backY; //x坐标总是为零
int nebulaX; //星云的x坐标
int nebulaY; //星云的y坐标
int ballX; //小球的横坐标
int ballY; //小球的纵坐标
int tileSize = 20; //图元的大小
int direction = -1; //小球运动方向,上为0,顺时针依次为1~7
int velocity = 4; //小球运动速度
int eatIndex; //吃人动画帧索引
int status; //游戏状态
int trapIndex; //陷阱动画索引
boolean showMenu; //是否显示菜单
DriftBall father; //DriftBall引用
DrawThread dt; //绘制线程
GameThread gt; //后台数据的修改线程
CannonThread ct; //大炮线程
GameMenuThread gmt; //游戏菜单线程
Meteorolite [] meteoArray; //陨石数组
ArrayList<Missile> alMissile = new ArrayList<Missile>(); //存放导弹集合
ArrayList<Cannon> alCannon = new ArrayList<Cannon>(); //存放大炮集合
Bitmap bmpStar; //星空图片
Bitmap bmpNebula; //星云图片
Bitmap bmpBall; //小球图片
Bitmap bmpTile; //地图图元,即路的图片
Bitmap [] bmpMeteo; //陨石图片
Bitmap [] bmpEat; //吃人图片
Bitmap bmpHome; //家的图片
Bitmap [] bmpTrap; //陷阱图片
Bitmap bmpCannon; //大炮图片
Bitmap bmpMissile; //导弹图片
Bitmap bmpPlusLife; //加命图片
Bitmap bmpMultiply; //乘号图片,用以显示命数
Bitmap [] bmpNumber; //数字图片
Bitmap [] bmpMenuItem; //菜单项图片数组
Bitmap bmpGameWin; //游戏胜利图片
Bitmap bmpGameOver; //游戏结束图片
Bitmap bmpGamePass; //游戏通关图片
(2)GameThread类的代码框架
代码如下:
package wyf.wpf; //声明包语句
/*
* 这个类主要负责绘制元素的数据变化,如控制陨石和星云的帧何时切换
* 同时还负责,移动小球。不同的元素的不同的换帧间隔是通过帧控制计数器
* 来实现的。移动小球的同时还会相应地进行碰撞检测
*/
import static wyf.wpf.DriftBall.*; //引入DriftBall类的静态常量
public class GameThread extends Thread{
GameView father; //GameView对象引用
int sleepSpan = 25; //休眠时间
int backCounter; //背景帧控制计数器
int nebulaCounter; //星云帧控制计数器
int eatCounter; //吃掉小球的帧控制计数器
int trapCounter; //陷阱帧控制计数器
int meteoCounter; //陨石帧控制计数器
boolean flag = false; //外层循环
boolean isGameOn = false; //游戏是否在进行
//构造器
public GameThread(GameView father){
this.father = father;
this.flag = true;
}
(3) GameMenuThraed类的开发
代码如下:
package wyf.wpf; //声明包语句
/*
* 该类继承自Thread类,主要负责将菜单及菜单项在屏幕上的位置
* 进行改变以达到动画效果
*/
public class GameMenuThread extends Thread{
DriftBall father; //主类引用
boolean flag; //循环控制变量
boolean isIn; //是否是淡入菜单
boolean isOut; //是否是淡出菜单
int sleepSpan = 20; //睡眠时间
int [][] menuCoordinate={ //菜单在没进来之前的位置,分别是菜单背景和4个菜单项
{350,0},
{400,30},
{450,80},
{500,130},
{550,180}
};
//构造器
public GameMenuThread(DriftBall father){
this.father = father;
father.gv.menuCoordinate = this.menuCoordinate;
flag = true;
isIn = true;
}
//线程执行方法
public void run(){
int inIndex=0; //淡入的索引顺序
int outIndex = 4; //淡出时的索引顺序
while(flag){
if(isIn){ //菜单进屏幕
for(int i=inIndex;i<father.gv.menuCoordinate.length;i++){
father.gv.menuCoordinate[i][0]-= 25; //向屏幕内移动菜单项
if(father.gv.menuCoordinate[i][0] == 150){ //判断菜单项是否已到位
inIndex=i+1; //将开始索引下移,即不再改变到位的菜单项坐标
}
}
if(inIndex == 5){ //如果所有菜单项都移动到位
isIn = false; //设置isIn标志位为false
}
}
else if(isOut){ //菜单出屏幕
father.gv.menuCoordinate[outIndex][0] +=10; //向屏幕外移动菜单项
if(father.gv.menuCoordinate[outIndex][0] >=320){ //判断是否将菜单项移出屏幕
outIndex--; //改移动前一个菜单项
if(outIndex < 0){ //判断是否所有的菜单项都移出屏幕
if(father.currView == father.gv){ //如果当前View是GameView
father.gv.resumeGame(); //调用resumeGame方法恢复游戏
}
flag = false; //停止线程的执行
}
}
}
try{ //线程休眠
Thread.sleep(sleepSpan);
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
五.游戏中各个图层的开发
(1) 地图图层的开发
代码如下:
package wyf.wpf; //声明包语句
/*
* 该类主要存储一个静态成员,3为数组,里面存放所有地图,每个地图
* 都是一个二维数组。同时还提供了一个静态方法,调用之后返回一个
* 地图的二维数组
*/
public class GameMap{
static byte [][][] map = {//地图,为0则空,为1则路,2为家,3是加命的,4是吃小球的,5是陷阱,6是大炮
{ //第一关
{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,5,1,1,1,1,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0},
{0,0,0,1,1,1,1,1,1,1,0,0,1,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,0,0,1,0,0,0,0,0,1,0,0,0,1,0},
{0,1,0,0,1,0,0,0,0,0,1,0,0,0,1,0},
{0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0},
{0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0},
{0,0,1,0,0,0,1,0,1,0,0,0,1,0,
展开阅读全文