Java坦克大战游戏设计.docx
《Java坦克大战游戏设计.docx》由会员分享,可在线阅读,更多相关《Java坦克大战游戏设计.docx(31页珍藏版)》请在冰豆网上搜索。
Java坦克大战游戏设计
北方民族大学
大作业报告
(游戏程序设计)
系(部、中心)计算机科学与工程学院
姓名王鑫学号20122201
专业软件工程 班级2012级软件三班
课程名称Java语言程序设计
作业题目名称《简易版坦克大战游戏程序设计》
起止时间2014年4月21日——2014年5月21日
成绩
指导教师签名贾艳波、林淑飞
简易版坦克大战游戏程序设计
一、游戏的基本规则
坦克种类分为敌方坦克和我方坦克,敌方有n辆蓝色坦克(n值可以自己设定),我方有一辆红色坦克,我方坦克发射子弹,击中敌人坦克后,敌方坦克消失,并产生爆炸效果,同理,敌方坦克击中我之后,我方坦克消失并爆炸。
游戏结束。
二、主要实现思想和算法
gui图形界面显示:
界面的显示是通过TankGame类(继承了JFrame)和MyPanel(继承了JPanel)类实现。
其中,MyPanel重写了paint方法,利用画笔Graphics绘制活动区域、坦克和子弹。
画坦克的思想:
选择一个参考点,如右图,首先参照参考点,画出
参考点
左边的矩形,然后参照参考点分别画出中间的正方形,
圆形,直线和右边的矩形。
这些形状组合起来就形成了
一辆坦克。
然后将画坦克的步骤封装成一个方法。
我的坦克发射子弹的思想:
首先创建一个Shot类,他拥有坐标(根据坦克的坐标换算得到)、方向、速度和是否存活的属性,因为,子弹的坐标要不断的改变,所以将它做成一个线程。
然后,在我的坦克里面定义了一个vactor(因为他是线程安全的)类集框架存放我的坦克的子弹。
然后在pannel的paint方法中绘制。
让MyPanel实现KeyListener接口,将TankGame注册让MyPanel监听,这样的话我按下j键,就在vactor里面添加一个子弹,然后让Shot实现Runnable接口,然后重写run方法,在run方法中通过改变子弹的坐标实现子弹的运动。
我的坦克移动的思想:
让MyPanel实现KeyListener接口,将TankGame注册让MyPanel监听,这样我按下相应的键,就相应的改变坦克的坐标,利用repaint重新绘制坦克。
敌人坦克移动的思想:
将敌人的坦克做成一个线程,然后在run方法中改变坦克坐标,重绘坦克。
里随机数生成不同的方向,从而让敌人的坦克自主选择方向移动。
实现动态画面的思想:
将MyPanel做成一个线程,然后将repaint函数方将run函数中,这样repaint函数就会被不断的调用,从而不断地刷新画面,达到动态效果。
判断子弹是否击中坦克的算法:
获得子弹的坐标和坦克的坐标,如果子弹坐标进入坦克坐标范围,就判为击中。
让已经死亡的坦克和子弹消失的方法:
被击中的坦克的isLive和子弹isLive的设置为false,这样,在绘制的时候会首先判断要绘制对象的isLive的值,如果为true才绘制,这样死亡的坦克和子弹就消失了。
让敌人坦克和子弹自动移动的思想:
将敌人坦克和子弹做成一个线程,然后分别在各自的run函数中添加一个修改坐标的程序段。
然后在MyPanel中启动对应的线程。
坐标不断的自动修改,另一方面,paint函数不断的重新绘制,从而让坦克和子弹自动的移动了起来。
让坦克和子弹在规定的区域内移动的方法:
通过比较坦克坐标和区域坐标范围,如果坦克坐标达到区域坐标范围边界,就不让坦克的坐标继续修改,从而将坦克控制在规定的范围。
通过比较子弹坐标和区域坐标范围,如果子弹坐标超出区域坐标范围,就将子弹的isLive置为false,这样在paint函数中就不再绘制这个子弹了,从而超出区域的子弹就消失了。
显示爆炸效果的方法:
首先我准备了一张爆炸的图片,然后创建一个爆炸的类Bomb,它拥坐标属性,和生命值属性。
还有减少生命的方法,当子弹击中坦克后,就坦克的坐标传递给Bomb,当做Bomb的坐标,然后开始绘制炸弹,同时让炸弹的生命不断减小,paint函数根据炸弹不同的生命值绘制不同大小的爆炸效果,不同的爆炸效果组合起来就形成了一个完整的爆炸。
三、游戏软件系统的设计
四、程序关键类的实现
Tank类,拥有坐标X,Y和方向,速度属性,以及对应的set和get方法。
还有判断坦克是否死亡的isLive属性。
Hero类,继承了Tank类,有子弹属性,有shotEnemy方法,和上下左右移动的方法
Shot类,实现了线程接口,run方法里面放置了修改子弹坐标和判断子弹是否处境的算法。
有坐标、速度、方向、和是否活着的属性。
炸弹类,有坐标、生命值和是否存活的属性。
有生命减少的方法。
EenmyTank类,继承了Tank类,实现了线程接口,在run方法中添加了修改坦克坐标的程序段,从而让坦克自动移动。
MyPanel类,是本游戏最主要的类,他继承了JPanel实现了keylistener和runnable接口,他的paint函数绘制了游戏中的坦克和子弹以及活动范围。
keyPressed函数监听键盘输入,run函数里面放了repaint和比较是否击中坦克的代码。
TankGame类,是本游戏的入口,其构造方法包含将面板添加到JFrame,设置窗口大小、可见性和默认的关闭方式。
五、游戏软件的主要界面截图
六、程序代码:
importjavax.swing.*;
publicclassTankGameextendsJFrame{
//面板
MyPanelmp=null;
publicstaticvoidmain(String[]args){
//创建窗口
TankGametankegame=newTankGame();
}
//构造函数
publicTankGame(){
//创建面板对象
mp=newMyPanel();
//将面板添加到JFrame
this.add(mp);
this.addKeyListener(mp);
//启动面板线程,让其paint方法不断调用,从而不断刷新,达到动态效果
Threadt=newThread(mp);
t.start();
//设置窗口大小
this.setSize(400,300);
//设置小图标
this.setIconImage(newImageIcon("image/tk.png").getImage());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
**********************************************
publicclassTank{
//坦克的很坐标
intx;
//坦克的纵坐标
inty;
//坦克的方向
//0表示上,1右,2下,3表示左
intdirect=0;
//坦克的速度
intspeed=4;
//坦克的外观
intcolor=0;
//坦克是否死亡
booleanisLive=true;
publicintgetColor(){
returncolor;
}
publicvoidsetColor(intcolor){
this.color=color;
}
publicintgetSpeed(){
returnspeed;
}
publicvoidsetSpeed(intspeed){
this.speed=speed;
}
publicintgetDirect(){
returndirect;
}
publicvoidsetDirect(intdirect){
this.direct=direct;
}
publicTank(intx,inty){
this.x=x;
this.y=y;
}
publicintgetX(){
returnx;
}
publicvoidsetX(intx){
this.x=x;
}
publicintgetY(){
returny;
}
publicvoidsetY(inty){
this.y=y;
}
}
***********************************************
importjava.util.Vector;
publicclassHeroextendsTank{
//放置子弹的类集框架
Vectorss=newVector();
//子弹
Shots=null;
publicHero(intx,inty){
super(x,y);
}
//开火
publicvoidshotEnemy(){
switch(this.direct){
case0:
s=newShot(x+10,y,0);
ss.add(s);
break;
case1:
s=newShot(x+30,y+10,1);
ss.add(s);
break;
case2:
s=newShot(x+10,y+30,2);
ss.add(s);
break;
case3:
s=newShot(x,y+10,3);
ss.add(s);
break;
}
//启动子弹线程
Threadt=newThread(s);
t.start();
}
//坦克向上移动
publicvoidmoveUp(){
y-=speed;
}
//坦克向右移动
publicvoidmoveRiget(){
x+=speed;
}
//坦克向下移动
publicvoidmoveDown(){
y+=speed;
}
//坦克向左移动
publicvoidmoveLeft(){
x-=speed;
}
}
*******************************************************************************
importjava.awt.*;
importjava.awt.event.KeyEvent;
importjava.awt.event.KeyListener;
importjava.util.Vector;
importjavax.swing.*;
publicclassMyPanelextendsJPanelimplementsKeyListener,Runnable{
//定义一个我的坦克
Herohero=null;
//定义敌人的坦克组,用Vector,因为他是线程安全的
Vectorets=newVector();
//敌人坦克的初始量
intenSize=2;
//定义炸弹集合
Vectorbombs=newVector();
//定义爆炸图片
Imageimage1=null;
Imageimage2=null;
Imageimage3=null;
//定义背景图片
Imageimagebg=null;
//MyPanel构造函数
publicMyPanel(){
//初始化我的坦克
hero=newHero(200,200);
//初始化敌人的坦克
for(inti=0;iEnemyTanket=newEnemyTank((i+1)*50,0);
//设置颜色
et.setColor
(1);
//设置方向
et.setDirect
(2);
//启动敌人坦克
Threadt=newThread(et);
t.start();
//给敌人坦克添加子弹
Shots=newShot(et.x+10,et.y+30,2);
et.ss.add(s);
Threadt2=newThread(s);
t2.start();
//加入类集框架
ets.add(et);
}
//初始化爆炸图片
image1=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bom.png"));
image2=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bom.png"));
image3=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bom.png"));
//初始化背景图片
imagebg=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bg.jpg"));
}
//重写paint(必须的步骤)
publicvoidpaint(Graphicsg){
super.paint(g);
//画一个活动区域
g.drawImage(imagebg,0,0,400,300,this);
if(hero.isLive==true){
//画我的坦克
this.drawTank(hero.getX(),hero.getY(),g,this.hero.getDirect(),this.hero.getColor());
}
//从ss中取出每颗子弹,并绘制
for(inti=0;iShotmyShot=this.hero.ss.get(i);
//画一颗子弹,要先判断是否为空,因为坦克刚创建的时候,没有按J的时候,子弹是空的,这个时候不能画,要不然会异常
if(myShot!
=null&&myShot.isLive==true){
g.draw3DRect(myShot.x,myShot.y,1,1,false);
}
//判断子弹是否死亡,如果死亡,就从Vocetor中移除
if(myShot.isLive==false){
hero.ss.remove(myShot);
}
}
//画出敌人的坦克
for(inti=0;iEnemyTanket=ets.get(i);
if(et.isLive){
this.drawTank(et.getX(),et.getY(),g,et.getDirect(),et.getColor());
//画出敌人的子弹
for(intj=0;j//取出子弹
ShotenemyShot=et.ss.get(j);
//开始画
if(enemyShot.isLive){
g.draw3DRect(enemyShot.x,enemyShot.y,1,1,false);
}else{
//如果子弹死亡,就把子弹移除
et.ss.remove(enemyShot);
}
}
}
}
//画出炸弹
for(inti=0;i//取出炸弹
Bombb=bombs.get(i);
//画炸弹。
根据不同的生命值爆炸不同的大小
if(b.life>6){
g.drawImage(image1,b.x,b.y,30,30,this);
}elseif(b.life>3){
g.drawImage(image2,b.x,b.y,15,15,this);
}else{
g.drawImage(image3,b.x,b.y,5,5,this);
}
//减小炸弹的生命值
b.lifeDown();
//如果炸弹死亡,就移除数组
if(b.life==0){
bombs.remove(b);
}
}
}
//判断敌人是否击中我
publicvoidhitMe(){
//取出每一个敌人
for(inti=0;i//取出坦克
EnemyTanket=ets.get(i);
//取出每一辆坦克的子弹
for(intj=0;j//取出子弹
ShotenemyShot=et.ss.get(j);
this.hitTank(enemyShot,hero);
}
}
}
//判断我的子弹是否击中敌人的坦克
publicvoidhitEnemyTank(){
//判断是否击中
for(inti=0;i//取出子弹
ShotmyShot=hero.ss.get(i);
//判断子弹是否还活着
if(myShot.isLive){
//遍历敌人坦克,判断子弹和坦克坐标
for(intj=0;j//取出坦克
EnemyTanket=ets.get(j);
if(et.isLive){
this.hitTank(myShot,et);
}
}
}
}
}
//判断子弹是否碰撞到坦克的函数
publicvoidhitTank(Shots,Tanket){
//判断敌军坦克的方向
switch(et.direct){
//向上或者向下的情况下
case0:
case2:
if(s.x>et.x&&s.xet.y&&s.y//击中
//子弹死亡
s.isLive=false;
//坦克死亡
et.isLive=false;
//创建一个炸弹,放入Vector
Bombb=newBomb(et.x,et.y);
bombs.add(b);
}
//向左或者向右的情况下
case1:
case3:
if(s.x>et.x&&s.xet.y&&s.y//击中
//子弹死亡
s.isLive=false;
//坦克死亡
et.isLive=false;
//创建一个炸弹,放入Vector
Bombb=newBomb(et.x,et.y);
bombs.add(b);
}
}
}
//画坦克的函数。
四个参数分别为:
起始画的坐标,方向,类型
publicvoiddrawTank(intx,inty,Graphicsg,intdirect,inttype){
//判断坦克的类型
switch(type){
case0:
g.setColor(Color.RED);//我的坦克
break;
case1:
g.setColor(Color.blue);//敌军坦克
break;
}
switch(direct){
case0:
//炮筒向上
//画坦克
//第一步画左边的那条履带
g.fill3DRect(x,y,5,30,false);//四个参数分别表示起始点和大小
//第二步画出右边的那条履带
g.fill3DRect(x+15,y,5,30,false);
//第三部画出中间的驾驶舱
g.fill3DRect(x+5,y+5,10,20,false);
//第四部画出中间的炮塔
g.fillOval(x+5,y+9,10,10);
//第五步画出炮筒
g.drawLine(x+10,y+15,x+10,y);//四个参数分别表示起始点和终止点
break;
case1:
//炮筒向右
//画坦克
//第一步画上边的那条履带
g.fill3DRect(x,y,30,5,false);//四个参数分别表示起始点和大小
//第二步画出下边的那条履带
g.fill3DRect(x,y+15,30,5,false);
//第三部画出中间的驾驶舱
g.fill3DRect(x+5,y+5,20,10,false);
//第四部画出中间的炮塔
g.fillOval(x+9,y+5,10,10);
//第五步画出炮筒
g.drawLine(x+15,y+10,x+30,y+10);//四个参数分别表示起始点和终止点
break;
case2:
//炮筒向下
//第一步画左边的那条履带
g.