坦克大战(版本1.7-版本2.4)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了坦克大战(版本1.7-版本2.4)相关的知识,希望对你有一定的参考价值。

版本1.7

功能:加入爆炸
步骤:
        1)添加爆炸类:Explode
           用不同直径的圆模拟爆炸: int[] diameter = {4, 7, 12, 18, 26, 32, 49, 30, 14, 6};
           加入live: private boolean live = true;
           加入位置属性: int x, y;
           加入draw方法
        2)爆炸应该存在于集合类中:
           TankClient加入集合explodes: List<Explode> explodes=new ArrayList<Explode>();
           将集合中的爆炸逐一画出(如果死去就去除):在Missile类的draw方法中,当爆炸live==false的时候,tc.missiles.remove(this);
        3)击毙一辆坦克后应产生爆炸:
           在Missile类的hitTank中,产生爆炸,Explode e=new Explode(x, y, tc); tc.explodes.add(e);

具体代码实现:

Tank:

技术分享
  1 import java.awt.*;
  2 import java.awt.event.*;
  3 import java.util.Random;
  4 
  5 public class Tank {
  6     // 方便后期更改
  7     public static final int XSPEED = 5;
  8     public static final int YSPEED = 5;
  9     // 将坦克的高度和宽度设置为常量
 10     public static final int WIDTH = 30;
 11     public static final int HEIGHT = 30;
 12     TankClient tc;
 13     // 区别是我方坦克还是地方坦克,方便据此进行不同的设置
 14     private boolean good;
 15     
 16     //判断坦克生死的变量
 17     private boolean live=true;
 18 
 19     
 20     public boolean isLive() {
 21         return live;
 22     }
 23 
 24     public void setLive(boolean live) {
 25         this.live = live;
 26     }
 27 
 28     private int x;
 29     private int y;
 30     // 添加记录按键状态的布尔量
 31     private boolean bL = false;
 32     private boolean bR = false;
 33     private boolean bU = false;
 34     private boolean bD = false;
 35 
 36     // 添加代表方向的量(使用枚举)
 37     enum Direction {
 38         L, R, U, D, LU, LD, RU, RD, STOP
 39     };
 40 
 41     private Direction dir = Direction.STOP;
 42 
 43     // 定义炮筒的方向,我们想办法将炮筒的方法调整成和坦克移动方向一致;
 44     // 我们这里会用一条直线来表示炮筒:模拟炮筒
 45     // 我们要根据炮筒的方向画直线表示炮筒
 46     Direction ptDir = Direction.D;
 47 
 48     //更改构造函数
 49     public Tank(int x, int y,boolean good) {
 50         this.x = x;
 51         this.y = y;
 52         this.good=good;
 53     }
 54 
 55     //这个位置的构造函数也相应进行了更改
 56     public Tank(int x, int y,boolean good,TankClient tc) {
 57         // 调用那个有两个参数的构造方法
 58         this(x, y,good);
 59         // 在这个位置初始化tc
 60         this.tc = tc;
 61     }
 62 
 63     // Tank对象的draw方法
 64     public void draw(Graphics g) {
 65         if(!live){
 66             return;
 67         }
 68         Color c = g.getColor();
 69         if(good){    
 70         g.setColor(Color.RED);
 71         }
 72         else {
 73             g.setColor(Color.PINK);
 74         }
 75         g.fillOval(x, y, WIDTH, HEIGHT);
 76         g.setColor(c);
 77         // 根据炮筒的方向画直线来表示我们坦克的炮筒
 78         switch (ptDir) {
 79         case L:
 80             // 画直线:四个参数分别代表:坦克中心点的坐标 直线的另一头的的坐标
 81             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y
 82                     + Tank.HEIGHT / 2);
 83             break;
 84         case R:
 85             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
 86                     y + Tank.HEIGHT / 2);
 87 
 88             break;
 89         case U:
 90             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH
 91                     / 2, y);
 92 
 93             break;
 94         case D:
 95             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH
 96                     / 2, y + Tank.HEIGHT);
 97 
 98             break;
 99         case LU:
100             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y);
101             break;
102         case LD:
103             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y
104                     + Tank.HEIGHT);
105 
106             break;
107         case RU:
108             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
109                     y);
110 
111             break;
112         case RD:
113             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
114                     y + Tank.HEIGHT);
115 
116             break;
117         /*
118          * case STOP: break;
119          */
120         }
121         move();
122     }
123 
124     public void move() {
125         switch (dir) {
126         case L:
127             x -= XSPEED;
128             break;
129         case R:
130             x += XSPEED;
131             break;
132         case U:
133             y -= YSPEED;
134             break;
135         case D:
136             y += YSPEED;
137             break;
138         case LU:
139             x -= XSPEED;
140             y -= YSPEED;
141             break;
142         case LD:
143             x -= XSPEED;
144             y += YSPEED;
145             break;
146         case RU:
147             x += XSPEED;
148             y -= YSPEED;
149             break;
150         case RD:
151             x += XSPEED;
152             y += YSPEED;
153             break;
154 
155         case STOP:
156             break;
157         }
158         // 如果坦克不是停着的,则将炮筒调整至和坦克移动的方向相同
159         if (this.dir != Direction.STOP) {
160             this.ptDir = this.dir;
161         }
162         if (x < 0) {
163             x = 0;
164         }
165         // 因为我们的游戏界面有那个missileCount标签,所以在y轴方向不能用y是否<0进行判断
166         // 否则的话我们的坦克可以从上面出去
167         if (y < 50) {
168             y = 50;
169         }
170         if (x + Tank.WIDTH > TankClient.GAME_WIDTH) {
171             x = TankClient.GAME_WIDTH - Tank.WIDTH;
172         }
173         if (y + Tank.HEIGHT > TankClient.GAME_HEIGHT) {
174             y = TankClient.GAME_HEIGHT - Tank.HEIGHT;
175         }
176     }
177 
178     public void locateDirection() {
179         if (bL && !bU && !bR && !bD)
180             dir = Direction.L;
181         else if (bL && bU && !bR && !bD)
182             dir = Direction.LU;
183         else if (!bL && bU && !bR && !bD)
184             dir = Direction.U;
185         else if (!bL && bU && bR && !bD)
186             dir = Direction.RU;
187         else if (!bL && !bU && bR && !bD)
188             dir = Direction.R;
189         else if (!bL && !bU && bR && bD)
190             dir = Direction.RD;
191         else if (!bL && !bU && !bR && bD)
192             dir = Direction.D;
193         else if (bL && !bU && !bR && bD)
194             dir = Direction.LD;
195         else if (!bL && !bU && !bR && !bD)
196             dir = Direction.STOP;
197 
198     }
199 
200     // 坦克自己向哪个方向移动,它自己最清楚;
201     public void KeyPressed(KeyEvent e) {
202         // 获得所按下的键所对应的虚拟码:
203         // Returns the integer keyCode associated with the key in this event
204         int key = e.getKeyCode();
205         // 判断不同的按键,指挥坦克的运动方向
206         switch (key) {
207         case KeyEvent.VK_LEFT:
208             bL = true;
209             break;
210         case KeyEvent.VK_UP:
211             bU = true;
212             break;
213         case KeyEvent.VK_RIGHT:
214             bR = true;
215             break;
216         case KeyEvent.VK_DOWN:
217             bD = true;
218             break;
219         }
220         locateDirection();
221     }
222 
223     public void keyReleased(KeyEvent e) {
224         int key = e.getKeyCode();
225         // 判断不同的按键,指挥坦克的运动方向
226         // 哪个键按下了,就把对应方向的布尔类型置为false
227         switch (key) {
228         // 为了防止一直按着Ctrl键的时候,炮弹太过于密集
229         // 因此我们定义在Ctrl键抬起的时候才发炮弹
230         // 这样炮弹不至于太过密集
231         case KeyEvent.VK_CONTROL:
232             fire();
233             break;
234         case KeyEvent.VK_LEFT:
235             bL = false;
236             break;
237         case KeyEvent.VK_UP:
238             bU = false;
239             break;
240         case KeyEvent.VK_RIGHT:
241             bR = false;
242             break;
243         case KeyEvent.VK_DOWN:
244             bD = false;
245             break;
246         }
247         // 重新定位一下
248         locateDirection();
249     }
250 
251     public Missile fire() {
252         // 计算子弹的位置,使得子弹从坦克的中间发出来
253         int x = this.x + Tank.WIDTH / 2 - Missile.WIDTH / 2;
254         int y = this.y + Tank.HEIGHT / 2 - Missile.HEIGHT / 2;
255         // 这个时候我们就根据炮筒的方向来发炮弹了,之前是根据坦克的方向来发炮弹
256         Missile m = new Missile(x, y, ptDir, tc);
257         // 将新产生的炮弹放置到List容器中
258         tc.missiles.add(m);
259         return m;
260     }
261 
262     //拿到包围坦克的那个方块
263     public Rectangle getRect() {
264         
265         return new Rectangle(x,y,WIDTH,HEIGHT);
266     }
267 }
View Code

Missile:

技术分享
  1 import java.awt.Color;
  2 import java.awt.Graphics;
  3 import java.awt.Rectangle;
  4 
  5 public class Missile {
  6     // 炮弹的移动速度,不要比坦克的移动速度慢,不然你看到的是满屏的坦克追着炮弹跑
  7     public static final int XSPEED = 10;
  8     public static final int YSPEED = 10;
  9     // 将子弹的高度和宽度设置为常量
 10     public static final int WIDTH = 10;
 11     public static final int HEIGHT = 10;
 12     // 炮弹自己的三个属性
 13     int x;
 14     int y;
 15     Tank.Direction dir;
 16 
 17     // 定义一个布尔类型的变量来判断炮弹是否已经消亡
 18     private boolean live = true;
 19     //我们在Missile类中也持有一个TankClient的引用
 20     //在炮弹出界的时候就可以从装炮弹的missiles集合中去除该炮弹,不再对其重画
 21     private TankClient tc;
 22 
 23     public boolean isLive() {
 24         return live;
 25     }
 26 
 27     public Missile(int x, int y, Tank.Direction dir) {
 28         this.x = x;
 29         this.y = y;
 30         this.dir = dir;
 31     }
 32     public Missile(int x,int y,Tank.Direction dir,TankClient tc){
 33         this(x, y, dir);
 34         this.tc=tc;
 35     }
 36 
 37     // 炮弹自己的draw方法
 38     public void draw(Graphics g) {
 39         //炮弹消亡就不需要再画出来了
 40         if(!live){
 41             tc.missiles.remove(this);
 42             return;
 43         }
 44         Color c = g.getColor();
 45         g.setColor(Color.BLACK);
 46         // 炮弹形状不要比坦克大,这里设置成10,10;
 47         g.fillOval(x, y, WIDTH, HEIGHT);
 48         g.setColor(c);
 49         move();
 50     }
 51 
 52     public void move() {
 53         switch (dir) {
 54         case L:
 55             x -= XSPEED;
 56             break;
 57         case R:
 58             x += XSPEED;
 59             break;
 60         case U:
 61             y -= YSPEED;
 62             break;
 63         case D:
 64             y += YSPEED;
 65             break;
 66         case LU:
 67             x -= XSPEED;
 68             y -= YSPEED;
 69             break;
 70         case LD:
 71             x -= XSPEED;
 72             y += YSPEED;
 73             break;
 74         case RU:
 75             x += XSPEED;
 76             y -= YSPEED;
 77             break;
 78         case RD:
 79             x += XSPEED;
 80             y += YSPEED;
 81             break;
 82         // 炮弹就没有STOP这个枚举类型的值了
 83         /*
 84          * case STOP: break;
 85          */
 86         }
 87         // 判断炮弹出边界则消亡
 88         // 注意x,y只有正数值,x向右递增,y向下递增
 89         if (x < 0 || y < 0 || x > TankClient.GAME_WIDTH
 90                 || y > TankClient.GAME_HEIGHT) {
 91             live = false;
 92         }
 93     }
 94     public boolean hitTank(Tank t){
 95         //炮弹的方框和坦克的方框碰在一起了并且坦克是存活着的
 96         if(this.getRect().intersects(t.getRect())&&t.isLive()){
 97             t.setLive(false);
 98             this.live=false;
 99             
100             //炮弹击中坦克,发生爆炸
101             Explode e=new Explode(x, y, tc);
102             tc.explodes.add(e);
103             return true;
104         }
105         return false;
106     }
107     //碰撞检测类Rectangle
108     //拿到包围在炮弹周围的小方块
109     public Rectangle getRect(){
110         return new Rectangle(x,y,WIDTH,HEIGHT);
111     }
112 }
View Code

Explode:

技术分享
 1 import java.awt.*;
 2 
 3 public class Explode {
 4     //爆炸的位置
 5     int x, y;
 6     //爆炸是否存在
 7     private boolean live = true;
 8     
 9     //持有一个Tankclient的引用
10     private TankClient tc ;
11     
12     //定义不同直径大小的爆炸
13     int[] diameter = {4, 7, 12, 18, 26, 32, 49, 30, 14, 6};
14     //爆炸发生到哪一个阶段了,对应相应大小的直径
15     int step = 0;
16     
17     public Explode(int x, int y, TankClient tc) {
18         this.x = x;
19         this.y = y;
20         this.tc = tc;
21     }
22     
23     public void draw(Graphics g) {
24         if(!live) {
25             //爆炸发生,将相应直径的爆炸圆从集合explodes中去除
26             tc.explodes.remove(this);
27             return;
28         }
29         
30         if(step == diameter.length) {
31             live = false;
32             step = 0;
33             return;
34         }
35         
36         Color c = g.getColor();
37         g.setColor(Color.ORANGE);
38         
39         //把不同的圆画出来
40         g.fillOval(x, y, diameter[step], diameter[step]);
41         g.setColor(c);
42         
43         step ++;
44     }
45 }
View Code

TankClient:

技术分享
  1 import java.awt.*;
  2 import java.awt.event.*;
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 
  6 public class TankClient extends Frame {
  7     // 设置成常量,方便以后的改动
  8     public static final int GAME_WIDTH = 800;
  9     public static final int GAME_HEIGHT = 600;
 10 
 11     // 将当前的TankClient对象传递给myTank;
 12     // 目的是方便我们在Tank这个类中访问m(炮弹对象)这个成员变量
 13     // 其实就是在Tank类中持有TankClient类对象的一个引用
 14     
 15     //我们这里new我们自己的坦克,用下面的方式
 16     Tank myTank = new Tank(50, 50, true,this);
 17     
 18     //新建敌方坦克
 19     Tank enemyTank=new Tank(100,100,false,this);
 20     //定义爆炸
 21     Explode e=new Explode(70, 70, this);
 22     //定义一个集合,多个爆炸点
 23     List<Explode> explodes=new ArrayList<Explode>();
 24     
 25     //使用容器装炮弹
 26     List<Missile> missiles=new ArrayList<Missile>();
 27 
 28     // 定义虚拟图片,方便后期的一次性显示
 29     Image offScreenImage = null;
 30 
 31     
 32     public void paint(Graphics g) {
 33         //记录屏幕上的子弹数目
 34         g.drawString("missiles count:" + missiles.size(), 10, 50);
 35     

以上是关于坦克大战(版本1.7-版本2.4)的主要内容,如果未能解决你的问题,请参考以下文章

坦克大战(版本1.0-版本1.6)

基于Netty的坦克大战网络版本

2019.04.19 坦克大战

Python游戏开发,pygame模块,Python实现升级版坦克大战小游戏

Tanks坦克大战

韩顺平--Java坦克大战