利用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 }