太空保卫战安卓游戏项目文档.docx
《太空保卫战安卓游戏项目文档.docx》由会员分享,可在线阅读,更多相关《太空保卫战安卓游戏项目文档.docx(17页珍藏版)》请在冰豆网上搜索。
太空保卫战安卓游戏项目文档
太空保卫战安卓游戏项目文档
项目介绍:
我们暑假作业做的是:
Android游戏太空保卫战。
这是滚动屏幕动作游戏,和超级玛丽和魂斗罗是一类游戏。
这是一本书上的一个项目作业,提供了相应的资源,比如图片,界面预览,音乐,还有一些写好的类。
我们负责写一些重要的类并完成代码逻辑和相关配置。
之所以选择这样做是因为我们没有美工人员。
由于能力有限所以游戏比较简陋,关卡只有一关,排名还有模式等功能没有设计。
另外一件很重要的事,这本书是在台湾买的所以里面的资源图片上的文字是繁体字。
分工:
完成游戏的架构,并完成游戏主界面GameView(负责界面绘制和玩家触控事件的处理),背景滚动程序GameViewBackGroundThread(负责背景滚动和各种道具的出现),地图类Maps(控制敌机路线,加血换枪道具等相关信息),还有物件移动类MoveThread(控制敌机的产生运动和射击)FingerTouch(控制触屏事件)。
主要完成游戏辅助界面,当然使用类来实现。
有欢迎界面WelcomeView,欢迎界面的动画展示WelcomeViewThread,说明界面HelpView(soeasy),载入界面ProcessView,胜利界面WinView还有失败界面FailView等。
(以下会绘图说明)。
封装各种物件对象。
有子弹类Bullet,主飞机类Plane,敌机类EnemyPlane,爆炸类Explode,爆炸换帧类ExplodeThread,补血道具类Life还有换枪类ChangeBullet等。
(这些类顾名思义就行了)。
另外,那本书上帮我么完成了一些公用类,包括PlaneActivity,这是整个程序的入口,监听程序PlaneMoveThread监听玩家触控事件并读取主飞机的状态值。
还有整个游戏所需要的常数ContantUtil类来管理程序中要用到的常数。
界面:
Processview:
WelcomeViewThread:
WelcomeView:
GameView:
HelpView:
FailView:
WinView:
游戏架构:
启动游戏,在进入PlaneActivity中会先进入载入界面ProcessView,然后会载入欢迎界面,之后启动WelcomeViewThread产生动画欢迎界面之后停在选择状态等待操作。
玩家按下说明按钮会启动HelpView.
玩家按下开始游戏按钮,会进入载入界面,背景将初始化,Maps类中的所有敌机道具信息也将被初始化。
初始化时同时启动GameViewBackGroundThread以滚动背景图片。
当玩家发射炮弹时见新建炮弹对象Bullet并添加到GameView中,如果需要爆炸效果会建立Explode对象以及ExplodeThread对象来渲染爆炸效果。
游戏界面间的框架设计
首先要说的是进入这一步之前要实现辅助界面,比如processView.
下面将仔细介绍游戏界面间的框架设计,即一些界面间的逻辑。
1.GameView在初始化时会从Maps类中读取信息,具体包括有敌机的路线(敌机的路线并不是随机的,在Maps类里面已经预先设计好了),补血道具还有换枪升级道具的数目还有路线(路线基本都是居中而且是直线)等。
2.在界面初始化的同时,还需要启动MoveThread,GameViewBackGroundThread,PlaneMoveThread还有ExplodeThread程序。
其中带Thread后缀的类基本都是控制图片或者物件的移动。
3.GameView会在适当的时候从Plane类中读取主战飞机的咨询并进行绘制。
4.当主战飞机发射子弹时,会建立Bullet物件并增加到指定容器中,此时MoveThread同样需要定时改变子弹物件的位置。
5.以上将的所有过程中都需要PlaneActivity还有ConstanntUtil的参与。
部分重要类和函数的实现
当然,有些类和函数实现难度还是挺高的,这里就把这些难点介绍下吧,会有具体的代码展示。
各View类
之所以说View类是个难点是因为它的工作量是有点大,View作为UI的最基本的元件,负责绘制UI元素和界面动作的监听。
可以认为是Button,文本域等界面元素或者其他View的容器。
至于元件,图片,文字等等的绘制工作都是要交给它的,这当然不算什么重要的。
关键是是View类还要负责处理用户输入和交互。
由于它责任重大所以代码量很大,代码量很大就会感觉尾大不掉。
然后就是各种问题,各种bug,各种让人摸不着头脑的bug.基本最后都是重新实现那部分出问题的代码。
挑选近500行的GameView(这里继承的是SurfaceView是View的派生类,不过大同小异)讲一下View的框架吧,先是GameView的成员变量声明,然后是初始化刷帧程序,背景滚动程序,监听程序等,还有图片和声音资源的初始化。
然后就是比较重要的部分了,onDraw()函数,这里的onDraw函数不是重写的,主要负责绘制游戏界面的所有元件包括主战飞机,敌机道具等。
然后是几个负责其他程序的start和shutdown.然后就是刷帧程序,负责定时呼叫游戏界面GameView的onDraw()函数对界面进行重新绘制。
onDraw()函数
这个主要在GameView里面的函数在其他类里面也有很大的用处。
而且考虑的东西很多,所以这里作重点介绍。
废话少说,先上代码。
publicvoidonDraw(Canvascanvas){//自己写的绘製方法,并非重写的
canvas.save();
canvas.translate(ConstantUtil.LOX,ConstantUtil.LOY);
canvas.scale(ConstantUtil.RADIO,ConstantUtil.RADIO);
canvas.clipRect(0,0,480,320);
//每次绘制之前要进行清屏
paint.setColor(Color.BLACK);
paint.setStyle(Style.FILL);
canvas.drawRect(-10,-10,ConstantUtil.screenWidth+10,ConstantUtil.screenHeight+10,paint);
//画的内容是z轴的,后画的会覆盖前面画的
intbackGroundIX=this.backGroundIX;
inti=this.i;
intcloudX=this.cloudX;
//解决i左侧的问题
if(backGroundIX>0){
intn=(backGroundIX/ConstantUtil.pictureWidth)+((backGroundIX%ConstantUtil.pictureWidth==0)?
0:
1);//计算i左面有几幅图
for(intj=1;j<=n;j++){
canvas.drawBitmap(
battlebacks[(i-j+ConstantUtil.pictureCount)%ConstantUtil.pictureCount],
backGroundIX-ConstantUtil.pictureWidth*j,
ConstantUtil.top,
paint
);
}
}
//解决i自己
canvas.drawBitmap(battlebacks[i],backGroundIX,ConstantUtil.top,paint);
//解决i右侧的问题
if(backGroundIXintk=ConstantUtil.screenWidth-(backGroundIX+ConstantUtil.pictureWidth);
intn=(k/ConstantUtil.pictureWidth)+((k%ConstantUtil.pictureWidth==0)?
0:
1);//计算i右面有几幅图
for(intj=1;j<=n;j++){
canvas.drawBitmap(
battlebacks[(i+j)%ConstantUtil.pictureCount],
backGroundIX+ConstantUtil.pictureWidth*j,
ConstantUtil.top,
paint
);
}
}
plane.draw(canvas);//画玩家飞机
if(status==1||status==3){//游戏中时,关口中时
try{//绘制我方子弹
for(Bulletb:
goodBollets){
b.draw(canvas);
}
}
catch(Exceptione){
}
try{//绘制敌方飞机
for(EnemyPlaneep:
enemyPlanes){
if(ep.status==true){
ep.draw(canvas);
}
}
}
catch(Exceptione){
}
try{//绘制敌方子弹
for(Bulletb:
badBollets){
b.draw(canvas);
}
}
catch(Exceptione){
}
try{
for(ChangeBulletcb:
changeBollets){//绘製吃了改变枪的物体
if(cb.status==true){
cb.draw(canvas);
}
}
}
catch(Exceptione){
}
try{//绘制血块
for(Lifel:
lifes){
if(l.status==true){
l.draw(canvas);
}
}
}
catch(Exceptione){
}
try{//绘制爆炸
for(Explodee:
explodeList){
e.draw(canvas);
}
}
catch(Exceptione){
}
}
if(cloudX>-cloud.getWidth()&&cloudXcanvas.drawBitmap(cloud,cloudX,ConstantUtil.top,paint);
}
canvas.drawBitmap(hullBackground,0,10,paint);//画生命处的背景
for(intj=0;j<((5-plane.life)<0?
5:
plane.life);j++){//绘制表示生命的小数条
canvas.drawBitmap(hull,95+11*j,13,paint);
}
StringtimeStr=gameThread.touchTime/10+"";//转换成字符串
for(intc=0;cinttempScore=timeStr.charAt(c)-'0';
canvas.drawBitmap(number[tempScore],350+c*22,12,paint);
}
//绘制发射子弹的图片和方向图片
canvas.drawBitmap(fireBullet,5,ConstantUtil.screenHeight-fireBullet.getHeight()-5,paint);
canvas.drawBitmap(direction,ConstantUtil.screenWidth-direction.getWidth()-5,ConstantUtil.screenHeight-direction.getHeight()-5,paint);
if(pause)canvas.drawBitmap(playBit,416,0,paint);
elsecanvas.drawBitmap(pauseBit,416,0,paint);
canvas.restore();//恢复画布
}
这是该游戏最主要的方法。
负责绘制游戏界面中的各种元件,在此函数中需要先将绘制物体的坐标先描述出来,以防同步问题产生的不顺畅,然后根据坐标进行绘制。
下面对以上代码进行解释,首先是函数屏幕自我调整的画布相关设定代码,其中主要都是调用函数库中的canvas类和paint类中的函数。
然后函数绘制了游戏界面的滚动背景,这里我们用了一种比较独特的方法,我们不是把一整个打的背景图片处理,而是把整个图片分割成很多份小图片放在图片阵列中,此时可以根据目前i的值还有小图片的宽度以及屏幕的宽度进行自动计算i图片左侧还有多少图片,右边还有多少图片,然后就可以从整个图片阵列中取出图片进行绘制。
当游戏状态真正开始后,对存放所有我方子弹的容器进行取出操作并逐一绘制。
先将touchTime成员装换成字符串,然后对字符串处理,取出每个字节,并将其减去字节所得到的数位,然后根据数位对图片进行绘制。
最后是绘制触控按钮,因为我们还不了解那种滑动操作的机制所以只好设计按钮操作了,但是按钮操作非常不舒适,这也是我们我们要注重改进的一点。
爆炸类的实现
爆炸类有两个,一个是Explode还有一个是ExplodeThread类。
Explode类为爆炸类别,制定位置绘製爆炸,其他线程透过呼叫nextFrame方法换帧。
Explode实现比较简单,代码如下
publicclassExplode{
intx;//爆炸的x坐标
inty;//爆炸的y坐标
Bitmap[]bitmaps;//所有爆炸的帧数组
intk=0;//当前帧
Bitmapbitmap;//当前帧
Paintpaint;//画笔
publicExplode(intx,inty,GameViewgameView){
this.x=x;
this.y=y;
this.bitmaps=gameView.explodes;
paint=newPaint();//初始化画笔
}
publicvoiddraw(Canvascanvas){//绘製方法
canvas.drawBitmap(bitmap,x,y,paint);
}
publicbooleannextFrame(){//换帧,成功返回true。
否则返回false
if(kbitmap=bitmaps[k];
k++;
returntrue;
}
returnfalse;
}
}
而ExplodeThread类为爆炸的换帧线程,每隔一段时间对GameView中explodeList中的爆炸换一帧。
代码如下
publicclassExplodeThreadextendsThread{
privatebooleanflag=true;//循环标籤位
privateintspan=100;//睡眠的毫秒数
GameViewgameView;//GameView的物件变数
ArrayListdeleteExplodes=newArrayList();//用于暂时存放需要删除的爆炸
publicExplodeThread(GameViewgameView){//建构式
this.gameView=gameView;
}
publicvoidsetFlag(booleanflag){//设置循环标位
this.flag=flag;
}
publicvoidrun(){
while(flag){
if(gameView.pause)continue;
try{//防止併发访问的异常
for(Explodee:
gameView.explodeList){
if(e.nextFrame()){
}
else{//当没有下一帧时删除该爆炸
deleteExplodes.add(e);
}
}
gameView.explodeList.removeAll(deleteExplodes);
deleteExplodes.clear();
}
catch(Exceptione){
e.printStackTrace();
}
try{
Thread.sleep(span);//睡眠休息
}
catch(Exceptione){
e.printStackTrace();
}
}
}
publicLife(intstart,inttarget,intstep,int[][]path,booleanstatus,longtouchPoint){//建构式
this.start=start;
this.target=target;
this.step=step;
this.path=path;
this.status=status;
this.touchPoint=touchPoint;
this.x=path[0][start];
this.y=path[1][start];
}
publicvoiddraw(Canvascanvas){
canvas.drawBitmap(bitmap,x,y,newPaint());
}
publicvoidmove(){
if(step==path[2][start]){//一段路径走完,到下一段路径开始
step=0;
start=(start+1)%(path[0].length);
target=(target+1)%(path[0].length);
this.x=path[0][start];
this.y=path[1][start];
}
else{//一段路径没有走完,继续走
intxSpan=(path[0][target]-path[0][start])/path[2][start];
intySpan=(path[1][target]-path[1][start])/path[2][start];
this.x=this.x+xSpan;
this.y=this.y+ySpan;
step++;
}
}
}
爆炸类别也包含一个图片阵列,不过这个原理和背景滚动类不一样,因为它不是分割的,他们都在Android项目常用的资源目录res下,当Explode类被调用时,这几个图片会进行很快的换帧,就是把当前的图片迅速换成下一张图片,当然,绘制是也要调用刚才介绍过的onDraw()函数,并且这里绘制时是根据已经生成的坐标进行绘制,而非自己加进去固定的位置。
游戏改进
虽然此游戏已经给我们准备了很多先决条件,比如资源还有一些类,但因为我们能力有限还是有很多不足,这些都需要改进和进一步的开发。
成绩的排行
如果此游戏能设计成有成绩排行功能并将玩家成绩保存起来会更有可玩性。
关卡的设计
前面已经讲过,如果要设计游戏中敌机还有道具的轨迹需要Maps类,但是这个Maps类过于简单。
其实应该设计一个能自动生成线路的地图类,所以地图设计还需改进。
另外,飞机视角能变成俯视的话应该会更好。
结语
总之,我们在这次项目开发中学到了很多知识,但是仍然还是很幼稚的,有很大的提升空间,我们会努力的。