Java-坦克大战
利用Java语言中的集合、Swing、线程等知识点编写一个坦克大战游戏。
(1) 画出敌我坦克的原理:
在坦克类里面有一个布尔类型变量good。用于判断坦克的阵营,在创建坦克对象时在Tank类的构造方法中传入good的值。在画坦克的时候判断good的值,区分敌我坦克的颜色;
(2) 坦克运动的原理:
在坦克类里写入了监听键盘摁键的响应事件,对监听到的上下左右键进行记录,并合成坦克移动的八个方向的变量。之后对应每个方向的不同对坦克坐标x,y的值做响应的更改实现我方坦克的移动。而敌方坦克则自动移动,通过随机数对敌方坦克移动方向的随机,并且随机出每次移动的次数。两个随机值相结合即实现了敌方坦克的移动。
(3) 坦克发射子弹的原理:
通过键盘监听,检测到发射子弹命令后将主类的子弹类集合中添加一个子弹类。将炮筒的方向以及坦克的位置以及坦克的阵营传入给子弹类,在主类paint画方法中一直循环子弹类集合,如果集合内有子弹,就画出来。这样就实现了发射子弹。
(4) 坦克、子弹、墙的碰撞原理:
在坦克类子弹类墙类中分别getRect方法获取自身的范围,然后在每次画坦克、子弹时都会进行相应的碰撞检测(在坦克类里有与墙和出自己外的坦克相撞的处理方法、在子弹类里有与墙和坦克相碰撞的处理方法。),如果自身与不该碰撞的物体的范围相重合,则代表两物体相撞。
(5)坦克加血的原理:
在血块类中有血块与我方坦克相碰撞的处理方法,如果血块范围与坦克范围重合则血块类死亡,并且坦克类的血量回复置满。
(6)坦克复活的原理:
通过键盘监听,检测到我方坦克复活命令后,如果我方坦克处于死亡状态,则将我方坦克存货状态改为活着并且将我方坦克血量回置满血。
编程思想:
坦克大战的编程思想在主类开启一个线程,没50毫秒循环一次画方法(绘制整个界面内的所有东西)。画的东西有敌我坦克(颜色区分)、子弹、墙、血块、爆炸。所以总共写出了几个类:Tank坦克类、Missile子弹类、Wall墙类、Blood血块类、TankClient主类。在每一个类中均写有画方法实现本类属性的绘制功能。在主类中有键盘监听事件调用这Tank类的键盘监听事件。通过键盘监听判断出对Tank做出相应的移动,而敌方Tank则是随机运动。并且每次刷新都有调用各类的碰撞方法,判断一些不该碰撞的对象的情况时做出处理。而每个对象的创建例如子弹这些是在触发产生之后将新建子弹类加入一个子弹类集合之中,在绘制的时候判断集合中的数量进行绘制,出界或者打死坦克则在集合中删除。其他类也均相似,不在细说。
代码中每步都注释有相应的解释。
TankClient.java
1 import java.awt.Color; 2 import java.awt.Font; 3 import java.awt.Graphics; 4 import java.awt.Image; 5 import java.awt.event.KeyAdapter; 6 import java.awt.event.KeyEvent; 7 import java.awt.event.WindowAdapter; 8 import java.awt.event.WindowEvent; 9 import java.util.ArrayList; 10 import java.util.List; 11 12 import javax.swing.JFrame; 13 14 public class TankClient extends JFrame{ 15 /** 16 * @param args 17 */ 18 Image OffScrennImage = null; //双缓冲内存图片存储 19 /*游戏大小*/ 20 public static final int GAME_WIDTH = 800; //界面宽 21 public static final int GAME_HEIGTH = 600; //界面高 22 23 Tank myTank = new Tank(500,400,true,Color.red,Tank.Direction.STOP, this);//我方坦克类 24 List<Missile> missiles = new ArrayList<Missile>();//子弹的集合 25 List<Explode> explode = new ArrayList<Explode>();//爆炸集合 26 List<Tank> tanks = new ArrayList<Tank>(); //坦克集合 27 Wall wall1 = new Wall(150,200,20,300,this); //墙1 28 Wall wall2 = new Wall(250,500,300,20,this); //墙2 29 Wall wall3 = new Wall(650,200,20,300,this); //墙2 30 Wall wall4 = new Wall(250,300,300,20,this); //墙2 31 Wall wb = new Wall(750,550,40,40,this); //墙2 32 Blood b = new Blood(); //血类 33 34 35 public static void main(String[] args) { 36 // TODO Auto-generated method stub 37 TankClient tc=new TankClient(); 38 tc.lauchFrame(); 39 } 40 41 private void lauchFrame() { 42 // TODO Auto-generated method stub 43 for (int i = 0; i < 10; i++){ 44 tanks.add(new Tank(50+40*(i+1), 50, false,Color.blue,Tank.Direction.D, this)); 45 } 46 this.setLocation(100, 100); //窗口初始坐标点 47 this.setSize(GAME_WIDTH, GAME_HEIGTH); //窗口初始大小 48 this.setTitle("TankWar"); //窗口名称 49 /*窗口监听*/ 50 this.addWindowListener(new WindowAdapter() { 51 @Override 52 /*点退出叉之后运行*/ 53 public void windowClosing(WindowEvent e) { 54 // TODO Auto-generated method stub 55 System.exit(0); //退出 56 } 57 }); 58 this.addKeyListener(new KeyMoniton()); //设置键盘监听 59 this.setVisible(true); //设置窗口显现 60 this.setResizable(false); //设置窗口不可改变大小 61 this.getContentPane().setBackground(Color.green); //设置窗口前景色为绿色 62 new Thread(new PaintThread()).start(); //开始运行PaintThread类run 63 } 64 65 @Override 66 public void paint(Graphics g) { 67 // TODO Auto-generated method stub 68 //Graphics为画笔类 69 super.paint(g); 70 myTank.draw(g); 71 wall1.draw(g); 72 wall2.draw(g); 73 wall3.draw(g); 74 wall4.draw(g); 75 wb.draw(g); 76 b.draw(g); 77 myTank.eatBlood(b); 78 myTank.hitWall(wall1); 79 myTank.hitWall(wall2); 80 myTank.hitWall(wall3); 81 myTank.hitWall(wall4); 82 /*循环子弹集合*/ 83 for (int i = 0; i < missiles.size(); i++){ 84 Missile m = missiles.get(i); //获取当前子弹 85 m.hitTanks(tanks); //自己子弹打死敌方坦克 86 m.hitWall(wall1); //子弹与墙 87 m.hitWall(wall2); 88 m.hitWall(wall3); 89 m.hitWall(wall4); 90 m.hitTank(myTank);//敌人子弹打击自己的坦克 91 m.draw(g); //画子弹 92 } 93 for (int i = 0; i < explode.size(); i++){ 94 explode.get(i).draw(g); //画爆炸 95 } 96 for (int i = 0; i < tanks.size(); i++){ 97 Tank t = tanks.get(i); 98 t.draw(g); //画敌方坦克 99 t.hitTanks(tanks); 100 t.hitWall(wall1); //坦克与墙 101 t.hitWall(wall2); 102 t.hitWall(wall3); 103 t.hitWall(wall4); 104 } 105 //g.setFont(new Font("宋体",Font.BOLD,20)); 106 g.drawString("missiles count:"+missiles.size(), 10, 50);//显示 107 g.drawString("explode count:"+explode.size(), 10, 80);//显示 108 g.drawString("tanks count:"+tanks.size(),10, 110); 109 g.drawString("myTank Life:"+myTank.getLife(), 10, 130); 110 g.drawString("回血:", 750, 540); 111 g.drawString("方向键移动方向;E:释放移动血快", 10, 590); 112 g.drawString("z:发射东风-31;a:发射东风-41;", 10, 570); 113 g.drawString("F2:复活;F3:敌方复活(对多20)", 10, 550); 114 g.drawString("R:位置还原;Q:血量加满", 10, 530); 115 } 116 117 @Override 118 /*repaint-〉update->paint*/ 119 public void update(Graphics g) { 120 // TODO Auto-generated method stub 121 super.update(g); 122 if(OffScrennImage == null) 123 OffScrennImage = this.createImage(GAME_WIDTH, GAME_HEIGTH); 124 Graphics goffscrenn = OffScrennImage.getGraphics(); //设置一个内存画笔颜色为前景图片颜色 125 Color c = goffscrenn.getColor(); //还是先保存前景颜色 126 goffscrenn.setColor(Color.green); //设置内存画笔颜色为绿色 127 goffscrenn.fillRect(0, 0, GAME_WIDTH, GAME_HEIGTH); //画成图片,大小为游戏大小 128 goffscrenn.setColor(c); //还原颜色 129 g.drawImage(OffScrennImage, 0, 0, null); //在界面画出保存的图片 130 paint(goffscrenn); //把内存画笔调用给paint 131 } 132 133 private class PaintThread implements Runnable{ 134 135 @Override 136 public void run() { 137 // TODO Auto-generated method stub 138 while(true){ 139 repaint(); //运行顺序repaint->update->paint 140 try{ 141 Thread.sleep(50); //每隔50毫秒刷新画面一次 142 }catch(Exception e){ 143 e.printStackTrace(); 144 } 145 } 146 } 147 148 } 149 /*键盘响应*/ 150 private class KeyMoniton extends KeyAdapter{ 151 152 /*摁下键盘响应*/ 153 @Override 154 public void keyPressed(KeyEvent e) { 155 // TODO Auto-generated method stub 156 super.keyPressed(e); 157 myTank.KeyPressed(e); 158 } 159 /*抬起键盘响应*/ 160 @Override 161 public void keyReleased(KeyEvent e) { 162 // TODO Auto-generated method stub 163 super.keyReleased(e); 164 myTank.keyReleased(e); 165 } 166 167 } 168 }
Tank.java
1 import java.awt.Color; 2 import java.awt.Graphics; 3 import java.awt.Image; 4 import java.awt.Rectangle; 5 import java.awt.event.KeyEvent; 6 import java.util.List; 7 import java.util.Random; 8 9 import javax.swing.ImageIcon; 10 11 12 public class Tank { 13 /*坦克本身数据*/ 14 int x, y;//坦克坐标 15 private int oldX, oldY; //坦克上一步坐标 16 public static final int Whith = 30; //坦克宽 17 public static final int Higth = 30; //坦克高 18 public static final int XSPEED = 5; //横向移动速度 19 public static final int YSPEED = 5; //纵向移动速度 20 private Color color; //坦克颜色 21 private boolean bL=false, bU=false, bR=false, bD=false; //四个方向控制值 22 enum Direction {L, LU, U, RU, R, RD, D, LD, STOP}; //由四个方向值合成八个方向的移动 23 private Direction dir = Direction.STOP; //出场方向 24 private Direction ptDir = Direction.D; //炮筒初始方向 25 private boolean good; //判断坦克的阵营 26 private boolean live = true; //判断坦克是否存活 27 private static Random r = new Random();//设置一个随机值变量 28 private static int step = r.nextInt(12)+3; //敌方坦克随机移动步骤3-14步 29 private int Life = 100; //血量 30 private BloodBar bb = new BloodBar(); //血块类 31 32 // ImageIcon icon = new ImageIcon("res\\myTank.jpg"); 33 // ImageIcon icon2 = new ImageIcon("res\\enemyTank.jpg"); 34 // Image image = icon.getImage(); 35 // Image image2 = icon2.getImage(); 36 37 38 private TankClient tc; //主类权限 39 40 public Tank(int x, int y, boolean good, Color color) { 41 super(); 42 this.x = x; 43 this.y = y; 44 this.color = color; 45 this.good = good; 46 } 47 public Tank(int x, int y, boolean good,Color color,Direction dir,TankClient tc){ 48 this(x,y,good,color); 49 this.dir = dir; 50 this.tc = tc; 51 } 52 /*获取坦克生命值*/ 53 public int getLife() { 54 return Life; 55 } 56 /*设置坦克生命值*/ 57 public void setLife(int Life) { 58 this.Life = Life; 59 } 60 61 /*获取坦克阵营*/ 62 public boolean isGood() { 63 return good; 64 } 65 /*设置坦克阵营*/ 66 public void setGood(boolean good) { 67 this.good = good; 68 } 69 /*获取坦克存活状态*/ 70 public boolean isLive() { 71 return live; 72 } 73 /*设置坦克存活状态*/ 74 public void setLive(boolean live) { 75 this.live = live; 76 } 77 /*画坦克*/ 78 public void draw(Graphics g){ 79 if(!live){ 80 if(!good){ 81 tc.tanks.remove(this); //敌方坦克死亡时在集合中删除 82 //tc.tanks.add(new Tank(r.nextInt(700),r.nextInt(500),false,Color.blue,Direction.D,this.tc)); 83 } 84 return; 85 } 86 /*先保存之前的画笔颜色,画完之后再还原画笔颜色*/ 87 Color c = g.getColor(); //获取当前画笔颜色 88 g.setColor(color); //设置画笔颜色为红色 89 /*画坦克*/ 90 g.fillOval(x, y, Whith, Higth); 91 /*两种方法绘制敌我坦克,运用之前加入的图片或者颜色区分*/ 92 // if(good) 93 // g.drawImage(image, x, y,Whith,Higth,null); 94 // else 95 // g.drawImage(image2, x, y, Whith, Higth, null); 96 if(good) 97 bb.draw(g); //我方坦克画血条 98 g.setColor(Color.black); 99 /*通过炮筒方向画出炮筒*/ 100 switch(ptDir){ 101 case L: 102 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x, y+Tank.Higth/2); 103 break; 104 case LU: 105 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x, y); 106 break; 107 case U: 108 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x+Tank.Whith/2, y); 109 break; 110 case RU: 111 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x+Tank.Whith, y); 112 break; 113 case R: 114 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x+Tank.Whith, y+Tank.Higth/2); 115 break; 116 case RD: 117 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x+Tank.Whith, y+Tank.Higth); 118 break; 119 case D: 120 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x+Tank.Whith/2, y+Tank.Higth); 121 break; 122 case LD: 123 g.drawLine(x+Tank.Whith/2, y+Tank.Higth/2, x, y+Tank.Higth); 124 break; 125 } 126 g.setColor(c); //还原画笔颜色 127 move();//移动 128 } 129 130 /*键盘监听;摁键*/ 131 public void KeyPressed(KeyEvent e){ 132 int key = e.getKeyCode(); //将键盘监听到的摁键以整数保存 133 /*键盘移动坦克*/ 134 switch(key){ 135 /*移动摁键*/ 136 case KeyEvent.VK_UP: 137 bU=true; 138 break; 139 case KeyEvent.VK_DOWN: 140 bD=true; 141 break; 142 case KeyEvent.VK_RIGHT: 143 bR=true; 144 break; 145 case KeyEvent.VK_LEFT: 146 bL=true; 147 break; 148 } 149 locateDirection(); 150 } 151 152 /*键盘监听;抬起键*/ 153 public void keyReleased(KeyEvent e){ 154 int key = e.getKeyCode(); //将键盘监听到的摁键以整数保存 155 /*键盘移动坦克*/ 156 switch(key){ 157 case KeyEvent.VK_UP: 158 bU=false; 159 break; 160 case KeyEvent.VK_DOWN: 161 bD=false; 162 break; 163 case KeyEvent.VK_RIGHT: 164 bR=false; 165 break; 166 case KeyEvent.VK_LEFT: 167 bL=false; 168 break; 169 case KeyEvent.VK_Z: //单发子弹 170 if(live) 171 fire(); 172 break; 173 case KeyEvent.VK_F2: //我方复活 174 if(!this.live){ 175 this.live=true; 176 this.setLife(100); 177 } 178 break; 179 case KeyEvent.VK_F3: //敌方复活 180 fuhuo(); 181 break; 182 case KeyEvent.VK_A: //无敌导弹 183 superFire(); 184 break; 185 case KeyEvent.VK_Q: //回血 186 if(this.live) 187 this.Life = 100; 188 break; 189 case KeyEvent.VK_E: //释放血块 190 tc.b.fh(); 191 break; 192 /*还原位置键*/ 193 case KeyEvent.VK_R: 194 x = 50; 195 y = 50; 196 break; 197 } 198 locateDirection(); //合成方向 199 } 200 /*合成移动方向*/ 201 void locateDirection(){ 202 if(bL&&!bU&&!bR&&!bD) dir=Direction.L; 203 else if(bL&&bU&&!bR&&!bD) dir=Direction.LU; 204 else if(!bL&&bU&&!bR&&!bD) dir=Direction.U; 205 else if(!bL&&bU&&bR&&!bD) dir=Direction.RU; 206 else if(!bL&&!bU&&bR&&!bD) dir=Direction.R; 207 else if(!bL&&!bU&&bR&&bD) dir=Direction.RD; 208 else if(!bL&&!bU&&!bR&&bD) dir=Direction.D; 209 else if(bL&&!bU&&!bR&&bD) dir=Direction.LD; 210 else if(!bL&&!bU&&!bR&&!bD) dir=Direction.STOP; 211 } 212 213 void move(){ //移动 214 /*记录上一步的位置*/ 215 oldX = x; 216 oldY = y; 217 switch(dir){ 218 case L: 219 x-=XSPEED; 220 break; 221 case LU: 222 x-=XSPEED; 223 y-=YSPEED; 224 break; 225 case U: 226 y-=YSPEED; 227 break; 228 case RU: 229 x+=XSPEED; 230 y-=YSPEED; 231 break; 232 case R: 233 x+=XSPEED; 234 break; 235 case RD: 236 x+=XSPEED; 237 y+=YSPEED; 238 break; 239 case D: 240 y+=YSPEED; 241 break; 242 case LD: 243 x-=XSPEED; 244 y+=YSPEED; 245 break; 246 case STOP: 247 break; 248 } 249 /*判断坦克移动越界情况(游戏边界)*/ 250 if(x < 5) x = 5; 251 if(y < 25) y = 25; 252 if(x+Whith > tc.GAME_WIDTH-5) x = tc.GAME_WIDTH-Whith-5; 253 if(y+Higth > tc.GAME_HEIGTH-5) y = tc.GAME_HEIGTH-Higth-5; 254 255 if(dir != Direction.STOP) //如果坦克不静止就改变炮筒方向 256 ptDir = dir; 257 258 /*敌方坦克自动移动*/ 259 if(!good){ 260 Direction[] dirs = Direction.values(); //将方向变量设为数组 261 if(step == 0){ 262 step = r.nextInt(12)+3; //随机移动步骤 263 int randomNumber = r.nextInt(dirs.length); //随机移动方向 264 dir = dirs[randomNumber]; 265 } 266 step--; 267 if(r.nextInt(40)>30) this.fire(); //随机是否发射炮弹 268 } 269 } 270 /*敌方坦克复活*/ 271 public void fuhuo(){ 272 if(tc.tanks.size() < 20) 273 while(true){ 274 int x = r.nextInt(700); 275 int y = r.nextInt(500); 276 Tank t = new Tank(x,y,false,Color.blue,Direction.D,tc); 277 /*如果坦克与墙重合则重新随机位置直到不重合为止才将新坦克加入集合*/ 278 if(t.getRect().intersects(tc.wall1.getRect())||t.getRect().intersects(tc.wall2.getRect()) 279 ||t.getRect().intersects(tc.wall3.getRect()) 280 ||t.getRect().intersects(tc.wall4.getRect())){ 281 continue; 282 } 283 else{ 284 tc.tanks.add(t); 285 break; 286 } 287 } 288 } 289 /*子弹发射*/ 290 public void fire(){ 291 int x = this.x + Whith/2 - Missile.Whith/2; //控制子弹方向为坦克中间 292 int y = this.y + Higth/2 - Missile.Higth/2; 293 tc.missiles.add(new Missile(ptDir,color,x,y,good,tc)); //创建新的子弹类加入到子弹集合中 294 } 295 /*碰撞;获取坦克的范围*/ 296 public Rectangle getRect(){ 297 return new Rectangle(x,y,Whith,Higth); 298 } 299 /*回执上一步位置*/ 300 private void stay(){ 301 x = oldX; 302 y = oldY; 303 } 304 /*如果撞墙,调用stay方法,返回上一步位置*/ 305 public boolean hitWall(Wall w){ 306 if(this.live&&this.getRect().intersects(w.getRect())){ 307 this.stay(); 308 return true; 309 } 310 return false; 311 } 312 /*坦克互相撞击事件*/ 313 public boolean hitTanks(List<Tank> tanks){ 314 for(int i=0;i<tanks.size();i++){ 315 Tank t=tanks.get(i); 316 if(this!=t){//自己与自己不可相撞 317 /*如果相撞返回上一步位置*/ 318 if(this.live&&t.isLive()&&this.getRect().intersects(t.getRect())){ 319 this.stay(); 320 t.stay(); 321 return true; 322 } 323 } 324 } 325 return false; 326 } 327 /*带开火方向的发射函数*/ 328 public Missile fire(Direction dir){ 329 if(!live) return null; 330 int x=this.x+Whith/2-Missile.Whith/2; 331 int y=this.y+Higth/2-Missile.Higth/2; 332 Missile m=new Missile(dir,color,x, y,good, this.tc); 333 tc.missiles.add(m); 334 return m; 335 } 336 /*超级射击导弹*/ 337 private void superFire(){ 338 Direction[] dirs=Direction.values(); 339 for(int i=0;i<8;i++){ 340 fire(dirs[i]);//循环调用八个方向 341 } 342 } 343 /*新增血块类*/ 344 private class BloodBar{ 345 /*画血条*/ 346 public void draw(Graphics g){ 347 Color c=g.getColor(); 348 g.setColor(Color.red); 349 g.drawRect(x, y-10, Whith, 10); 350 int w=Whith*Life/100; 351 g.fillRect(x, y-10, w, 10); 352 g.setColor(c); 353 } 354 } 355 /*吃血方法*/ 356 public boolean eatBlood(Blood b){ 357 if(this.live&&b.isLive()&&this.isGood()&&this.getRect().intersects(b.getRect())){ 358 this.setLife(100); 359 b.setLive(false); 360 return true; 361 } 362 if(this.getRect().intersects(tc.wb.getRect())) 363 this.Life = 100; 364 return false; 365 } 366 }
Missile.java
1 import java.awt.Color; 2 import java.awt.Graphics; 3 import java.awt.Rectangle; 4 import java.util.List; 5 6 public class Missile { 7 /*子弹本身数据*/ 8 Tank.Direction dir; //子弹方向 9 Color c; //子弹颜色 10 int x,y; //子弹位置 11 public static final int XSPEED = 15; //横向移动速度 12 public static final int YSPEED = 15; //纵向移动速度 13 public static final int Whith = 10; //子弹宽 14 public static final int Higth = 10; //子弹高 15 private boolean live = true; //判断子弹的存活 16 private boolean good; //判断子弹和阵营 17 18 private TankClient tc;//主类权限 19 20 21 public Missile(Tank.Direction dir,Color c, int x, int y) { 22 super(); 23 this.dir = dir; 24 this.x = x; 25 this.y = y; 26 this.c = c; 27 } 28 public Missile(Tank.Direction dir,Color c, int x, int y,boolean good,TankClient tc){ 29 this(dir,c,x,y); 30 this.good = good; 31 this.tc = tc; 32 } 33 34 /*获取子弹的存活*/ 35 public boolean isLive() { 36 return live; 37 } 38 /*设置子弹的存活*/ 39 public void setLive(boolean live) { 40 this.live = live; 41 } 42 public void draw(Graphics g){ 43 /*如果子弹死亡状态将这个子弹在子弹集合中删除*/ 44 if(!live){ 45 tc.missiles.remove(this); //集合中删除 46 return; 47 } 48 /*先保存之前的画笔颜色,画完之后再还原画笔颜色*/ 49 Color d = g.getColor(); //获取当前画笔颜色 50 g.setColor(c); //设置画笔颜色为红色 51 /*画子弹*/ 52 g.fillOval(x, y, Whith, Higth); 53 54 g.setColor(d); //还原画笔颜色 55 move(); //移动 56 } 57 58 public void move(){ 59 /*判断移动方向移动坦克位置*/ 60 switch(dir){ 61 case L: 62 x-=XSPEED; 63 break; 64 case LU: 65 x-=XSPEED; 66 y-=YSPEED; 67 break; 68 case U: 69 y-=YSPEED; 70 break; 71 case RU: 72 x+=XSPEED; 73 y-=YSPEED; 74 break; 75 case R: 76 x+=XSPEED; 77 break; 78 case RD: 79 x+=XSPEED; 80 y+=YSPEED; 81 break; 82 case D: 83 y+=YSPEED; 84 break; 85 case LD: 86 x-=XSPEED; 87 y+=YSPEED; 88 break; 89 case STOP: 90 break; 91 } 92 /*判断子弹的越界情况;出界则子弹死亡,在子弹集合中删去*/ 93 if(x<0||y<0||x>TankClient.GAME_WIDTH||y>TankClient.GAME_HEIGTH) 94 live = false; 95 } 96 /*碰撞;获取子弹的范围*/ 97 public Rectangle getRect(){ 98 return new Rectangle(x,y,Whith,Higth); 99 } 100 /*子弹与坦克碰撞过程*/ 101 public boolean hitTank(Tank t){ 102 /*如果子弹与坦克在同一范围则子弹和坦克同时死亡;且子弹只能杀死对方坦克*/ 103 if(this.live&&this.getRect().intersects(t.getRect())&&t.isLive()&&this.good!=t.isGood()){ 104 if(t.isGood()){ //好坦克 105 /*我方坦克子弹射中会减少生命值,生命值0的时候会死亡*/ 106 t.setLife(t.getLife()-20); 107 if(t.getLife()<=0) 108 t.setLive(false); 109 }else{ //坏坦克 110 t.setLive(false);//死亡 111 } 112 this.live=false;//子弹死亡 113 tc.explode.add(new Explode(x, y, tc));//新建爆炸加入集合 114 return true; 115 } 116 return false; 117 } 118 /*循环坦克集合分别进行判断子弹碰撞*/ 119 public boolean hitTanks(List<Tank> tanks){ 120 for (int i = 0; i < tanks.size(); i++){ 121 if(hitTank(tanks.get(i))) 122 return true; 123 } 124 return false; 125 } 126 /*子弹与墙的碰撞过程*/ 127 public boolean hitWall(Wall w){ 128 /*如果子弹与墙的范围重合子弹死亡*/ 129 if(this.live&&this.getRect().intersects(w.getRect())){ 130 this.live=false; //子弹死亡 131 return true; 132 } 133 return false; 134 } 135 }
Wall.java
1 import java.awt.Graphics; 2 import java.awt.Rectangle; 3 4 5 public class Wall { 6 /*墙数据*/ 7 int x,y,w,h; //位置和宽高 8 private TankClient tc; //主类权限 9 10 public Wall(int x, int y, int w, int h, TankClient tc) { 11 super(); 12 this.x = x; 13 this.y = y; 14 this.w = w; 15 this.h = h; 16 this.tc = tc; 17 } 18 /*获取墙的范围*/ 19 public Rectangle getRect(){ 20 return new Rectangle(x,y,w,h); 21 } 22 /*画墙*/ 23 public void draw(Graphics g){ 24 g.fillRect(x, y, w, h); 25 } 26 }
Explode.java
import java.awt.Color; import java.awt.Graphics; public class Explode { /*坦克爆炸属性*/ int x,y; //爆炸位置 private boolean live = true; //爆炸是否存在 int step = 0; //爆炸时间控制 int [] diameter = new int[] {4, 7, 12, 18, 26, 32, 49, 56, 65, 77, 80, 50, 40, 30, 14, 6};//爆炸范围 private TankClient tc; //主类权限 public Explode(int x, int y, TankClient tc) { super(); this.x = x; this.y = y; this.tc = tc; } /*画爆炸*/ public void draw(Graphics g){ if(!live) return; //如果爆炸死亡状态不画结束 /*如果爆炸时间结束爆炸不存在并在集合中删除*/ if(step == diameter.length){ live = false; //爆炸死亡 step = 0; //步骤时间归0 tc.explode.remove(this); //集合中删除 return; } /*画爆炸*/ Color c = g.getColor(); g.setColor(Color.orange); g.fillOval(x, y, diameter[step], diameter[step]); g.setColor(c); step++; } }
Blood.java
1 import java.awt.Color; 2 import java.awt.Graphics; 3 import java.awt.Rectangle; 4 import java.util.Random; 5 6 7 public class Blood { 8 /*血块数据*/ 9 int x, y, w, h;//血块位置和大小 10 private TankClient tc; //主类权限 11 private boolean live=true;//血块的存活 12 private static Random r = new Random();//设置一个随机值变量 13 /*获取血块的存活状态*/ 14 public boolean isLive() { 15 return live; 16 } 17 /*设置血块的存活状态*/ 18 public void setLive(boolean live) { 19 this.live = live; 20 } 21 /*血块位置初值随机一个数值*/ 22 public Blood(){ 23 x=r.nextInt(600)+100; 24 y=r.nextInt(400)+100; 25 w=h=15; 26 } 27 /*画血块*/ 28 public void draw(Graphics g){ 29 if(!live) return; 30 Color c=g.getColor(); 31 g.setColor(Color.magenta); 32 g.fillRect(x, y, w, h); 33 g.setColor(c); 34 } 35 /*释放血块*/ 36 public void fh(){ 37 if(!live){ 38 x = r.nextInt(600)+100; 39 y = r.nextInt(400)+100; 40 live = true; 41 } 42 } 43 /*获取血块范围*/ 44 public Rectangle getRect(){ 45 return new Rectangle(x, y, w, h); 46 } 47 }