J2ME潜艇大战游戏设计与实现

本文介绍了飞机射击类(潜艇)游戏的设计过程,给出操作流程、算法处理、类结构等内容。游戏以全屏方式开启,有暂停等功能。算法上采用单态结构,用Vector数组管理物体,避免多线程性能问题。还提供了Demo版源代码下载地址,代码有注释但存在待完善问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

摘要

    本文给出了一个飞机射击类(潜艇)游戏的设计过程以及相应的流程图,并提供了Demo版源代码下载地址,游戏在sun wtk v2.2 下调试通过。

声明:本游戏所用的资源大多不属于作者,代码仅供非商业用途的学习参考。

以下为游戏的几张截图



游戏设计

1 游戏操作流程:

    游戏的初始画面是一个implusiveList列表格式,选择new game以后就可以启动游戏,游戏是以全屏方式开启,但仍有用于暂停/开始和退出的命令响应功能键。在游戏当中启动暂停,海水和海洋生物仍将继续活动,但敌方潜艇和所有鱼雷都将静止下来,玩家的控制也将不起作用,直到游戏被再次启动为止。从游戏状态退出将回到菜单界面,再次选择退出将退出程序。

以下是游戏的总体流程图:




2 算法处理

游戏自身是一个单态结构(singletone),由一个Controller来处理目前应该显现的屏幕和状态。主要的显示类包括主画面,游戏画布,帮助画面和一些辅助的Alert,其中最重要是游戏画面。游戏是在MIDP 2的状态下运行的,所以画面继承了GameCanvas。游戏中的角色图层全部加载在一个远大于手机屏幕大小的图层管理器上。当玩家位置移动时,图层管理器同步计算出玩家的相对位置,移动当前图层的显示位置。

这个游戏的本质就是在midlet启动后把整个画布作为一个线程,每隔25ms扫描一下用户按键操作,每隔50ms扫描一次敌人和鱼雷等物体的运动状态,对于比较苛求的子弹射出实时响应,则继承了keyPressed方法。

在扫描玩家移动操作时,按键编码被传入到玩家潜艇的响应方法。在扫描敌人和鱼雷运动时,分两步完成。

第一步,执行各个物体画面的移动方法。程序并不为每个新增鱼雷或者敌人开启一个新线程,太多线程会造成程序的性能直线下降;而是为每一个物体类型保留一个Vector数组,每当一个新物体产生,他将首先被加入改类型所属的数组中,然后才在图层上画出;当物体消除时,除了在图层上被消除,也需要从响应数组中删除。这样就形成一种注册机制,所有游戏物体的产生和消除都需要向画布注册,画布拥有不同类型物体的所有“名单”,所以,当执行移动命令时,只需要遍历各个类型数组,依次执行其中每个元素的移动方法即可。

第二步,就是一般意义上重画,这里使用flushGraphics()替代了传统的repaint(),由于本游戏是以导入图片为操作对象,图片位置的更改已经在第一步被执行,所以没有怎么涉及到象素级的重画,只是在游戏初始化状态时需要加载各个物体数组所对应的图层到新的图层管理器。


画布触发流程简图:

(由于手上没有rose,只有暂时用EclipseUML的流程图画出草图,若干有问题的地方需要商榷,也希望擅长此到的朋友不吝指正)



3 类结构

以下列出了主要组成类的含义结构,并以游戏画布为中心列出一个类关联图。

Controller: 控制类,用以控制当前屏幕显示哪一个Displayable类。

SubObject: 接口类型。玩家潜艇,敌人潜艇以及鱼雷等可移动图层类型皆扩展于此接口。

Sub: 玩家潜艇。包含了位置,生命值等成员变量以及移动,开火等方法。

EnemySub, MoveableSprite, Tinfish: 敌人潜艇,海洋生物,鱼雷。都是可移动图层类型,一旦产生就在画布中注册,由时间触发器维护其运动和生命状态。

SubCanvas: 游戏主画布。存储着游戏地图信息,游戏状态,玩家信息,同步维护着敌人潜艇,鱼雷,海洋生物的运动和生存状态。

SubCanvas关联类图:





4 源代码

本程序的源代码,包括jad,混淆过的jar和一个rar文件,全部可以在 http://www.hyweb.net/BrowseFiles.aspx?Folder=Public/My%20Project 上下载到,代码中包含了较为详细的注释。这份程序只是一个demo版本,有一些遗留问题(玩家生命值显示,性能优化)还需要进一步完善,有任何好的建议,请一定联系我. ^_^

*简单潜艇大战 全局变量speed一开始需要调整,大家的速度不同 主要练习下这个游戏的基本算法,用简单的形来模拟 ----跳蚤侦探-------*/#include #include #include #include #define KEY_ESC 0x01#define KEY_SPACE 0x39#define KEY_LEFT 0x4b#define KEY_RIGHT 0x4dint speed=10000;char key_state[128],key_pressed[128];/*键盘操作用的变量*/int score=0;/*得分*/char scorestr[10];/*输出分数的变量*/struct Fire/*子弹的结构体*/{ int x; int y; int start;/*是否发射炮弹*/}amyfire[6];/*屏幕上最多有5个敌人可以发子弹*/struct Play/*玩家的结构体*/{ int x; int y; struct Fire fire[6]; life;}play;struct Amy/*敌人的结构体*/{ int x; int y; int speed;/*敌人的速度*/ int color; int direction; life;}amy[6];void InitGraph(void);/*形初始化*/void CloseGraph(void);/*形结束*/void GamePlay(void);/*具体玩游戏*/void DrawPlay(void);/*画玩家*/void DrawAmy(int i);/*画敌人*/void DrawFire(int x,int y,int n);/*画子弹,0去除,1显示*/void DrawAmyFire(int x,int y,int n);/*画子弹,0去除,1显示*/void DrawBlack(int x,int y,int color);/*去除原来地方的物体*/void PrScore();/*输出得分*/int GetKey(int ScanCode);/*这里开始都是按键函数*/void interrupt far (*OldInt9Handler)();void far interrupt NewInt9();void InstallKeyboard();void ShutDownKeyboard();void main(void){ InitGraph();/*形初始化*/ GamePlay();/*具体玩游戏*/ CloseGraph();/*形结束*/}void InitGraph(void)/*形初始化*/{ int gd=DETECT,gm; initgraph(&gd,&gm,"c:\\tc"); cleardevice(); InstallKeyboard();}void DrawPlay(void)/*画玩家*/{ setfillstyle(SOLID_FILL,6); bar(play.x-20,play.y-10,play.x+20,play.y); setfillstyle(SOLID_FILL,4); bar(play.x-20,play.y-10,play.x-10,play.y);}void DrawAmy(int i)/*画敌人*/{ setfillstyle(SOLID_FILL,amy[i].color); bar(amy[i].x-20,amy[i].y-10,amy[i].x+20,amy[i].y); setfillstyle(SOLID_FILL,GREEN); if(amy[i].direction==1) bar(amy[i].x-20,amy[i].y-10,amy[i].x-10,amy[i].y); else bar(amy[i].x+10,amy[i].y-10,amy[i].x+20,amy[i].y);}void DrawBlack(int x,int y,int color)/*去除原来地方的物体*/{ setfillstyle(SOLID_FILL,color); bar(x-20,y-10,x+20,y);}void DrawFire(int x,int y,int n)/*画子弹,0去除,1显示*/{ if(n==0) setfillstyle(SOLID_FILL,BLUE); else setfillstyle(SOLID_FILL,0); setcolor(BLUE); fillellipse(x,y,5,5);}void DrawAmyFire(int x,int y,int n)/*画子弹,0去除,1显示*/{ if(n==0) setfillstyle(SOLID_FILL,BLUE); else setfillstyle(SOLID_FILL,YELLOW);/*敌人的炮弹是黄的*/ setcolor(BLUE); fillellipse(x,y,3,3);}void PrScore()/*输出得分*/{ setfillstyle(SOLID_FILL,8);/*把原来分数去除*/ bar(30,0,200,40); setcolor(11);/*输出新得分*/ settextstyle(0,0,2); sprintf(scorestr,"%d",score); outtextxy(30,20,scorestr);}void GamePlay(void)/*具体玩游戏*/{ int i,j; setfillstyle(SOLID_FILL,BLUE); bar(0,100,640,480); setfillstyle(SOLID_FILL,8); bar(0,0,640,99); play.x=200;play.y=99;/*玩家初始位置*/ for(i=0;i<6;i++) { play.fire[i].start=0;/*一开始的子弹都为没发射状态*/ amyfire[i].start=0; amy[i].life=0; } play.life=1; DrawPlay();/*玩家初始位置*/ PrScore();/*输出得分*/ randomize(); while(1) { for(i=0;i<6;i++)/*查找玩家是否有发射的子弹*/ { if(play.fire[i].start==1)/*发射的子弹*/ { DrawFire(play.fire[i].x,play.fire[i].y,0);/*去除原来子弹位置*/ play.fire[i].y+=3; DrawFire(play.fire[i].x,play.fire[i].y,1);/*显示新位置*/ for(j=0;j(amy[j].x-22)&&play.fire[i].x(amy[j].y-14)&&play.fire[i].y<amy[j].y+5)/*击中敌人*/ { play.fire[i].start=0;/*子弹消失*/ amy[j].life=0;/*敌人生命结束*/ score+=10;/*得分增加*/ DrawFire(play.fire[i].x,play.fire[i].y,0);/*去除原来子弹位置*/ DrawBlack(amy[j].x,amy[j].y,BLUE);/*去除敌人*/ PrScore(); } if(play.fire[i].y>480)/*子弹超出屏幕就等于消失*/ { play.fire[i].start=0; DrawFire(play.fire[i].x,play.fire[i].y,0); } } } for(i=0;i<6;i++)/*敌人炮弹的产生*/ { if(amy[i].life==1&&amy[i].color<14&&amyfire[i].start==0)/*敌人发射炮弹的条件*/ { amyfire[i].start=1; amyfire[i].x=amy[i].x; amyfire[i].y=amy[i].y-10; } } for(i=0;i<6;i++)/*敌人炮弹移动以及移动*/ { if(amyfire[i].start==1)/*子弹存在*/ { DrawAmyFire(amyfire[i].x,amyfire[i].y,0); amyfire[i].y-=2; DrawAmyFire(amyfire[i].x,amyfire[i].y,1);/*画敌人炮弹新位置*/ } if(amyfire[i].x>(play.x-14)&&amyfire[i].x<(play.x+14)&&(amyfire[i].y+3)<100)/*击中玩家*/ { play.life=0; amyfire[i].start=0; DrawAmyFire(amyfire[i].x,amyfire[i].y,0); DrawBlack(play.x,play.y,8);/*去除玩家*/ break; } if(amyfire[i].y<96)/*敌人炮弹超出海洋就消失*/ { amyfire[i].start=0; setfillstyle(SOLID_FILL,8); setcolor(8); fillellipse(amyfire[i].x,amyfire[i].y,3,3); } } delay(speed);/*间隔时间可以自己定*/ if(play.life!=1)/*玩家被击中*/ break; for(i=0;i<6;i++) { if(amy[i].life==0)/*出现一个敌人后就跳出循环*/ { amy[i].life=1; amy[i].color=rand()%4+10;/*敌人的颜色*/ amy[i].y=rand()%300+130;/*高度随机*/ amy[i].speed=2+rand()%10;/*敌人的移动速度随机*/ amy[i].direction=rand()%2;/*敌人的移动方向,0左边,1右边出来*/ if(amy[i].direction==0) amy[i].x=-20; else amy[i].x=660; break; } } if(GetKey(KEY_ESC))/*退出键*/ break; if(GetKey(KEY_SPACE))/*发射*/ { for(i=0;i<6;i++) if(play.fire[i].start==0)/*发射一颗子弹后跳出循环*/ { play.fire[i].x=play.x; play.fire[i].y=105; play.fire[i].start=1; break; } } if(GetKey(K
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值