java學習之坦克大戰游戲


  總結:由於這幾天快過年比較忙然后沒怎么寫,寫代碼途中一些經驗總結現在給忘記了。這次的小項目感覺比上次寫的思路清楚了點。沒有之前第一次寫那么邏輯混亂,結構也搞的比之前的要好,添加功能比較容易。學習了之前的經驗,操作對象的方法由對象本身提供。不過這次小項目還有不足和不完善之處,有些可以做的功能沒有實現,比如游戲存檔,這里應該可以用下對象的序列化,還有游戲難度的設置也可以寫個文件弄出來。要過年了,到處走親戚沒什么心思寫了,這里只能留個尾巴了。

  前言:之前的及時通信項目完成后感覺線程方面和對java的運用還不是很熟悉,在另外一個學習視頻中看到一個做坦克游戲的項目視頻,便想自己試着做做看,先看視頻把游戲規則什么的都搞清楚。然后開始一步一步實現。

主要功能步驟如下

* 1、畫出坦克
* 2、我的坦克可以上下移動
* 3、可以發射子彈,子彈連發(或者最多5發)
* 4、當我的坦克擊中敵人坦克時,敵人坦克消失(或者爆炸效果)
* 5、我被擊中也顯示爆炸效果。
* 6、游戲開始和游戲介紹選項

這次游戲界面沒有進行設計,直接在一個frame上放個panel。

游戲設計仿mvc 這里不做詳細介紹了直接上代碼

model包

package com.gh.model;
/**
 * 爆炸類
 * 考慮到同時爆炸定義個類
 * @author ganhang
 *
 */
public class Bomb {
    private int x;
    private int y;//坐標
    public boolean islive=true;
    private int time=9;//炸彈生命
    public Bomb() {
        super();
    }
    public Bomb(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    public int getTime() {
        return time;
    }
    //生命遞減
    public void livedown(){
        if(time>0){
            time--;
        }else{
            islive=false;
        }
    }
}
Bomb
 1 package com.gh.model;
 2 /**
 3  * 子彈類,
 4  * 因為多個子彈同時運動所以需要個內部類做線程
 5  * @author ganhang
 6  *
 7  */
 8 public class Bullet {
 9     private int x;
10     private int y;
11     private int speed;
12     private int drect;
13     public boolean islive=true;
14     public Bullet(int x, int y, int speed, int drect) {
15         super();
16         this.x = x;
17         this.y = y;
18         this.speed = speed;
19         this.drect = drect;
20         new Thread(new BulletThread()).start();
21     }
22     public Bullet() {
23         super();
24     }
25 
26     public int getX() {
27         return x;
28     }
29 
30     public void setX(int x) {
31         this.x = x;
32     }
33 
34     public int getY() {
35         return y;
36     }
37 
38     public void setY(int y) {
39         this.y = y;
40     }
41 
42     class BulletThread implements Runnable {
43         @Override
44         public void run() {
45             while (true) {
46                 try {
47                     Thread.sleep(50);
48                 } catch (Exception e) {
49                     e.printStackTrace();
50                 }
51                 switch (drect) {//判斷方向坐標移動
52                 case 0:
53                     y-=speed;
54                     break;
55                 case 1:
56                     x+=speed;
57                     break;
58                 case 2:
59                     y+=speed;
60                     break;
61                 case 3:
62                     x-=speed;
63                     break;
64                 }
65                 if (x < 0 || y < 0 || x > 500 || y > 500||!islive) {
66                     islive=false;
67                     break;
68                 }
69             }
70         }
71     }
72 }
Bullet
package com.gh.model;

/**
 * 地圖坐標標記
 * 防止敵方坦克重疊
 * @author ganhang
 *
 */
public class Map {
    public int[][] location=new int[500][500];
    public Map() {
        for (int i = 0; i < 500; i++) {
            for (int j = 0; j <500; j++) {
                location[i][j]=0;
            }
        }
    }
}
Map

坦克類,剛才上傳發現點問題暫時沒改

  1 package com.gh.model;
  2 
  3 import java.util.Vector;
  4 /**
  5  * 坦克類
  6  * 每個坦克就是一個線程,
  7  * 這里自己坦克並沒有啟動線程
  8  * @author ganhang
  9  *
 10  */
 11 public class Tank implements Runnable {
 12     private int x = 0;
 13     private int y = 0;// 坐標
 14     private int drect = 0;// 方向 0向上,1向右,2向下,3向左;
 15     private int type = 0;// 坦克類型 0表示自己
 16     private int speed = 3;// 速度
 17     public Vector<Bullet> mybs = new Vector<Bullet>();// 子彈集
 18     private Bullet myBullet;// 子彈
 19     public boolean islive = true;
 20     private Map map;
 21     public boolean start = true;
 22     public Map getMap() {
 23         return map;
 24     }
 25 
 26     public void setMap(Map map) {
 27         this.map = map;
 28     }
 29 
 30     public Tank(int x, int y, int drect, int type) {
 31         super();
 32         this.x = x;
 33         this.y = y;
 34         this.drect = drect;
 35         this.type = type;
 36     }
 37 
 38     public Tank() {
 39         super();
 40     }
 41 
 42     public Bullet getMyBullet() {
 43         return myBullet;
 44     }
 45 
 46     public int getSpeed() {
 47         return speed;
 48     }
 49 
 50     public void setSpeed(int speed) {
 51         this.speed = speed;
 52     }
 53 
 54     public int getX() {
 55         return x;
 56     }
 57 
 58     public int getDrect() {
 59         return drect;
 60     }
 61 
 62     public void setDrect(int drect) {
 63         this.drect = drect;
 64     }
 65 
 66     public int getType() {
 67         return type;
 68     }
 69 
 70     public void setType(int type) {
 71         this.type = type;
 72     }
 73 
 74     public void setX(int x) {
 75         this.x = x;
 76     }
 77 
 78     public int getY() {
 79         return y;
 80     }
 81 
 82     public void setY(int y) {
 83         this.y = y;
 84     }
 85 
 86     public void moveUp() {
 87         if (y - speed < 0)
 88             y = 0;
 89         else {
 90             y -= speed;
 91              map.location[x][y]=1;//標記此坦克坐標在地圖上防止其他坦克過來占用導致重疊
 92 //             這里只標記了坦克坐標那一個點,會有bug,部分坦克還是有重疊現象,
 93 //             這里可以遍歷整個坦克坐標(x到x+20,y到y+30)設置標記。
 94 //             for(int i=x;i<x+20;i++){
 95 //                 for (int j = y; j < y+30; j++) {
 96 //                     map.location[x][y]=1;
 97 //                }
 98 //             }
 99         }
100     }
101 
102     public void moveDown() {
103         if (y + speed > 470)
104             y = 470;
105         else {
106             y += speed;
107              map.location[x][y]=1;
108         }
109     }
110 
111     public void moveRight() {
112         if (x + speed > 470)
113             x = 470;
114         else {
115             x += speed;
116              map.location[x][y]=1;
117         }
118     }
119 
120     public void moveLeft() {
121         if (x - speed < 0)
122             x = 0;
123         else {
124             x -= speed;
125              map.location[x][y]=1;
126         }
127     }
128 
129     public void shot() {
130         switch (drect) {
131         case 0:
132             myBullet = new Bullet(x + 10, y, 5, 0);
133             mybs.add(myBullet);
134             break;
135         case 1:
136             myBullet = new Bullet(x + 30, y + 10, 5, 1);
137             mybs.add(myBullet);
138             break;
139         case 2:
140             myBullet = new Bullet(x + 10, y + 30, 5, 2);
141             mybs.add(myBullet);
142             break;
143         case 3:
144             myBullet = new Bullet(x, y + 10, 5, 3);
145             mybs.add(myBullet);
146             break;
147         }
148     }
149 
150     @Override
151     public void run() {
152         while (islive) {
153             if (start) {
154                 int step;
155                 int s;
156                 try {
157                     switch (drect) {
158                     case 0:
159                         step = (int) (Math.random() * 30);
160                         for (int i = 0; i < step; i++) {
161                             moveUp();
162                             if (y <= 0)
163                                 break;// 撞牆跳出循環
164                             if (y >= 30)// 仿數組越界
165                                 if (map.location[x][y - 30] == 1 || map.location[x][y - 20] == 1) {
166                                     map.location[x][y - 30] = 0;//這里沒分開判斷
167                                     map.location[x][y - 20] = 0;
168                                     break;
169                                 }
170                             Thread.sleep(80);
171                         }
172                         break;
173                     case 1:
174                         step = (int) (Math.random() * 30);
175                         for (int i = 0; i < step; i++) {
176                             moveRight();
177                             if (x >= 500)
178                                 break;
179                             if (x < 470)
180                                 if (map.location[x + 20][y] == 1 || map.location[x + 30][y] == 1) {
181                                     map.location[x + 20][y] = 0;
182                                     map.location[x + 30][y] = 0;
183                                     break;
184                                 }
185                             Thread.sleep(80);
186                         }
187                         break;
188                     case 2:
189                         step = (int) (Math.random() * 30);
190                         for (int i = 0; i < step; i++) {
191                             moveDown();
192                             if (y >= 500)
193                                 break;
194                             if (y < 470)
195                                 if (map.location[x][y + 30] == 1 || map.location[x][y + 20] == 1) {
196                                     map.location[x][y + 30] = 0;
197                                     map.location[x][y + 20] = 0;
198                                     break;
199                                 }
200                             Thread.sleep(80);
201                         }
202                         break;
203                     case 3:
204                         step = (int) (Math.random() * 30);
205                         for (int i = 0; i < step; i++) {
206                             moveLeft();
207                             if (x <= 0)
208                                 break;
209                             if (x >= 30)
210                                 if (map.location[x - 20][y] == 1 || map.location[x - 30][y] == 1) {
211                                     map.location[x - 20][y] = 0;
212                                     map.location[x - 30][y] = 0;
213                                     break;
214                                 }
215                             Thread.sleep(80);
216                         }
217                         break;
218                     }
219                 } catch (InterruptedException e) {
220                     e.printStackTrace();
221                 }
222                 drect = (int) (Math.random() * 4);// 隨機方向
223                 s = (int) (Math.random() * 10);
224                 if (s > 8) {
225                     shot();
226                 }
227             }
228         }
229     }
230 }
Tank

view包

  1 package com.gh.view;
  2 
  3 import java.awt.Color;
  4 import java.awt.Graphics;
  5 import java.awt.Image;
  6 import java.awt.Toolkit;
  7 import java.util.Vector;
  8 
  9 import javax.swing.JOptionPane;
 10 import javax.swing.JPanel;
 11 
 12 import com.gh.model.Bomb;
 13 import com.gh.model.Bullet;
 14 import com.gh.model.Map;
 15 import com.gh.model.Tank;
 16 
 17 /**
 18  * 游戲顯示面板
 19  * 
 20  * @author ganhang
 21  *
 22  */
 23 
 24 public class Mypanel extends JPanel implements Runnable {
 25     public Tank mytank = null;// 我的坦克
 26     Tank ek = null;
 27     Image img;
 28     Vector<Tank> eks = new Vector<Tank>();//地方坦克集
 29     Vector<Bomb> bs = new Vector<Bomb>();//爆炸集合
 30     Map map = new Map();
 31 
 32     public Mypanel() {
 33         mytank = new Tank(200, 200, 0, 0);
 34         mytank.setMap(map);
 35         // 創建敵人坦克
 36         for (int i = 0; i < 17; i++) {
 37             ek = new Tank(i * 30, 10, 2, 1);
 38             eks.add(ek);
 39             ek.setMap(map);
 40             new Thread(ek).start();
 41         }
 42         img = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/1.png"));
 43     }
 44 
 45     @Override
 46     public void paint(Graphics g) {
 47         super.paint(g);
 48         // 畫背景
 49         g.fillRect(0, 0, 500, 500);
 50         // 畫自己的坦克
 51         if (mytank.islive)
 52             drawTank(mytank.getX(), mytank.getY(), g, mytank.getDrect(), mytank.getType());
 53         // 畫自己的子彈
 54         for (int i = 0; i < mytank.mybs.size(); i++) {// 循環時刪除集合時,不要用foreach,用for
 55             Bullet b = new Bullet();
 56             b = mytank.mybs.get(i);
 57             if (b.islive) {
 58                 g.setColor(Color.white);
 59                 g.fill3DRect(b.getX(), b.getY(), 2, 2, false);
 60             } else
 61                 mytank.mybs.remove(b);
 62         }
 63         // 畫敵人坦克
 64         for (int i = 0; i < eks.size(); i++) {
 65             Tank ek = new Tank();
 66             ek = eks.get(i);
 67             if (ek.islive)
 68                 drawEnemyTank(ek.getX(), ek.getY(), ek.getDrect(), g);
 69             // 畫敵人子彈
 70             for (int j = 0; j < ek.mybs.size(); j++) {
 71                 Bullet eb = new Bullet();
 72                 eb = ek.mybs.get(j);
 73                 if (eb.islive) {
 74                     g.setColor(Color.green);
 75                     g.fill3DRect(eb.getX(), eb.getY(), 2, 2, false);
 76                 } else
 77                     ek.mybs.remove(eb);
 78             }
 79         }
 80         // 畫爆炸,這里有個bug第一次爆炸沒有爆炸效果圖出來,檢查原因是只一閃而過
 81         // 添加休眠好了點,不過影響后面爆炸效果,不明白為什么第一次畫得快些
 82         for (int i = 0; i < bs.size(); i++) {
 83             // System.out.println(bs.size());
 84             Bomb bb = bs.get(i);
 85             if (bb.islive) {
 86                 if (bb.getTime() > 6) {
 87                     try {
 88                         Thread.sleep(50);
 89                     } catch (Exception e) {
 90                         e.printStackTrace();
 91                     }
 92                     g.drawImage(img, bb.getX(), bb.getY(), 30, 30, this);
 93                 } else if (bb.getTime() > 3) {
 94                     g.drawImage(img, bb.getX(), bb.getY(), 15, 15, this);
 95                 } else if (bb.getTime() > 0) {
 96                     g.drawImage(img, bb.getX(), bb.getY(), 1, 1, this);
 97                 }
 98             }
 99             bb.livedown();
100             if (bb.getTime() == 0)
101                 bs.remove(bb);
102         }
103     }
104 
105     public boolean isHitEnemy(Bullet b, Tank ek) {
106         if (ek.getDrect() == 0 || ek.getDrect() == 2) {
107             // 坦克豎着時寬20,高30
108             if (b.getX() >= ek.getX() && b.getX() <= ek.getX() + 20 && b.getY() >= ek.getY()
109                     && b.getY() <= ek.getY() + 30) {
110                 b.islive = false;
111                 ek.islive = false;
112                 Bomb bb = new Bomb(ek.getX(), ek.getY());
113                 bs.add(bb);
114                 return true;
115             }
116             return false;
117         } else {// 橫着寬30,高20;
118             if (b.getX() >= ek.getX() && b.getX() <= ek.getX() + 30 && b.getY() >= ek.getY()
119                     && b.getY() <= ek.getY() + 20) {
120                 ek.islive = false;
121                 b.islive = false;
122                 Bomb bb = new Bomb(ek.getX(), ek.getY());
123                 bs.add(bb);
124                 return true;
125             }
126             return false;
127         }
128     }
129 
130     public void drawEnemyTank(int x, int y, int drect, Graphics g) {
131         drawTank(x, y, g, drect, 1);
132     }
133 
134     public void drawTank(int x, int y, Graphics g, int drect, int type) {
135         switch (type) {
136         case 0:
137             g.setColor(Color.cyan);
138             break;
139         case 1:
140             g.setColor(Color.GREEN);
141         default:
142             break;
143         }
144         switch (drect) {
145         case 0:
146             // 坦克向上時寬20,高30
147             g.fill3DRect(x, y, 5, 30, false);
148             g.fill3DRect(x + 15, y, 5, 30, false);
149             g.fill3DRect(x + 5, y + 9, 10, 15, false);
150             g.drawLine(x + 10, y + 14, x + 10, y);
151             break;
152         case 1:
153             // 坦克向右時寬30,高20
154             g.fill3DRect(x, y, 30, 5, false);
155             g.fill3DRect(x, y + 15, 30, 5, false);
156             g.fill3DRect(x + 7, y + 5, 15, 10, false);
157             g.drawLine(x + 13, y + 10, x + 30, y + 10);
158             break;
159         case 2:
160             g.fill3DRect(x, y, 5, 30, false);
161             g.fill3DRect(x + 15, y, 5, 30, false);
162             g.fill3DRect(x + 5, y + 7, 10, 15, false);
163             g.drawLine(x + 10, y + 12, x + 10, y + 30);
164             break;
165         case 3:
166             g.fill3DRect(x, y, 30, 5, false);
167             g.fill3DRect(x, y + 15, 30, 5, false);
168             g.fill3DRect(x + 8, y + 5, 15, 10, false);
169             g.drawLine(x, y + 10, x + 13, y + 10);
170             break;
171         }
172     }
173 
174     @Override
175     public void run() {
176         while (true) {
177             try {
178                 Thread.sleep(50);// 畫板刷新頻率
179             } catch (InterruptedException e) {
180                 e.printStackTrace();
181             }
182             // 判斷自己坦克的子彈是否擊中敵人坦克
183             for (int i = 0; i < mytank.mybs.size(); i++) {
184                 Bullet mb = new Bullet();
185                 mb = mytank.mybs.get(i);
186                 if (mb.islive) {
187                     for (int j = 0; j < eks.size(); j++) {
188                         Tank ek = new Tank();
189                         ek = eks.get(j);
190                         if (ek.islive) {
191                             isHitEnemy(mb, ek);
192                         }
193                     }
194                 }
195             }
196             // 判斷敵方坦克 的子彈是否擊中我方坦克
197             for (int i = 0; i < eks.size(); i++) {
198                 Tank et = new Tank();
199                 et = eks.get(i);
200                 for (int j = 0; j < et.mybs.size(); j++) {// 這里寫錯ek查到死。。。
201                     Bullet etb = new Bullet();
202                     etb = et.mybs.get(j);
203                     if (etb.islive) {
204                         isHitEnemy(etb, mytank);
205                     }
206                 }
207             }
208             this.repaint();// 刷新
209             if (!mytank.islive) {
210                 JOptionPane.showMessageDialog(this, "你被GG");
211                 mytank.islive = true;
212             }
213         }
214     }
215 }
Mypanel

開始游戲類

 1 package com.gh.view;
 2 
 3 import java.awt.EventQueue;
 4 /**
 5  * 1、畫出坦克
 6  * 2、我的坦克可以上下移動
 7  * 3、可以發射子彈,子彈連發(或者最多5發)
 8  * 4、當我的坦克擊中敵人坦克時,敵人坦克消失(或者爆炸效果)
 9  * 5、我被擊中也顯示爆炸效果。
10  * 6、游戲開始選項
11  * @author ganhang
12  *
13  */
14 public class TankGame {
15     private JFrame frame;
16     /**
17      * Launch the application.
18      */
19     public static void main(String[] args) {
20         EventQueue.invokeLater(new Runnable() {
21             public void run() {
22                 try {
23                     TankGame window = new TankGame();
24                     window.frame.setVisible(true);
25                 } catch (Exception e) {
26                     e.printStackTrace();
27                 }
28             }
29         });
30     }
31 
32     /**
33      * Create the application.
34      */
35     public TankGame() {
36         initialize();
37     }
38 
39     /**
40      * Initialize the contents of the frame.
41      */
42     private void initialize() {
43         frame = new JFrame();
44         frame.setTitle("\u5766\u514B\u5927\u6218");
45         frame.setBounds(450, 70, 600, 600);
46         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
47 
48         JMenuBar menuBar = new JMenuBar();
49         frame.setJMenuBar(menuBar);
50         
51         JMenu mnNewMenu = new JMenu("\u9009\u9879");
52         mnNewMenu.setFont(new Font("微軟雅黑", Font.PLAIN, 13));
53         menuBar.add(mnNewMenu);
54         
55         JMenuItem mntmNewMenuItem = new JMenuItem("開始游戲");
56         mntmNewMenuItem.addActionListener(new ActionListener() {
57             public void actionPerformed(ActionEvent e) {
58                 Mypanel mp = new Mypanel();
59                 Thread t=new Thread(mp);
60                 t.start();
61                 frame.getContentPane().add(mp, BorderLayout.CENTER);
62                 frame.addKeyListener(new KeyListen(mp));
63                 frame.setVisible(true);
64             }
65         });
66         
67         mntmNewMenuItem.setFont(new Font("微軟雅黑", Font.PLAIN, 12));
68         mnNewMenu.add(mntmNewMenuItem);
69         
70         JMenu mnNewMenu_1 = new JMenu("\u6E38\u620F\u8BF4\u660E");
71         mnNewMenu_1.setFont(new Font("微軟雅黑", Font.PLAIN, 13));
72         menuBar.add(mnNewMenu_1);
73         
74         JMenuItem mntmNewMenuItem_1 = new JMenuItem("\u5173\u4E8E\u6E38\u620F");
75         mntmNewMenuItem_1.addActionListener(new ActionListener() {
76             public void actionPerformed(ActionEvent e) {
77                 JOptionPane.showMessageDialog(frame, "上:W, 下:A ,左:S, 右:D ,射擊:空格\n Made by Ganhang");;
78             }
79         });
80         mntmNewMenuItem_1.setFont(new Font("微軟雅黑", Font.PLAIN, 12));
81         mnNewMenu_1.add(mntmNewMenuItem_1);
82 
83     }
84 
85 }
TankGame

control包 這里放的事件監聽主要業務邏輯在畫板類和模型類里寫了

 1 package com.gh.control;
 2 
 3 import java.awt.event.KeyEvent;
 4 import java.awt.event.KeyListener;
 5 
 6 import com.gh.view.Mypanel;
 7 
 8 /**
 9  * 事件監聽
10  * 這里有個控制最大發射子彈數
11  * @author ganhang
12  */
13 public class KeyListen implements KeyListener{
14     private Mypanel mp=null;
15     
16     public KeyListen(Mypanel mp) {
17         super();
18         this.mp = mp;
19     }
20     @Override
21     public void keyTyped(KeyEvent e) {
22         
23     }
24     
25     @Override
26     public void keyPressed(KeyEvent e) {
27         //方向鍵監聽
28         if(e.getKeyCode()==KeyEvent.VK_W){
29             mp.mytank.setDrect(0);
30             mp.mytank.moveUp();
31         }else if(e.getKeyCode()==KeyEvent.VK_S){
32             mp.mytank.setDrect(2);
33             mp.mytank.moveDown();
34         }else if(e.getKeyCode()==KeyEvent.VK_D){
35             mp.mytank.setDrect(1);
36             mp.mytank.moveRight();
37         }else if(e.getKeyCode()==KeyEvent.VK_A){
38             mp.mytank.setDrect(3);
39             mp.mytank.moveLeft();
40         }
41         //發射子彈監聽
42         if(e.getKeyCode()==KeyEvent.VK_SPACE){
43             if(mp.mytank.mybs.size()<5)
44             mp.mytank.shot();
45         }
46         mp.repaint();
47     }
48     @Override
49     public void keyReleased(KeyEvent e) {
50         // TODO Auto-generated method stub
51         
52     }
53 }
KeyListen

 github:https://github.com/ganhang/My_TankGame

想到什么再更吧。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM