java坦克游戏双人对战版_第1页
java坦克游戏双人对战版_第2页
java坦克游戏双人对战版_第3页
java坦克游戏双人对战版_第4页
java坦克游戏双人对战版_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 坦克大战双人对战版 班级: 姓名:yangxixi 学号:任务:游戏设计,代码书写,调试 班级: 姓名: 学号:任务:代码调试,美工1、 游戏介绍:本游戏实现坦克大战双人对战,添加了超级炮弹,增加友军数量,复活等选项。目前是单机版,网络版代码目前已实现联网对战。P1玩家:WASD控制移动方向,F发射子弹,G发射超级炮弹,Q复活E增加5个友军,B清空;P2玩家:上下左右方向键控制移动方向,Ctrl发射子弹,I发射超级炮弹,O复活P增加5个友军,B清空;2 设计思路:1. 画出主窗口,坦克,实现自己坦克八个方向的移动:通过对按键监听,判断出坦克移动方向,再根据方向改变坦克位置,实现坦克的移动;2

2、.产生敌人坦克:改变坦克好坏变量,增加敌人坦克;3.加入子弹,能够打击敌人:增加子弹类,封装所需信息,在合适位置创建子弹类对象;4.让敌人能够移动:用随机数产生器给坦克增加随机的方向,子弹;5.加入爆炸:增加爆炸类,在合适的地方创建对象;6.加入墙,解决碰撞问题:增加墙类,在合适的地方创建对象;7.加入血块:增加血块类,在合适的地方创建对象; 加入血量显示:在我的坦克位置上方画出血量;8.添加超级炮弹,加入键位控制。9.加入图片:加入图片让游戏更加美观。10.加入另一两主战坦克,实现双人对战:产生另一辆坦克,以your变量区分,增加键盘控制;3 关键代码TankClient.java,Tank

3、.java, Wall.java,Missile.java,Explode.javaBlood.java一共6个java文件,其他每个类都拿到一个TankClient类的引用,方便对其变量,常量,方法的调用。1. 实现自己坦克八个方向的移动:首先TankClient继承Frame,新建一个窗口,添加窗口关闭事件处理信息,固定窗口大小,:/* * 这个方法画出游戏的主窗口 */publicvoid launchFrame() for(inti=0;i5;i+)this.tanks.add(new Tank(50+(i+1)*40,50,false,false,false,this);this.s

4、etBounds(Startx, Starty,Image_Width,Image_LENGTH);this.setTitle(TankWar);this.setBackground(Color.black);this.setVisible(true);this.setResizable(false);/* * 添加窗口关闭监听 */this.addWindowListener(new WindowAdapter() publicvoid windowClosing(WindowEvent e) sw=false;System.exit(0);重写paint方法,负责画出坦克,画出时只需调用坦

5、克的draw方法(体现面向对象思维),意味着新建tank类,用于封装坦克信息,暂时用实心圆表示坦克,重写update方法,将坦克图像先画到一张图片上再画到屏幕上:myTank.draw(g);yourTank.draw(g);w1.draw(g);w2.draw(g);w3.draw(g);w4.draw(g);b.draw(g);publicvoid update(Graphics g) if(offScreenImage=null)offScreenImage=this.createImage(Image_Width,Image_LENGTH); Graphics goffScreen=o

6、ffScreenImage.getGraphics(); Color c=goffScreen.getColor();goffScreen.setColor(new Color(139, 139, 0);goffScreen.fillRect(0, 0, Image_Width,Image_LENGTH); paint(goffScreen);g.drawImage(offScreenImage, 0, 0, null);接下来创建一个新的线程类,每隔80ms重画一次,当坦克的位置改变时,画面中就会出现坦克的移动,repaint方法会自动调用paint方法:publicclass PaintT

7、hread implements Runnable/* * 重写run方法 */publicvoid run() while(sw)repaint();try Thread.sleep(80); catch (InterruptedException e) e.printStackTrace();接下来让坦克听从我们的指挥移动,添加键盘监听器类KeyMonitor,在tank类中添加move方法及方向属性,move方法根据坦克方向改变坦克位置:caseL:x -= x_SPEED;break;caseLU:x -= x_SPEED;y -= y_SPEED;break;caseU:y -= y

8、_SPEED;break;caseUR:x += x_SPEED;y -= y_SPEED;break;caseR:x += x_SPEED;break;caseRD:x += x_SPEED;y += y_SPEED;break;caseD:y += y_SPEED;break;caseLD:x -= x_SPEED;y += y_SPEED;break;caseSTOP:break;default:而在监听类中,先根据键盘读出上下左右(由keypressed方法完成),再判断是否有两个方向同时被按下(locateDirections方法完成):publicvoidkeyPressed(Ke

9、yEvent e) intkey = e.getKeyCode();switch (key) case KeyEvent.VK_CONTROL:fire();break;case KeyEvent.VK_LEFT:bL = true;break;case KeyEvent.VK_UP:bU = true;break;case KeyEvent.VK_RIGHT:bR = true;break;case KeyEvent.VK_DOWN:bD = true;break;default:break;locateDirections();publicvoidlocateDirections() if

10、 (bL& !bU& !bR& !bD)dir = Directions.L;if (bL&bU& !bR& !bD)dir = Directions.LU;if (!bL&bU& !bR& !bD)dir = Directions.U;if (!bL&bU&bR& !bD)dir = Directions.UR;if (!bL& !bU&bR& !bD)dir = Directions.R;if (!bL& !bU&bR&bD)dir = Directions.RD;if (!bL& !bU& !bR&bD)dir = Directions.D;if (bL& !bU& !bR&bD)dir

11、 = Directions.LD;if (!bL& !bU& !bR& !bD)dir = Directions.STOP;TankCient添加键盘监听器,针对不同的键改变坦克的位置,与重画线程结合产生不同方向运动:publicvoid keyPressed(KeyEvent e) myTank.keyPressed(e);yourTank.keyPressed1(e);addEnemTanks(e);addMyTanks(e);addMineTanks(e);cleanAll(e);superMissile(e);这样我们就实现流坦克根据键盘按键向八个方向移动。补充一点,处理坦克出界问题,

12、判断是否达到边界,若是,则改变坦克位置:if (x 0)x = 0;if (y TankClient.Image_Width)x = TankClient.Image_Width - Tank.width;if (y + Tank.length TankClient.Image_LENGTH)y = TankClient.Image_LENGTH - Tank.length;/ 子弹出界的问题2. 产生敌人坦克:为了区别坦克好坏,我们在tank里添加good属性,在draw方法里根据good选不同的颜色,并在TankClient类里创建敌人坦克:for(inti=0;i5;i+)this.ta

13、nks.add(new Tank(50+(i+1)*40,50,false,false,false,this);在TankClient类里面增加tanks集合永丰余存放坦克对象。Listtanks=new ArrayList();(注意这里用到了泛型)3. 加入子弹:添加子弹Missile类,其中包括子弹的位置,速度,等基本信息,有自己的构造方法,draw方法,在TankClient类里面添加;一个集合存放子弹:Listmissiles=new ArrayList();(注意这里用到了泛型)在paint方法里画出missiles集合里面的每一个对象。接下来便是让坦克打出一发炮弹,于是在tank

14、类里增加监听Ctrl键,并且增加方法fire,每当被按下时,便创建一个missile对象添加到集合里:publicvoidfire() if (this.live)tc.missiles.add(new Missile(x + width / 2 - Missile.width / 2, y + length / 2 - Missile.length / 2, good,ptdir, tc);而在tank类里增加一个炮筒,炮筒的方向就是子弹的方向,炮筒用黑色直线画出来:if (dir != Directions.STOP)ptdir = dir;switch (ptdir) caseL:g.d

15、rawImage(imgs.get(L), x, y, null);break;caseLU:g.drawImage(imgs.get(LU), x, y, null);break;caseU:g.drawImage(imgs.get(U), x, y, null);break;caseUR:g.drawImage(imgs.get(RU), x, y, null);break;caseR:g.drawImage(imgs.get(R), x, y, null);break;caseRD:g.drawImage(imgs.get(RD), x, y, null);break;caseD:g.d

16、rawImage(imgs.get(D), x, y, null);break;caseLD:g.drawImage(imgs.get(LD), x, y, null);break;default:break;子弹出界问题同坦克,但是此时增加blive属性表示子弹的生命,当坦克出界时,子弹生命结束,从集合中移除if(!myMissile.isLive() missiles.remove(i);elsemyMissile.draw(g);4.让敌人能够移动:而为了让敌人坦克移动起来,在坦克里面创建一个随机数产生器,随机产生坦克方向使其移动,其中step用来存储坦克随机移动步骤:if (!mine

17、& !your) if (step = 0) step = rn.nextInt(20) + 5;dir = dirsrn.nextInt(dirs.length);if (rn.nextInt(50) 46)fire();step-;使用随机数控制子弹产生:if (rn.nextInt(50) 46)fire();5. 加入爆炸:爆炸表示坦克被击毙。首先判断一个坦克是否被打中,此时需要给子弹添加一个新的属性good,区分好坏:privatebooleangood;然后拿到给tank,missile类都增加getRectangle()方法,拿到边界,然后在missile类里面增加hitTank

18、()方法,判断子弹是否存活,边界是否交叉,坦克是否存活,坦克的好坏,若都满足条件,则子弹和坦克均死亡。if (this.live&this.getRectangle().intersects(enem.getRectangle() &enem.isLive()&this.good != enem.isGood() if(!enem.isMine()&!enem.isYour()/判断敌我坦克能否被一炮打死enem.setLive(false);Explode e = new Explode(x, y, tc);tc.explodes.add(e);returntrue;接着创建一个新的Expl

19、ode类,封装位置等信息,拥有draw方法,一开始爆炸通过画出不同半径的圆来表示,后面则用图片。publicExplode(intx, inty, TankClient tc) this.x = x;this.y = y;this.tc = tc;每当有坦克被击中时,在坦克的位置上添加一个爆炸对象,将坦克的位置信息传递给坦克:Explode e = new Explode(x, y, tc);最后是保证每一颗子弹都能击中每一辆坦克,在missile类里面添加hittanks方法,打击每一辆坦克:for (inti = 0; itanks.size(); i+) if (hitTank(tank

20、s.get(i)returntrue;在TankClient类里面创建一个集合用来装爆炸对象:Listexplodes=new ArrayList();里面的对象都在paint方法里画出来:if(!live) tc.explodes.remove(this);return;if(step = imgs.length) live = false;step = 0;return;g.drawImage(imgsstep, x, y, null);6.加入墙:增加墙类,在合适的地方创建对象;首先创建新的Wall类,封装墙的信息,建立Wall对象、墙有自己的draw方法可以把自己画出来:publicv

21、oid draw(Graphics g) Color c=g.getColor();g.setColor(Color.black);g.fillRect(x, y, width, height);g.setColor(c); Wall w1=new Wall(150, 200, 20, 150,this);Wall w2=new Wall(250, 100, 300, 20,this);Wall w3=new Wall(600, 200, 20, 150,this);Wall w4=new Wall(250, 450, 300, 20,this);增加拿到墙的边界的getRectangle方法

22、:publicRectangle getRectangle()returnnew Rectangle(x, y, width, height); 然后让每一颗子弹打击每一堵墙,在子弹里增加hitWall()方法,在方法里面,判断子弹是否击中墙,若打中,则子弹死亡:publicbooleanhitWall(Wall wall) if (this.live&this.getRectangle().intersects(wall.getRectangle() this.live = false;returntrue;returnfalse;注意:在测试过程中,子弹速度不能太快,否则很容易穿过墙,所以

23、当时调整了子弹的速度。接下来,让坦克不能穿过墙,这和子弹不同,当AI坦克碰到墙之后,若让坦克停止则坦克就一直移动不了,因为一直会判断坦克与墙边界接触,所以要记录坦克上一次的位置oldX, oldY,每当坦克碰到墙,就需要让坦克回到上一次位置:publicvoid move() this.old_x = x;this.old_y = y;在移动之前要记录上一次位置。在tank类里面增加collidsWall(Wall)方法:publicbooleancollidsWall(Wall wall) if (this.live&this.getRectangle().intersects(wall.g

24、etRectangle() this.stay();returntrue;publicvoidstay() x = old_x;y = old_y;Stay方法是让坦克回到上一次位置最后开始解决坦克之间的碰撞问题:首先应该在tank类增加collidsTanks(List)方法,注意里面参数需要传tanks集合,for (inti = 0; itanks.size(); i+) Tank t = tanks.get(i);if (this.live&t.isLive() &this.getRectangle().intersects(t.getRectangle() &t != this) t

25、his.stay();判断坦克是否相撞,相撞则stay。7. 加入血块:增加血块类,在合适的地方创建对象;首先血块能让坦克恢复HP,在此之前需要给坦克增加生命值属性privateintlife = 100初始值为100.然后依据life值给我的坦克画出血量,为此在坦克里增加一个内部类,拥有draw方法,负责画出血条:classBloodBar publicvoid draw(Graphics g) Color c = g.getColor();if(mine) g.setColor(Color.red);if(your) g.setColor(Color.blue);g.drawRect(x+

26、9, y - 10, width-20, 10);intw = (width-20) * life / 100;g.fillRect(x+9, y - 10, w, 10);g.setColor(c);为此修改missile类的hittank方法:if(!enem.isMine()&!enem.isYour()/判断敌我坦克能否被一炮打死elseenem.setLife(enem.getLife()-20);Explode e = new Explode(x, y, tc);tc.explodes.add(e);if(enem.getLife()=0) enem.setLive(false);

27、e = new Explode(x, y, tc);tc.explodes.add(e);returntrue;每次打中减少20生命值,然后life=0时,我的坦克死亡。接下来创建新的Blood类,封装位置,大小,移动路径等信息:/* * 这个二维数组存储血块移动的路线 */privateint loc=400,400,410,400,420,400,430,400,440,400,450,400, 450,410,450,420,450,430,450,440,450,450,440,450,430,450,420,450, 410,450,400,450,400,440,400,430,4

28、00,420,400,410,400,400;/* * 血块的移动方法 */publicvoid move()step+;if(step=loc.length)step=0; this.x=locstep0;this.y=locstep1; 根据移动位置画出血块位置:publicvoiddraw(Graphics g)if(!live) return; Color c=g.getColor();g.setColor(Color.MAGENTA);g.fillRect(x, y, w, h);g.setColor(c); move(); 然后给血块增加live属性,表示血块生命值,拿到边界:pu

29、blic Rectangle getRectangle()returnnew Rectangle(x, y, w, h); 接着在tank类里面增加collidsBlood(Blood)方法:publicbooleancollidsBlood(Blood b) if (this.live& (this.mine | this.your) &this.getRectangle().intersects(b.getRectangle() b.setLive(false);this.setLife(100);returntrue;returnfalse;只有我的坦克能够触碰到血块,接触后,坦克的生命

30、值加满,血块死亡。在TankClient类里面创建血块对象并画出来Blood b=new Blood();b.draw(g);到此血块添加完毕。8. 添加超级炮弹,加入键位控制超级炮弹就是向八个方向发射子弹,添加superFire()方法,拿到8个方向,向missiles集合中添加8个对象,方向不同。publicvoidsuperFire() Directions dirs = Directions.values();for (inti = 0; idirs.length - 1; i+) if (this.live)tc.missiles.add(new Missile(x + width

31、/ 2 - Missile.width / 2, y + length / 2 - Missile.length / 2,good, dirsi, tc);在TankClient类里里面添加监听,当I按下时,调用superFire()方法publicvoidsuperMissile(KeyEvent e)intkey = e.getKeyCode();switch (key) case KeyEvent.VK_I:myTank.superFire();break;case KeyEvent.VK_G:yourTank.superFire();break;default:break; 增加O键使

32、我的坦克复活,TankClient类中添加监听,判断我的坦克是否存活,若死亡则复活有效:switch (key) case KeyEvent.VK_O:if(!myTank.isLive()myTank=new Tank(x, y,true,true,false,this);增加P键添加我方友军,友军是good属性与我一致的:case KeyEvent.VK_P:for(inti=0;i5;i+)this.tanks.add(new Tank(50+(i+1)*40,500,true,false,false,this);break;每次添加5辆增加B键清除画面中坦克,子弹:intkey = e

33、.getKeyCode();switch (key) case KeyEvent.VK_B:myTank.setLive(false);yourTank.setLive(false);for(inti=0;itanks.size();i+)tanks.get(i).setLive(false);for(inti=0;imissiles.size();i+)Missile myMissile=missiles.get(i);myMissile.setLive(false);9. 加入图片:加入图片让游戏更加美观将修剪好的图片添加进工程,在tank类里面创建Toolkit对象privatestat

34、ic Toolkit tk = Toolkit.getDefaultToolkit();用一个数组存储拿到的图片:tankImgs = new Image tk.getImage(Explode.class.getClassLoader().getResource(Images/tankD.gif),tk.getImage(Explode.class.getClassLoader().getResource(Images/tankL.gif),然后修改draw方法:caseL:g.drawImage(imgs.get(L), x, y, null);以上是坦克8个方向的图片,当然边界方法也得修

35、改。10. 加入另一两主战坦克,实现双人对战:双方坦克都增加变量mine,和your,区别双方,mine坦克good属性是true。而your的是false,这样坦克双方可以开火打击对方 * 甲方 */privatebooleanmine;/* *乙方 */privatebooleanyour;接下来像mine坦克那样增加键位控制,:* 乙方坦克键盘监听 * param e */publicvoidkeyPressed1(KeyEvent e) intkey = e.getKeyCode();switch (key) case KeyEvent.VK_F:fire();break;case K

36、eyEvent.VK_A:bL = true;break;case KeyEvent.VK_W:bU = true;break;case KeyEvent.VK_D:bR = true;break;case KeyEvent.VK_S:bD = true;break;default:Missile,tank类里面有mine的地方都要加上your属性控制:if (mine&live)bb.draw(g);if (your&live)bb.draw(g);到此双人对战功能完成!四运行结果:文件目录:开始界面:增加5个友军坦克:复活:Q键:发射超级炮弹:B键清零:血块加血:五代码及总结:游戏一共经历

37、了25个版本,从最开始的画出一个移动的圆圈,到加入坦克图片,子弹,墙,这是一个很漫长却又让人激动的过程,这个游戏主要综合使用到了J2SE部分数组,类,线程,异常,集合,GUI等知识,一个游戏写下来,感觉对于这部分知识有了更加深刻的理解,学一门语言真是要靠敲代码才能真正学会它,而这也是理解项目如何完成的一个过程,一个版本一个版本的增加新的功能,真是万丈高楼平地起啊!我们还用eclipse生成了javadoc文档,以下是API文档截图:代码:TankClient.javapackage Java.Tank.yangxixi;import java.awt.*;import java.awt.eve

38、nt.*;import java.util.List;import java.util.ArrayList;/* * 这个类是游戏的主窗口,实现各个部件的添加,图像的显示。 * author yangxixi * */public class TankClient extends Frame /* * 主窗口的宽度 */public static final int Image_Width=800;/* * 主窗口的高度 */public static final int Image_LENGTH=600;/* * 初始位置x */public static final int Startx=

39、250;/* * 初始位置y */public static final int Starty=80;/* * 整个窗口的开始与结束 */private boolean sw=true;/* * 坦克初始位置x,y */int x=500,y=500;Tank myTank=new Tank(x, y,true,true,false,this);Tank yourTank=new Tank(x-400, y-400,false,false,true,this);List tanks=new ArrayList();List missiles=new ArrayList();List explo

40、des=new ArrayList();Image offScreenImage=null;Wall w1=new Wall(150, 200, 20, 150,this);Wall w2=new Wall(250, 100, 300, 20,this);Wall w3=new Wall(600, 200, 20, 150,this);Wall w4=new Wall(250, 450, 300, 20,this);Blood b=new Blood();/* * 这个方法画出每个元素 */public void paint(Graphics g) Color c=g.getColor();g

41、.setColor(Color.black);/g.drawString(missiles count: +missiles.size(), 10, 50);/g.drawString(explodes count: +explodes.size(), 10, 60);g.drawString(蓝方坦克数: +getEnem(), 10, 70);g.drawString(红方坦克数: +(tanks.size()-getEnem(), 10, 85);g.drawString(HP1: +myTank.getLife(), 10, 100);g.drawString(HP2: +yourTa

42、nk.getLife(), 10, 115);g.setColor(c);/每个子弹攻击其他坦克,并判断子弹是否存活,死亡则去除for(int i=0;imissiles.size();i+)Missile myMissile=missiles.get(i);/if(myMissile.hitTanks(tanks) missiles.remove(i);myMissile.hitTanks(tanks);if(!myMissile.isLive() missiles.remove(i);else myMissile.draw(g);/画出我的坦克,墙myTank.draw(g);yourTa

43、nk.draw(g);w1.draw(g);w2.draw(g);w3.draw(g);w4.draw(g);b.draw(g);/画出友军坦克for(int i=0;itanks.size();i+)tanks.get(i).draw(g);/tanks.get(i).collidsWall(w1);/tanks.get(i).collidsWall(w2);/画出子弹for(int i=0;iexplodes.size();i+)Explode e=explodes.get(i);e.draw(g);/* * 这个方法先把图像画到一张图片上,再把图片画到屏幕上 */ public void

44、 update(Graphics g) if(offScreenImage=null) offScreenImage=this.createImage(Image_Width,Image_LENGTH); Graphics goffScreen=offScreenImage.getGraphics(); Color c=goffScreen.getColor(); goffScreen.setColor(new Color(139, 139, 0); goffScreen.fillRect(0, 0, Image_Width,Image_LENGTH); paint(goffScreen);

45、g.drawImage(offScreenImage, 0, 0, null); /* * 主方法,创建类实体并开始 * param args */public static void main(String args) TankClient tc=new TankClient(); tc.launchFrame();/* * 这个方法画出游戏的主窗口 */public void launchFrame() for(int i=0;i5;i+)this.tanks.add(new Tank(50+(i+1)*40,50,false,false,false,this);this.setBound

46、s(Startx, Starty,Image_Width,Image_LENGTH);this.setTitle(TankWar);this.setBackground(Color.black);this.setVisible(true);this.setResizable(false);/* * 添加窗口关闭监听 */this.addWindowListener(new WindowAdapter() public void windowClosing(WindowEvent e) sw=false;System.exit(0);); this.addKeyListener(new KeyM

47、onitor(); new Thread(new PaintThread().start();/* * 这个内部类继承Runnable接口,在另一个线程里每隔80毫秒重画一次,实现画面的更新 * author yangxixi * */public class PaintThread implements Runnable/* * 重写run方法 */public void run() while(sw)repaint();try Thread.sleep(80); catch (InterruptedException e) e.printStackTrace();/* * 这个类用于监听键

48、盘反应 * author yangxixi * */class KeyMonitor extends KeyAdapter/* * 重写keyReleased方法 */public void keyReleased(KeyEvent e) myTank.KeyReleased(e);yourTank.KeyReleased1(e);/* * 重写keyPressed方法 */public void keyPressed(KeyEvent e) myTank.keyPressed(e);yourTank.keyPressed1(e);addEnemTanks(e);addMyTanks(e);addMineTanks(e);cleanAll(e);superMissile(e);/* * 用E键控制敌军坦克 * param e */public void addEnemT

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论