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

想到什么再更吧。。

posted @ 2016-02-05 21:15  CodeNoob  阅读(7845)  评论(1编辑  收藏  举报