zoukankan      html  css  js  c++  java
  • 坦克大战(版本1.0-版本1.6)

    版本1.0

    功能: 添加子弹类

    步骤: 1)添加Missile类;

             2)添加x,y,dir等属性以及常量;

             3)添加构造方法、draw方法等必要方法;

             4)根据不同方向,进行不同的运动;

             5)在TankClient中模拟一颗子弹;

             6)new一颗子弹出来;

             7)画出来

    注意: 不一定一次写到位,进行多次试验,将步骤分解开来逐一进行调试;

    具体代码实现:

    Tank:

      1 import java.awt.*;
      2 import java.awt.event.*;
      3 
      4 public class Tank {
      5     // 方便后期更改
      6     public static final int XSPEED = 5;
      7     public static final int YSPEED = 5;
      8     private int x;
      9     private int y;
     10     // 添加记录按键状态的布尔量
     11     private boolean bL = false;
     12     private boolean bR = false;
     13     private boolean bU = false;
     14     private boolean bD = false;
     15 
     16     // 添加代表方向的量(使用枚举)
     17     enum Direction {
     18         L, R, U, D, LU, LD, RU, RD, STOP
     19     };
     20 
     21     private Direction dir = Direction.STOP;
     22 
     23     public Tank(int x, int y) {
     24         this.x = x;
     25         this.y = y;
     26     }
     27 
     28     // Tank对象的draw方法
     29     public void draw(Graphics g) {
     30         Color c = g.getColor();
     31         g.setColor(Color.RED);
     32         g.fillOval(x, y, 30, 30);
     33         g.setColor(c);
     34         move();
     35     }
     36 
     37     public void move() {
     38         switch (dir) {
     39         case L:
     40             x -= XSPEED;
     41             break;
     42         case R:
     43             x += XSPEED;
     44             break;
     45         case U:
     46             y -= YSPEED;
     47             break;
     48         case D:
     49             y += YSPEED;
     50             break;
     51         case LU:
     52             x -= XSPEED;
     53             y -= YSPEED;
     54             break;
     55         case LD:
     56             x -= XSPEED;
     57             y += YSPEED;
     58             break;
     59         case RU:
     60             x += XSPEED;
     61             y -= YSPEED;
     62             break;
     63         case RD:
     64             x += XSPEED;
     65             y += YSPEED;
     66             break;
     67 
     68         case STOP:
     69             break;
     70         }
     71     }
     72 
     73     public void locateDirection() {
     74         if (bL && !bU && !bR && !bD)
     75             dir = Direction.L;
     76         else if (bL && bU && !bR && !bD)
     77             dir = Direction.LU;
     78         else if (!bL && bU && !bR && !bD)
     79             dir = Direction.U;
     80         else if (!bL && bU && bR && !bD)
     81             dir = Direction.RU;
     82         else if (!bL && !bU && bR && !bD)
     83             dir = Direction.R;
     84         else if (!bL && !bU && bR && bD)
     85             dir = Direction.RD;
     86         else if (!bL && !bU && !bR && bD)
     87             dir = Direction.D;
     88         else if (bL && !bU && !bR && bD)
     89             dir = Direction.LD;
     90         else if (!bL && !bU && !bR && !bD)
     91             dir = Direction.STOP;
     92 
     93     }
     94 
     95     // 坦克自己向哪个方向移动,它自己最清楚;
     96     public void KeyPressed(KeyEvent e) {
     97         // 获得所按下的键所对应的虚拟码:
     98         // Returns the integer keyCode associated with the key in this event
     99         int key = e.getKeyCode();
    100         // 判断不同的按键,指挥坦克的运动方向
    101         switch (key) {
    102         case KeyEvent.VK_LEFT:
    103             bL = true;
    104             break;
    105         case KeyEvent.VK_UP:
    106             bU = true;
    107             break;
    108         case KeyEvent.VK_RIGHT:
    109             bR = true;
    110             break;
    111         case KeyEvent.VK_DOWN:
    112             bD = true;
    113             break;
    114         }
    115         locateDirection();
    116     }
    117 
    118     public void keyReleased(KeyEvent e) {
    119         int key = e.getKeyCode();
    120         // 判断不同的按键,指挥坦克的运动方向
    121         // 哪个键按下了,就把对应方向的布尔类型置为false
    122         switch (key) {
    123         case KeyEvent.VK_LEFT:
    124             bL = false;
    125             break;
    126         case KeyEvent.VK_UP:
    127             bU = false;
    128             break;
    129         case KeyEvent.VK_RIGHT:
    130             bR = false;
    131             break;
    132         case KeyEvent.VK_DOWN:
    133             bD = false;
    134             break;
    135         }
    136         // 重新定位一下
    137         locateDirection();
    138     }
    139 }
    View Code

    Missile:新添加的子弹类

     1 import java.awt.Color;
     2 import java.awt.Graphics;
     3 
     4 public class Missile {
     5     //炮弹的移动速度,不要比坦克的移动速度慢,不然你看到的是满屏的坦克追着炮弹跑
     6     public static final int XSPEED=10;
     7     public static final int YSPEED=10;
     8     //炮弹自己的三个属性
     9     int x;
    10     int y;
    11     Tank.Direction dir;
    12     public Missile(int x, int y, Tank.Direction dir) {
    13         this.x = x;
    14         this.y = y;
    15         this.dir = dir;
    16     }
    17     //炮弹自己的draw方法
    18     public void draw(Graphics g){
    19         Color c=g.getColor();
    20         g.setColor(Color.BLACK);
    21         //炮弹形状不要比坦克大,这里设置成10,10;
    22         g.fillOval(x, y, 10, 10);
    23         g.setColor(c);
    24         move();
    25     }
    26     public  void move() {
    27         switch (dir) {
    28         case L:
    29             x -= XSPEED;
    30             break;
    31         case R:
    32             x += XSPEED;
    33             break;
    34         case U:
    35             y -= YSPEED;
    36             break;
    37         case D:
    38             y += YSPEED;
    39             break;
    40         case LU:
    41             x -= XSPEED;
    42             y -= YSPEED;
    43             break;
    44         case LD:
    45             x -= XSPEED;
    46             y += YSPEED;
    47             break;
    48         case RU:
    49             x += XSPEED;
    50             y -= YSPEED;
    51             break;
    52         case RD:
    53             x += XSPEED;
    54             y += YSPEED;
    55             break;
    56         //炮弹就没有STOP这个枚举类型的值了
    57     /*    case STOP:
    58             break;*/
    59         }
    60     }
    61 }

    TankClient:在TankClient中模拟一颗子弹

     1 import java.awt.*;
     2 import java.awt.event.*;
     3 
     4 public class TankClient extends Frame {
     5     // 设置成常量,方便以后的改动
     6     public static final int GAME_WIDTH = 800;
     7     public static final int GAME_HEIGHT = 600;
     8     Tank myTank = new Tank(50, 50);
     9 
    10     // 在TankClient中定义炮弹
    11     Missile m = new Missile(50, 50, Tank.Direction.R);
    12     // 定义虚拟图片,方便后期的一次性显示
    13     Image offScreenImage = null;
    14 
    15     public void paint(Graphics g) {
    16         // 把炮弹画出来
    17         m.draw(g);
    18         // 不改变前景色
    19         myTank.draw(g);
    20     }
    21 
    22     // 刷新操作
    23     public void update(Graphics g) {
    24         if (offScreenImage == null) {
    25             offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
    26         }
    27         Graphics gOffScreen = offScreenImage.getGraphics();
    28         Color c = gOffScreen.getColor();
    29         gOffScreen.setColor(Color.GREEN);
    30         gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
    31         gOffScreen.setColor(c);
    32         paint(gOffScreen);
    33         g.drawImage(offScreenImage, 0, 0, null);
    34     }
    35 
    36     public void lauchFrame() {
    37         this.setLocation(400, 300);
    38         this.setSize(GAME_WIDTH, GAME_HEIGHT);
    39         this.setTitle("TankWar");
    40         this.addWindowListener(new WindowAdapter() {
    41             public void windowClosing(WindowEvent e) {
    42                 System.exit(0);
    43             }
    44         });
    45         this.setResizable(false);
    46         this.setBackground(Color.GREEN);
    47 
    48         this.addKeyListener(new KeyMonitor());
    49 
    50         setVisible(true);
    51 
    52         new Thread(new PaintThread()).start();
    53     }
    54 
    55     public static void main(String[] args) {
    56         TankClient tc = new TankClient();
    57         tc.lauchFrame();
    58     }
    59 
    60     private class PaintThread implements Runnable {
    61 
    62         public void run() {
    63             while (true) {
    64                 repaint();
    65                 try {
    66                     Thread.sleep(50);
    67                 } catch (InterruptedException e) {
    68                     e.printStackTrace();
    69                 }
    70             }
    71         }
    72     }
    73 
    74     // 创建键盘时间监听
    75     private class KeyMonitor extends KeyAdapter {
    76 
    77         // 直接调用myTank自己的方法根据相应的按键信息进行移动
    78         public void keyPressed(KeyEvent e) {
    79             myTank.KeyPressed(e);
    80             // 添加了处理键抬起的事件,可以控制坦克起步以后的状态
    81             // 而不是一直按照一个方向走下去
    82         }
    83         public void keyReleased(KeyEvent e){
    84             myTank.keyReleased(e);
    85         }
    86 
    87     }
    88 }
    View Code

    版本1.1

    功能:根据主战坦克的方向和位置,打出子弹,让子弹从坦克的中心打出来;

    步骤:

           1)增加对Ctrl键的按键处理;

           2)根据“坦克打出一发子弹”这句话,来确定Tank中的方法fire,其返回值为Missle;

           3)根据Tank方向和位置设定子弹的方向和位置并new出来,然后返回(fire方法的实现)

    注意: 掌握面向对象的思维方式来确定类应该具有的方法

    下面这个图中左上角是坦克的的位置(x,y),圆心中心是坦克的中心,w是坦克的宽度,h是坦克的高度,我们计算炮弹的位置可以通过下面的公式计算:

    注意x轴向右递增,y轴向下递增;

        int x=this.x+Tank.WIDTH/2-Missile.WIDTH/2;
        int y=this.y+Tank.HEIGHT/2-Missile.HEIGHT/2;

    具体代码实现:

    Tank:

      1 import java.awt.*;
      2 import java.awt.event.*;
      3 
      4 public class Tank {
      5     // 方便后期更改
      6     public static final int XSPEED = 5;
      7     public static final int YSPEED = 5;
      8     // 将坦克的高度和宽度设置为常量
      9     public static final int WIDTH = 30;
     10     public static final int HEIGHT = 30;
     11     TankClient tc = null;
     12     private int x;
     13     private int y;
     14     // 添加记录按键状态的布尔量
     15     private boolean bL = false;
     16     private boolean bR = false;
     17     private boolean bU = false;
     18     private boolean bD = false;
     19 
     20     // 添加代表方向的量(使用枚举)
     21     enum Direction {
     22         L, R, U, D, LU, LD, RU, RD, STOP
     23     };
     24 
     25     private Direction dir = Direction.STOP;
     26 
     27     public Tank(int x, int y) {
     28         this.x = x;
     29         this.y = y;
     30     }
     31 
     32     public Tank(int x, int y, TankClient tc) {
     33         // 调用那个有两个参数的构造方法
     34         this(x, y);
     35         // 在这个位置初始化tc
     36         this.tc = tc;
     37     }
     38 
     39     // Tank对象的draw方法
     40     public void draw(Graphics g) {
     41         Color c = g.getColor();
     42         g.setColor(Color.RED);
     43         g.fillOval(x, y, WIDTH, HEIGHT);
     44         g.setColor(c);
     45         move();
     46     }
     47 
     48     public void move() {
     49         switch (dir) {
     50         case L:
     51             x -= XSPEED;
     52             break;
     53         case R:
     54             x += XSPEED;
     55             break;
     56         case U:
     57             y -= YSPEED;
     58             break;
     59         case D:
     60             y += YSPEED;
     61             break;
     62         case LU:
     63             x -= XSPEED;
     64             y -= YSPEED;
     65             break;
     66         case LD:
     67             x -= XSPEED;
     68             y += YSPEED;
     69             break;
     70         case RU:
     71             x += XSPEED;
     72             y -= YSPEED;
     73             break;
     74         case RD:
     75             x += XSPEED;
     76             y += YSPEED;
     77             break;
     78 
     79         case STOP:
     80             break;
     81         }
     82     }
     83 
     84     public void locateDirection() {
     85         if (bL && !bU && !bR && !bD)
     86             dir = Direction.L;
     87         else if (bL && bU && !bR && !bD)
     88             dir = Direction.LU;
     89         else if (!bL && bU && !bR && !bD)
     90             dir = Direction.U;
     91         else if (!bL && bU && bR && !bD)
     92             dir = Direction.RU;
     93         else if (!bL && !bU && bR && !bD)
     94             dir = Direction.R;
     95         else if (!bL && !bU && bR && bD)
     96             dir = Direction.RD;
     97         else if (!bL && !bU && !bR && bD)
     98             dir = Direction.D;
     99         else if (bL && !bU && !bR && bD)
    100             dir = Direction.LD;
    101         else if (!bL && !bU && !bR && !bD)
    102             dir = Direction.STOP;
    103 
    104     }
    105 
    106     // 坦克自己向哪个方向移动,它自己最清楚;
    107     public void KeyPressed(KeyEvent e) {
    108         // 获得所按下的键所对应的虚拟码:
    109         // Returns the integer keyCode associated with the key in this event
    110         int key = e.getKeyCode();
    111         // 判断不同的按键,指挥坦克的运动方向
    112         switch (key) {
    113         // Ctrl键控制打出炮弹
    114         case KeyEvent.VK_CONTROL:
    115             // fire函数返回的是一个Missile类型的对象
    116             tc.m = fire();
    117             break;
    118         case KeyEvent.VK_LEFT:
    119             bL = true;
    120             break;
    121         case KeyEvent.VK_UP:
    122             bU = true;
    123             break;
    124         case KeyEvent.VK_RIGHT:
    125             bR = true;
    126             break;
    127         case KeyEvent.VK_DOWN:
    128             bD = true;
    129             break;
    130         }
    131         locateDirection();
    132     }
    133 
    134     public void keyReleased(KeyEvent e) {
    135         int key = e.getKeyCode();
    136         // 判断不同的按键,指挥坦克的运动方向
    137         // 哪个键按下了,就把对应方向的布尔类型置为false
    138         switch (key) {
    139         case KeyEvent.VK_LEFT:
    140             bL = false;
    141             break;
    142         case KeyEvent.VK_UP:
    143             bU = false;
    144             break;
    145         case KeyEvent.VK_RIGHT:
    146             bR = false;
    147             break;
    148         case KeyEvent.VK_DOWN:
    149             bD = false;
    150             break;
    151         }
    152         // 重新定位一下
    153         locateDirection();
    154     }
    155 
    156     public Missile fire() {
    157         // 计算子弹的位置,使得子弹从坦克的中间发出来
    158         int x = this.x + Tank.WIDTH / 2 - Missile.WIDTH / 2;
    159         int y = this.y + Tank.HEIGHT / 2 - Missile.HEIGHT / 2;
    160         // 将坦克的位置和方向传递给炮弹
    161         Missile m = new Missile(x, y, dir);
    162         return m;
    163     }
    164 }
    View Code

    Missile:

     1 import java.awt.Color;
     2 import java.awt.Graphics;
     3 
     4 public class Missile {
     5     // 炮弹的移动速度,不要比坦克的移动速度慢,不然你看到的是满屏的坦克追着炮弹跑
     6     public static final int XSPEED = 10;
     7     public static final int YSPEED = 10;
     8     // 将子弹的高度和宽度设置为常量
     9     public static final int WIDTH = 10;
    10     public static final int HEIGHT = 10;
    11     // 炮弹自己的三个属性
    12     int x;
    13     int y;
    14     Tank.Direction dir;
    15 
    16     public Missile(int x, int y, Tank.Direction dir) {
    17         this.x = x;
    18         this.y = y;
    19         this.dir = dir;
    20     }
    21 
    22     // 炮弹自己的draw方法
    23     public void draw(Graphics g) {
    24         Color c = g.getColor();
    25         g.setColor(Color.BLACK);
    26         // 炮弹形状不要比坦克大,这里设置成10,10;
    27         g.fillOval(x, y, WIDTH, HEIGHT);
    28         g.setColor(c);
    29         move();
    30     }
    31 
    32     public void move() {
    33         switch (dir) {
    34         case L:
    35             x -= XSPEED;
    36             break;
    37         case R:
    38             x += XSPEED;
    39             break;
    40         case U:
    41             y -= YSPEED;
    42             break;
    43         case D:
    44             y += YSPEED;
    45             break;
    46         case LU:
    47             x -= XSPEED;
    48             y -= YSPEED;
    49             break;
    50         case LD:
    51             x -= XSPEED;
    52             y += YSPEED;
    53             break;
    54         case RU:
    55             x += XSPEED;
    56             y -= YSPEED;
    57             break;
    58         case RD:
    59             x += XSPEED;
    60             y += YSPEED;
    61             break;
    62         // 炮弹就没有STOP这个枚举类型的值了
    63         /*
    64          * case STOP: break;
    65          */
    66         }
    67     }
    68 }
    View Code

    TankClient:

     1 import java.awt.*;
     2 import java.awt.event.*;
     3 
     4 public class TankClient extends Frame {
     5     // 设置成常量,方便以后的改动
     6     public static final int GAME_WIDTH = 800;
     7     public static final int GAME_HEIGHT = 600;
     8 
     9     //将当前的TankClient对象传递给myTank;
    10     //目的是方便我们在Tank这个类中访问m(炮弹对象)这个成员变量
    11     //其实就是在Tank类中持有TankClient类对象的一个引用
    12     Tank myTank = new Tank(50, 50,this);
    13 
    14     //炮弹不是固定的了,这里先不给出初始化
    15     Missile m =null;
    16     // 定义虚拟图片,方便后期的一次性显示
    17     Image offScreenImage = null;
    18 
    19     public void paint(Graphics g) {
    20         //m!=null的时候才将炮弹画出来,否则会报空指针异常
    21         if(m!=null){
    22             // 把炮弹画出来
    23             m.draw(g);        
    24         }
    25         // 不改变前景色
    26         myTank.draw(g);
    27     }
    28 
    29     // 刷新操作
    30     public void update(Graphics g) {
    31         if (offScreenImage == null) {
    32             offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
    33         }
    34         Graphics gOffScreen = offScreenImage.getGraphics();
    35         Color c = gOffScreen.getColor();
    36         gOffScreen.setColor(Color.GREEN);
    37         gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
    38         gOffScreen.setColor(c);
    39         paint(gOffScreen);
    40         g.drawImage(offScreenImage, 0, 0, null);
    41     }
    42 
    43     public void lauchFrame() {
    44         this.setLocation(400, 300);
    45         this.setSize(GAME_WIDTH, GAME_HEIGHT);
    46         this.setTitle("TankWar");
    47         this.addWindowListener(new WindowAdapter() {
    48             public void windowClosing(WindowEvent e) {
    49                 System.exit(0);
    50             }
    51         });
    52         this.setResizable(false);
    53         this.setBackground(Color.GREEN);
    54 
    55         this.addKeyListener(new KeyMonitor());
    56 
    57         setVisible(true);
    58 
    59         new Thread(new PaintThread()).start();
    60     }
    61 
    62     public static void main(String[] args) {
    63         TankClient tc = new TankClient();
    64         tc.lauchFrame();
    65     }
    66 
    67     private class PaintThread implements Runnable {
    68 
    69         public void run() {
    70             while (true) {
    71                 repaint();
    72                 try {
    73                     Thread.sleep(50);
    74                 } catch (InterruptedException e) {
    75                     e.printStackTrace();
    76                 }
    77             }
    78         }
    79     }
    80 
    81     // 创建键盘时间监听
    82     private class KeyMonitor extends KeyAdapter {
    83 
    84         // 直接调用myTank自己的方法根据相应的按键信息进行移动
    85         public void keyPressed(KeyEvent e) {
    86             myTank.KeyPressed(e);
    87             // 添加了处理键抬起的事件,可以控制坦克起步以后的状态
    88             // 而不是一直按照一个方向走下去
    89         }
    90         public void keyReleased(KeyEvent e){
    91             myTank.keyReleased(e);
    92         }
    93 
    94     }
    95 }
    View Code

    版本1.2

    功能:为了解决坦克停下也能打出炮弹的问题—画出炮筒,因为你会发现我们的版本1.1中坦克不动,按下Ctrl键是没有炮弹的,我们要实现坦克停着也要能发炮弹;

    步骤:

            1)Tank类增加新的属性ptDir

            2)每次move后根据Tank新的方向确定炮筒的方向

            3)将炮筒用直线的形式表现出来

    相较于炮弹的坐标(即图中左上角的x,y)值,计算炮筒(即我们用一条直线代表炮筒)的另一头(也就是炮筒的出弹口)的坐标,在代码中有体现;

    Tank:

      1 import java.awt.*;
      2 import java.awt.event.*;
      3 
      4 public class Tank {
      5     // 方便后期更改
      6     public static final int XSPEED = 5;
      7     public static final int YSPEED = 5;
      8     // 将坦克的高度和宽度设置为常量
      9     public static final int WIDTH = 30;
     10     public static final int HEIGHT = 30;
     11     TankClient tc = null;
     12     private int x;
     13     private int y;
     14     // 添加记录按键状态的布尔量
     15     private boolean bL = false;
     16     private boolean bR = false;
     17     private boolean bU = false;
     18     private boolean bD = false;
     19 
     20     // 添加代表方向的量(使用枚举)
     21     enum Direction {
     22         L, R, U, D, LU, LD, RU, RD, STOP
     23     };
     24 
     25     private Direction dir = Direction.STOP;
     26 
     27     // 定义炮筒的方向,我们想办法将炮筒的方法调整成和坦克移动方向一致;
     28     // 我们这里会用一条直线来表示炮筒:模拟炮筒
     29     // 我们要根据炮筒的方向画直线表示炮筒
     30     Direction ptDir = Direction.D;
     31 
     32     public Tank(int x, int y) {
     33         this.x = x;
     34         this.y = y;
     35     }
     36 
     37     public Tank(int x, int y, TankClient tc) {
     38         // 调用那个有两个参数的构造方法
     39         this(x, y);
     40         // 在这个位置初始化tc
     41         this.tc = tc;
     42     }
     43 
     44     // Tank对象的draw方法
     45     public void draw(Graphics g) {
     46         Color c = g.getColor();
     47         g.setColor(Color.RED);
     48         g.fillOval(x, y, WIDTH, HEIGHT);
     49         g.setColor(c);
     50         // 根据炮筒的方向画直线来表示我们坦克的炮筒
     51         switch (ptDir) {
     52         case L:
     53             // 画直线:四个参数分别代表:坦克中心点的坐标 直线的另一头的的坐标
     54             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y
     55                     + Tank.HEIGHT / 2);
     56             break;
     57         case R:
     58             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
     59                     y + Tank.HEIGHT / 2);
     60 
     61             break;
     62         case U:
     63             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH
     64                     / 2, y);
     65 
     66             break;
     67         case D:
     68             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH
     69                     / 2, y + Tank.HEIGHT);
     70 
     71             break;
     72         case LU:
     73             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y);
     74             break;
     75         case LD:
     76             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y
     77                     + Tank.HEIGHT);
     78 
     79             break;
     80         case RU:
     81             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
     82                     y);
     83 
     84             break;
     85         case RD:
     86             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
     87                     y + Tank.HEIGHT);
     88 
     89             break;
     90         /*
     91          * case STOP: break;
     92          */
     93         }
     94         move();
     95     }
     96 
     97     public void move() {
     98         switch (dir) {
     99         case L:
    100             x -= XSPEED;
    101             break;
    102         case R:
    103             x += XSPEED;
    104             break;
    105         case U:
    106             y -= YSPEED;
    107             break;
    108         case D:
    109             y += YSPEED;
    110             break;
    111         case LU:
    112             x -= XSPEED;
    113             y -= YSPEED;
    114             break;
    115         case LD:
    116             x -= XSPEED;
    117             y += YSPEED;
    118             break;
    119         case RU:
    120             x += XSPEED;
    121             y -= YSPEED;
    122             break;
    123         case RD:
    124             x += XSPEED;
    125             y += YSPEED;
    126             break;
    127 
    128         case STOP:
    129             break;
    130         }
    131         // 如果坦克不是停着的,则将炮筒调整至和坦克移动的方向相同
    132         if (this.dir != Direction.STOP) {
    133             this.ptDir = this.dir;
    134         }
    135     }
    136 
    137     public void locateDirection() {
    138         if (bL && !bU && !bR && !bD)
    139             dir = Direction.L;
    140         else if (bL && bU && !bR && !bD)
    141             dir = Direction.LU;
    142         else if (!bL && bU && !bR && !bD)
    143             dir = Direction.U;
    144         else if (!bL && bU && bR && !bD)
    145             dir = Direction.RU;
    146         else if (!bL && !bU && bR && !bD)
    147             dir = Direction.R;
    148         else if (!bL && !bU && bR && bD)
    149             dir = Direction.RD;
    150         else if (!bL && !bU && !bR && bD)
    151             dir = Direction.D;
    152         else if (bL && !bU && !bR && bD)
    153             dir = Direction.LD;
    154         else if (!bL && !bU && !bR && !bD)
    155             dir = Direction.STOP;
    156 
    157     }
    158 
    159     // 坦克自己向哪个方向移动,它自己最清楚;
    160     public void KeyPressed(KeyEvent e) {
    161         // 获得所按下的键所对应的虚拟码:
    162         // Returns the integer keyCode associated with the key in this event
    163         int key = e.getKeyCode();
    164         // 判断不同的按键,指挥坦克的运动方向
    165         switch (key) {
    166         // Ctrl键控制打出炮弹
    167         case KeyEvent.VK_CONTROL:
    168             // fire函数返回的是一个Missile类型的对象
    169             tc.m = fire();
    170             break;
    171         case KeyEvent.VK_LEFT:
    172             bL = true;
    173             break;
    174         case KeyEvent.VK_UP:
    175             bU = true;
    176             break;
    177         case KeyEvent.VK_RIGHT:
    178             bR = true;
    179             break;
    180         case KeyEvent.VK_DOWN:
    181             bD = true;
    182             break;
    183         }
    184         locateDirection();
    185     }
    186 
    187     public void keyReleased(KeyEvent e) {
    188         int key = e.getKeyCode();
    189         // 判断不同的按键,指挥坦克的运动方向
    190         // 哪个键按下了,就把对应方向的布尔类型置为false
    191         switch (key) {
    192         case KeyEvent.VK_LEFT:
    193             bL = false;
    194             break;
    195         case KeyEvent.VK_UP:
    196             bU = false;
    197             break;
    198         case KeyEvent.VK_RIGHT:
    199             bR = false;
    200             break;
    201         case KeyEvent.VK_DOWN:
    202             bD = false;
    203             break;
    204         }
    205         // 重新定位一下
    206         locateDirection();
    207     }
    208 
    209     public Missile fire() {
    210         // 计算子弹的位置,使得子弹从坦克的中间发出来
    211         int x = this.x + Tank.WIDTH / 2 - Missile.WIDTH / 2;
    212         int y = this.y + Tank.HEIGHT / 2 - Missile.HEIGHT / 2;
    213         // 这个时候我们就根据炮筒的方向来发炮弹了,之前是根据坦克的方向来发炮弹
    214         Missile m = new Missile(x, y, dir);
    215         return m;
    216     }
    217 }
    View Code

    Missile:

     1 import java.awt.Color;
     2 import java.awt.Graphics;
     3 
     4 public class Missile {
     5     // 炮弹的移动速度,不要比坦克的移动速度慢,不然你看到的是满屏的坦克追着炮弹跑
     6     public static final int XSPEED = 10;
     7     public static final int YSPEED = 10;
     8     // 将子弹的高度和宽度设置为常量
     9     public static final int WIDTH = 10;
    10     public static final int HEIGHT = 10;
    11     // 炮弹自己的三个属性
    12     int x;
    13     int y;
    14     Tank.Direction dir;
    15 
    16     public Missile(int x, int y, Tank.Direction dir) {
    17         this.x = x;
    18         this.y = y;
    19         this.dir = dir;
    20     }
    21 
    22     // 炮弹自己的draw方法
    23     public void draw(Graphics g) {
    24         Color c = g.getColor();
    25         g.setColor(Color.BLACK);
    26         // 炮弹形状不要比坦克大,这里设置成10,10;
    27         g.fillOval(x, y, WIDTH, HEIGHT);
    28         g.setColor(c);
    29         move();
    30     }
    31 
    32     public void move() {
    33         switch (dir) {
    34         case L:
    35             x -= XSPEED;
    36             break;
    37         case R:
    38             x += XSPEED;
    39             break;
    40         case U:
    41             y -= YSPEED;
    42             break;
    43         case D:
    44             y += YSPEED;
    45             break;
    46         case LU:
    47             x -= XSPEED;
    48             y -= YSPEED;
    49             break;
    50         case LD:
    51             x -= XSPEED;
    52             y += YSPEED;
    53             break;
    54         case RU:
    55             x += XSPEED;
    56             y -= YSPEED;
    57             break;
    58         case RD:
    59             x += XSPEED;
    60             y += YSPEED;
    61             break;
    62         // 炮弹就没有STOP这个枚举类型的值了
    63         /*
    64          * case STOP: break;
    65          */
    66         }
    67     }
    68 }
    View Code

    TankClient:

     1 import java.awt.*;
     2 import java.awt.event.*;
     3 
     4 public class TankClient extends Frame {
     5     // 设置成常量,方便以后的改动
     6     public static final int GAME_WIDTH = 800;
     7     public static final int GAME_HEIGHT = 600;
     8 
     9     // 将当前的TankClient对象传递给myTank;
    10     // 目的是方便我们在Tank这个类中访问m(炮弹对象)这个成员变量
    11     // 其实就是在Tank类中持有TankClient类对象的一个引用
    12     Tank myTank = new Tank(50, 50, this);
    13 
    14     // 炮弹不是固定的了,这里先不给出初始化
    15     Missile m = null;
    16     // 定义虚拟图片,方便后期的一次性显示
    17     Image offScreenImage = null;
    18 
    19     public void paint(Graphics g) {
    20         // m!=null的时候才将炮弹画出来,否则会报空指针异常
    21         if (m != null) {
    22             // 把炮弹画出来
    23             m.draw(g);
    24         }
    25         // 不改变前景色
    26         myTank.draw(g);
    27     }
    28 
    29     // 刷新操作
    30     public void update(Graphics g) {
    31         if (offScreenImage == null) {
    32             offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
    33         }
    34         Graphics gOffScreen = offScreenImage.getGraphics();
    35         Color c = gOffScreen.getColor();
    36         gOffScreen.setColor(Color.GREEN);
    37         gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
    38         gOffScreen.setColor(c);
    39         paint(gOffScreen);
    40         g.drawImage(offScreenImage, 0, 0, null);
    41     }
    42 
    43     public void lauchFrame() {
    44         this.setLocation(400, 300);
    45         this.setSize(GAME_WIDTH, GAME_HEIGHT);
    46         this.setTitle("TankWar");
    47         this.addWindowListener(new WindowAdapter() {
    48             public void windowClosing(WindowEvent e) {
    49                 System.exit(0);
    50             }
    51         });
    52         this.setResizable(false);
    53         this.setBackground(Color.GREEN);
    54 
    55         this.addKeyListener(new KeyMonitor());
    56 
    57         setVisible(true);
    58 
    59         new Thread(new PaintThread()).start();
    60     }
    61 
    62     public static void main(String[] args) {
    63         TankClient tc = new TankClient();
    64         tc.lauchFrame();
    65     }
    66 
    67     private class PaintThread implements Runnable {
    68 
    69         public void run() {
    70             while (true) {
    71                 repaint();
    72                 try {
    73                     Thread.sleep(50);
    74                 } catch (InterruptedException e) {
    75                     e.printStackTrace();
    76                 }
    77             }
    78         }
    79     }
    80 
    81     // 创建键盘时间监听
    82     private class KeyMonitor extends KeyAdapter {
    83 
    84         // 直接调用myTank自己的方法根据相应的按键信息进行移动
    85         public void keyPressed(KeyEvent e) {
    86             myTank.KeyPressed(e);
    87             // 添加了处理键抬起的事件,可以控制坦克起步以后的状态
    88             // 而不是一直按照一个方向走下去
    89         }
    90 
    91         public void keyReleased(KeyEvent e) {
    92             myTank.keyReleased(e);
    93         }
    94 
    95     }
    96 }
    View Code

    经过这个版本我们的坦克可以根据炮筒的方向发出炮弹了;

    版本1.3

    功能:打出多发炮弹

    步骤:

          1)使用容器装炮弹

          2)每当抬起Ctrl键就往容器中加入新的炮弹

          3)逐一画出每一发炮弹

    注意: 泛型的使用

    Tank:

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

    Missle:

     1 import java.awt.Color;
     2 import java.awt.Graphics;
     3 
     4 public class Missile {
     5     // 炮弹的移动速度,不要比坦克的移动速度慢,不然你看到的是满屏的坦克追着炮弹跑
     6     public static final int XSPEED = 10;
     7     public static final int YSPEED = 10;
     8     // 将子弹的高度和宽度设置为常量
     9     public static final int WIDTH = 10;
    10     public static final int HEIGHT = 10;
    11     // 炮弹自己的三个属性
    12     int x;
    13     int y;
    14     Tank.Direction dir;
    15 
    16     public Missile(int x, int y, Tank.Direction dir) {
    17         this.x = x;
    18         this.y = y;
    19         this.dir = dir;
    20     }
    21 
    22     // 炮弹自己的draw方法
    23     public void draw(Graphics g) {
    24         Color c = g.getColor();
    25         g.setColor(Color.BLACK);
    26         // 炮弹形状不要比坦克大,这里设置成10,10;
    27         g.fillOval(x, y, WIDTH, HEIGHT);
    28         g.setColor(c);
    29         move();
    30     }
    31 
    32     public void move() {
    33         switch (dir) {
    34         case L:
    35             x -= XSPEED;
    36             break;
    37         case R:
    38             x += XSPEED;
    39             break;
    40         case U:
    41             y -= YSPEED;
    42             break;
    43         case D:
    44             y += YSPEED;
    45             break;
    46         case LU:
    47             x -= XSPEED;
    48             y -= YSPEED;
    49             break;
    50         case LD:
    51             x -= XSPEED;
    52             y += YSPEED;
    53             break;
    54         case RU:
    55             x += XSPEED;
    56             y -= YSPEED;
    57             break;
    58         case RD:
    59             x += XSPEED;
    60             y += YSPEED;
    61             break;
    62         // 炮弹就没有STOP这个枚举类型的值了
    63         /*
    64          * case STOP: break;
    65          */
    66         }
    67     }
    68 }
    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     Tank myTank = new Tank(50, 50, this);
     15     //使用容器装炮弹
     16     List<Missile> missiles=new ArrayList<Missile>();
     17 
     18     // 定义虚拟图片,方便后期的一次性显示
     19     Image offScreenImage = null;
     20 
     21     
     22     public void paint(Graphics g) {
     23         g.drawString("missiles count:" + missiles.size(), 10, 50);
     24 
     25         
     26         //遍历结合,发出多发炮弹
     27         for(int i=0;i<missiles.size();i++){
     28             Missile m=missiles.get(i);
     29             m.draw(g);
     30         }
     31         // 不改变前景色
     32         myTank.draw(g);
     33     }
     34 
     35     // 刷新操作
     36     public void update(Graphics g) {
     37         if (offScreenImage == null) {
     38             offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
     39         }
     40         Graphics gOffScreen = offScreenImage.getGraphics();
     41         Color c = gOffScreen.getColor();
     42         gOffScreen.setColor(Color.GREEN);
     43         gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
     44         gOffScreen.setColor(c);
     45         paint(gOffScreen);
     46         g.drawImage(offScreenImage, 0, 0, null);
     47     }
     48 
     49     public void lauchFrame() {
     50 //        this.setLocation(400, 300);
     51         this.setSize(GAME_WIDTH, GAME_HEIGHT);
     52         this.setTitle("TankWar");
     53         this.addWindowListener(new WindowAdapter() {
     54             public void windowClosing(WindowEvent e) {
     55                 System.exit(0);
     56             }
     57         });
     58         this.setResizable(false);
     59         this.setBackground(Color.GREEN);
     60 
     61         this.addKeyListener(new KeyMonitor());
     62 
     63         setVisible(true);
     64 
     65         new Thread(new PaintThread()).start();
     66     }
     67 
     68     public static void main(String[] args) {
     69         TankClient tc = new TankClient();
     70         tc.lauchFrame();
     71     }
     72 
     73     private class PaintThread implements Runnable {
     74 
     75         public void run() {
     76             while (true) {
     77                 repaint();
     78                 try {
     79                     Thread.sleep(50);
     80                 } catch (InterruptedException e) {
     81                     e.printStackTrace();
     82                 }
     83             }
     84         }
     85     }
     86 
     87     // 创建键盘时间监听
     88     private class KeyMonitor extends KeyAdapter {
     89 
     90         // 直接调用myTank自己的方法根据相应的按键信息进行移动
     91         public void keyPressed(KeyEvent e) {
     92             myTank.KeyPressed(e);
     93             // 添加了处理键抬起的事件,可以控制坦克起步以后的状态
     94             // 而不是一直按照一个方向走下去
     95         }
     96 
     97         public void keyReleased(KeyEvent e) {
     98             myTank.keyReleased(e);
     99         }
    100 
    101     }
    102 }
    View Code

    版本1.4.1

    功能:解决炮弹不消亡的问题,解决坦克出界的问题

    步骤:1)加入控制炮弹生死的量bLive(Missle):private boolean live = true;

            2)当炮弹已经死去就不需要对其重画:我们在Missile类中也持有一个TankClient的引用,在炮弹出界的时候就可以从装炮弹的missiles集合中去除该炮弹,不再对其重画

            3)当炮弹飞出边界就死亡,判断方式:

    1 if (x < 0 || y < 0 || x > TankClient.GAME_WIDTH
    2                 || y > TankClient.GAME_HEIGHT) {
    3             live = false;
    4             
    5         }

            4)当炮弹死亡就从容器中去除:

    1     if (x < 0 || y < 0 || x > TankClient.GAME_WIDTH
    2                 || y > TankClient.GAME_HEIGHT) {
    3             live = false;
    4             //炮弹消亡,从集合中删除该元素
    5             tc.missiles.remove(this);
    6         }

    在Tank类中,当我们在fire函数中生成炮弹的时候使用Missile m = new Missile(x, y, ptDir,tc);这个构造方法,将tc也作为参数传入,运行程序你会发现当所有炮弹触碰边界消亡的时候,missleCount的值变成了0;

    注意: 将思维转化为代码

    具体代码实现:

    Tank:

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

    Missile:

     1 import java.awt.Color;
     2 import java.awt.Graphics;
     3 
     4 public class Missile {
     5     // 炮弹的移动速度,不要比坦克的移动速度慢,不然你看到的是满屏的坦克追着炮弹跑
     6     public static final int XSPEED = 10;
     7     public static final int YSPEED = 10;
     8     // 将子弹的高度和宽度设置为常量
     9     public static final int WIDTH = 10;
    10     public static final int HEIGHT = 10;
    11     // 炮弹自己的三个属性
    12     int x;
    13     int y;
    14     Tank.Direction dir;
    15 
    16     // 定义一个布尔类型的变量来判断炮弹是否已经消亡
    17     private boolean live = true;
    18     //我们在Missile类中也持有一个TankClient的引用
    19     //在炮弹出界的时候就可以从装炮弹的missiles集合中去除该炮弹,不再对其重画
    20     private TankClient tc;
    21 
    22     public boolean isLive() {
    23         return live;
    24     }
    25 
    26     public Missile(int x, int y, Tank.Direction dir) {
    27         this.x = x;
    28         this.y = y;
    29         this.dir = dir;
    30     }
    31     public Missile(int x,int y,Tank.Direction dir,TankClient tc){
    32         this(x, y, dir);
    33         this.tc=tc;
    34     }
    35 
    36     // 炮弹自己的draw方法
    37     public void draw(Graphics g) {
    38         Color c = g.getColor();
    39         g.setColor(Color.BLACK);
    40         // 炮弹形状不要比坦克大,这里设置成10,10;
    41         g.fillOval(x, y, WIDTH, HEIGHT);
    42         g.setColor(c);
    43         move();
    44     }
    45 
    46     public void move() {
    47         switch (dir) {
    48         case L:
    49             x -= XSPEED;
    50             break;
    51         case R:
    52             x += XSPEED;
    53             break;
    54         case U:
    55             y -= YSPEED;
    56             break;
    57         case D:
    58             y += YSPEED;
    59             break;
    60         case LU:
    61             x -= XSPEED;
    62             y -= YSPEED;
    63             break;
    64         case LD:
    65             x -= XSPEED;
    66             y += YSPEED;
    67             break;
    68         case RU:
    69             x += XSPEED;
    70             y -= YSPEED;
    71             break;
    72         case RD:
    73             x += XSPEED;
    74             y += YSPEED;
    75             break;
    76         // 炮弹就没有STOP这个枚举类型的值了
    77         /*
    78          * case STOP: break;
    79          */
    80         }
    81         // 判断炮弹出边界则消亡
    82         // 注意x,y只有正数值,x向右递增,y向下递增
    83         if (x < 0 || y < 0 || x > TankClient.GAME_WIDTH
    84                 || y > TankClient.GAME_HEIGHT) {
    85             live = false;
    86             //炮弹消亡,从集合中删除该元素
    87             tc.missiles.remove(this);
    88         }
    89     }
    90 }
    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     Tank myTank = new Tank(50, 50, this);
     15     //使用容器装炮弹
     16     List<Missile> missiles=new ArrayList<Missile>();
     17 
     18     // 定义虚拟图片,方便后期的一次性显示
     19     Image offScreenImage = null;
     20 
     21     
     22     public void paint(Graphics g) {
     23         g.drawString("missiles count:" + missiles.size(), 10, 50);
     24 
     25         
     26         //遍历结合,发出多发炮弹
     27         for(int i=0;i<missiles.size();i++){
     28             Missile m=missiles.get(i);
     29             m.draw(g);
     30         }
     31         // 不改变前景色
     32         myTank.draw(g);
     33     }
     34 
     35     // 刷新操作
     36     public void update(Graphics g) {
     37         if (offScreenImage == null) {
     38             offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
     39         }
     40         Graphics gOffScreen = offScreenImage.getGraphics();
     41         Color c = gOffScreen.getColor();
     42         gOffScreen.setColor(Color.GREEN);
     43         gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
     44         gOffScreen.setColor(c);
     45         paint(gOffScreen);
     46         g.drawImage(offScreenImage, 0, 0, null);
     47     }
     48 
     49     public void lauchFrame() {
     50 //        this.setLocation(400, 300);
     51         this.setSize(GAME_WIDTH, GAME_HEIGHT);
     52         this.setTitle("TankWar");
     53         this.addWindowListener(new WindowAdapter() {
     54             public void windowClosing(WindowEvent e) {
     55                 System.exit(0);
     56             }
     57         });
     58         this.setResizable(false);
     59         this.setBackground(Color.GREEN);
     60 
     61         this.addKeyListener(new KeyMonitor());
     62 
     63         setVisible(true);
     64 
     65         new Thread(new PaintThread()).start();
     66     }
     67 
     68     public static void main(String[] args) {
     69         TankClient tc = new TankClient();
     70         tc.lauchFrame();
     71     }
     72 
     73     private class PaintThread implements Runnable {
     74 
     75         public void run() {
     76             while (true) {
     77                 repaint();
     78                 try {
     79                     Thread.sleep(50);
     80                 } catch (InterruptedException e) {
     81                     e.printStackTrace();
     82                 }
     83             }
     84         }
     85     }
     86 
     87     // 创建键盘时间监听
     88     private class KeyMonitor extends KeyAdapter {
     89 
     90         // 直接调用myTank自己的方法根据相应的按键信息进行移动
     91         public void keyPressed(KeyEvent e) {
     92             myTank.KeyPressed(e);
     93             // 添加了处理键抬起的事件,可以控制坦克起步以后的状态
     94             // 而不是一直按照一个方向走下去
     95         }
     96 
     97         public void keyReleased(KeyEvent e) {
     98             myTank.keyReleased(e);
     99         }
    100 
    101     }
    102 }
    View Code

    版本1.4.2

    功能:解决坦克可以出开出边界的问题,代码中相较于上一个版本只有Tank类的move方法中做了修改,其他两个类没有进行更改;

     1 if(x<0){
     2             x=0;
     3         }
     4         //因为我们的游戏界面有那个missileCount标签,所以在y轴方向不能用y是否<0进行判断
     5         //否则的话我们的坦克可以从上面出去
     6         if(y<50){
     7             y=50;
     8         }
     9         if(x+Tank.WIDTH>TankClient.GAME_WIDTH){
    10             x=TankClient.GAME_WIDTH-Tank.WIDTH;
    11         }
    12         if(y+Tank.HEIGHT>TankClient.GAME_HEIGHT){
    13             y=TankClient.GAME_HEIGHT-Tank.HEIGHT;
    14         }

    具体代码实现:

    Tank类:

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

    版本1.5

    功能:画一辆敌人的坦克

    步骤:

            1)加入区别敌我的量good:private boolean good;

            2)根据敌我的不同设置不同的颜色;

            3)更新Tank的构造函数,加入good:可能会有其他方法调用了我们的构造方法,我们更新Tank的构造函数会导致原先的调用失败,为方便更改我们需要知道都有那些地方调用了我们的Tank构造方法:

        可以使用下面的方式:选中Tank类名->右键->选择Open Call Hierarchy->在控制台位置就可以看到在那些位置我们需要在更新完Tank构造方法后进行更改;

            4)TankClient中new出敌人的坦克并画出:

    1 //我们这里new我们自己的坦克,用下面的方式
    2 Tank myTank = new Tank(50, 50, true,this);
    3 //新建敌方坦克
    4 Tank enemyTank=new Tank(100,100,false,this);

    具体代码实现:(只有Tank类和TankClient类做了更改)

    Tank:

      1 import java.awt.*;
      2 import java.awt.event.*;
      3 
      4 public class Tank {
      5     // 方便后期更改
      6     public static final int XSPEED = 5;
      7     public static final int YSPEED = 5;
      8     // 将坦克的高度和宽度设置为常量
      9     public static final int WIDTH = 30;
     10     public static final int HEIGHT = 30;
     11     TankClient tc = null;
     12     // 区别是我方坦克还是地方坦克,方便据此进行不同的设置
     13     private boolean good;
     14 
     15     private int x;
     16     private int y;
     17     // 添加记录按键状态的布尔量
     18     private boolean bL = false;
     19     private boolean bR = false;
     20     private boolean bU = false;
     21     private boolean bD = false;
     22 
     23     // 添加代表方向的量(使用枚举)
     24     enum Direction {
     25         L, R, U, D, LU, LD, RU, RD, STOP
     26     };
     27 
     28     private Direction dir = Direction.STOP;
     29 
     30     // 定义炮筒的方向,我们想办法将炮筒的方法调整成和坦克移动方向一致;
     31     // 我们这里会用一条直线来表示炮筒:模拟炮筒
     32     // 我们要根据炮筒的方向画直线表示炮筒
     33     Direction ptDir = Direction.D;
     34 
     35     //更改构造函数
     36     public Tank(int x, int y,boolean good) {
     37         this.x = x;
     38         this.y = y;
     39         this.good=good;
     40     }
     41 
     42     //这个位置的构造函数也相应进行了更改
     43     public Tank(int x, int y,boolean good,TankClient tc) {
     44         // 调用那个有两个参数的构造方法
     45         this(x, y,good);
     46         // 在这个位置初始化tc
     47         this.tc = tc;
     48     }
     49 
     50     // Tank对象的draw方法
     51     public void draw(Graphics g) {
     52         Color c = g.getColor();
     53         if(good){    
     54         g.setColor(Color.RED);
     55         }
     56         else {
     57             g.setColor(Color.PINK);
     58         }
     59         g.fillOval(x, y, WIDTH, HEIGHT);
     60         g.setColor(c);
     61         // 根据炮筒的方向画直线来表示我们坦克的炮筒
     62         switch (ptDir) {
     63         case L:
     64             // 画直线:四个参数分别代表:坦克中心点的坐标 直线的另一头的的坐标
     65             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y
     66                     + Tank.HEIGHT / 2);
     67             break;
     68         case R:
     69             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
     70                     y + Tank.HEIGHT / 2);
     71 
     72             break;
     73         case U:
     74             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH
     75                     / 2, y);
     76 
     77             break;
     78         case D:
     79             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH
     80                     / 2, y + Tank.HEIGHT);
     81 
     82             break;
     83         case LU:
     84             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y);
     85             break;
     86         case LD:
     87             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y
     88                     + Tank.HEIGHT);
     89 
     90             break;
     91         case RU:
     92             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
     93                     y);
     94 
     95             break;
     96         case RD:
     97             g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH,
     98                     y + Tank.HEIGHT);
     99 
    100             break;
    101         /*
    102          * case STOP: break;
    103          */
    104         }
    105         move();
    106     }
    107 
    108     public void move() {
    109         switch (dir) {
    110         case L:
    111             x -= XSPEED;
    112             break;
    113         case R:
    114             x += XSPEED;
    115             break;
    116         case U:
    117             y -= YSPEED;
    118             break;
    119         case D:
    120             y += YSPEED;
    121             break;
    122         case LU:
    123             x -= XSPEED;
    124             y -= YSPEED;
    125             break;
    126         case LD:
    127             x -= XSPEED;
    128             y += YSPEED;
    129             break;
    130         case RU:
    131             x += XSPEED;
    132             y -= YSPEED;
    133             break;
    134         case RD:
    135             x += XSPEED;
    136             y += YSPEED;
    137             break;
    138 
    139         case STOP:
    140             break;
    141         }
    142         // 如果坦克不是停着的,则将炮筒调整至和坦克移动的方向相同
    143         if (this.dir != Direction.STOP) {
    144             this.ptDir = this.dir;
    145         }
    146         if (x < 0) {
    147             x = 0;
    148         }
    149         // 因为我们的游戏界面有那个missileCount标签,所以在y轴方向不能用y是否<0进行判断
    150         // 否则的话我们的坦克可以从上面出去
    151         if (y < 50) {
    152             y = 50;
    153         }
    154         if (x + Tank.WIDTH > TankClient.GAME_WIDTH) {
    155             x = TankClient.GAME_WIDTH - Tank.WIDTH;
    156         }
    157         if (y + Tank.HEIGHT > TankClient.GAME_HEIGHT) {
    158             y = TankClient.GAME_HEIGHT - Tank.HEIGHT;
    159         }
    160     }
    161 
    162     public void locateDirection() {
    163         if (bL && !bU && !bR && !bD)
    164             dir = Direction.L;
    165         else if (bL && bU && !bR && !bD)
    166             dir = Direction.LU;
    167         else if (!bL && bU && !bR && !bD)
    168             dir = Direction.U;
    169         else if (!bL && bU && bR && !bD)
    170             dir = Direction.RU;
    171         else if (!bL && !bU && bR && !bD)
    172             dir = Direction.R;
    173         else if (!bL && !bU && bR && bD)
    174             dir = Direction.RD;
    175         else if (!bL && !bU && !bR && bD)
    176             dir = Direction.D;
    177         else if (bL && !bU && !bR && bD)
    178             dir = Direction.LD;
    179         else if (!bL && !bU && !bR && !bD)
    180             dir = Direction.STOP;
    181 
    182     }
    183 
    184     // 坦克自己向哪个方向移动,它自己最清楚;
    185     public void KeyPressed(KeyEvent e) {
    186         // 获得所按下的键所对应的虚拟码:
    187         // Returns the integer keyCode associated with the key in this event
    188         int key = e.getKeyCode();
    189         // 判断不同的按键,指挥坦克的运动方向
    190         switch (key) {
    191         case KeyEvent.VK_LEFT:
    192             bL = true;
    193             break;
    194         case KeyEvent.VK_UP:
    195             bU = true;
    196             break;
    197         case KeyEvent.VK_RIGHT:
    198             bR = true;
    199             break;
    200         case KeyEvent.VK_DOWN:
    201             bD = true;
    202             break;
    203         }
    204         locateDirection();
    205     }
    206 
    207     public void keyReleased(KeyEvent e) {
    208         int key = e.getKeyCode();
    209         // 判断不同的按键,指挥坦克的运动方向
    210         // 哪个键按下了,就把对应方向的布尔类型置为false
    211         switch (key) {
    212         // 为了防止一直按着Ctrl键的时候,炮弹太过于密集
    213         // 因此我们定义在Ctrl键抬起的时候才发炮弹
    214         // 这样炮弹不至于太过密集
    215         case KeyEvent.VK_CONTROL:
    216             fire();
    217             break;
    218         case KeyEvent.VK_LEFT:
    219             bL = false;
    220             break;
    221         case KeyEvent.VK_UP:
    222             bU = false;
    223             break;
    224         case KeyEvent.VK_RIGHT:
    225             bR = false;
    226             break;
    227         case KeyEvent.VK_DOWN:
    228             bD = false;
    229             break;
    230         }
    231         // 重新定位一下
    232         locateDirection();
    233     }
    234 
    235     public Missile fire() {
    236         // 计算子弹的位置,使得子弹从坦克的中间发出来
    237         int x = this.x + Tank.WIDTH / 2 - Missile.WIDTH / 2;
    238         int y = this.y + Tank.HEIGHT / 2 - Missile.HEIGHT / 2;
    239         // 这个时候我们就根据炮筒的方向来发炮弹了,之前是根据坦克的方向来发炮弹
    240         Missile m = new Missile(x, y, ptDir, tc);
    241         // 将新产生的炮弹放置到List容器中
    242         tc.missiles.add(m);
    243         return m;
    244     }
    245 }
    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     List<Missile> missiles=new ArrayList<Missile>();
     22 
     23     // 定义虚拟图片,方便后期的一次性显示
     24     Image offScreenImage = null;
     25 
     26     
     27     public void paint(Graphics g) {
     28         g.drawString("missiles count:" + missiles.size(), 10, 50);
     29 
     30         
     31         //遍历结合,发出多发炮弹
     32         for(int i=0;i<missiles.size();i++){
     33             Missile m=missiles.get(i);
     34             m.draw(g);
     35         }
     36         // 不改变前景色
     37         myTank.draw(g);
     38         //敌方坦克调用draw方法
     39         enemyTank.draw(g);
     40     }
     41 
     42     // 刷新操作
     43     public void update(Graphics g) {
     44         if (offScreenImage == null) {
     45             offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
     46         }
     47         Graphics gOffScreen = offScreenImage.getGraphics();
     48         Color c = gOffScreen.getColor();
     49         gOffScreen.setColor(Color.GREEN);
     50         gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
     51         gOffScreen.setColor(c);
     52         paint(gOffScreen);
     53         g.drawImage(offScreenImage, 0, 0, null);
     54     }
     55 
     56     public void lauchFrame() {
     57 //        this.setLocation(400, 300);
     58         this.setSize(GAME_WIDTH, GAME_HEIGHT);
     59         this.setTitle("TankWar");
     60         this.addWindowListener(new WindowAdapter() {
     61             public void windowClosing(WindowEvent e) {
     62                 System.exit(0);
     63             }
     64         });
     65         this.setResizable(false);
     66         this.setBackground(Color.GREEN);
     67 
     68         this.addKeyListener(new KeyMonitor());
     69 
     70         setVisible(true);
     71 
     72         new Thread(new PaintThread()).start();
     73     }
     74 
     75     public static void main(String[] args) {
     76         TankClient tc = new TankClient();
     77         tc.lauchFrame();
     78     }
     79 
     80     private class PaintThread implements Runnable {
     81 
     82         public void run() {
     83             while (true) {
     84                 repaint();
     85                 try {
     86                     Thread.sleep(50);
     87                 } catch (InterruptedException e) {
     88                     e.printStackTrace();
     89                 }
     90             }
     91         }
     92     }
     93 
     94     // 创建键盘时间监听
     95     private class KeyMonitor extends KeyAdapter {
     96 
     97         // 直接调用myTank自己的方法根据相应的按键信息进行移动
     98         public void keyPressed(KeyEvent e) {
     99             myTank.KeyPressed(e);
    100             // 添加了处理键抬起的事件,可以控制坦克起步以后的状态
    101             // 而不是一直按照一个方向走下去
    102         }
    103 
    104         public void keyReleased(KeyEvent e) {
    105             myTank.keyReleased(e);
    106         }
    107 
    108     }
    109 }
    View Code

    版本1.6

    功能: 将敌人坦克击毙

    分析: 一颗子弹击中敌人坦克

    步骤:

            1)Missle中加入hitTank(Tank)方法,返回布尔类型

            2)碰撞检测的辅助类Rectangle

            3为Tank和Missle都加入getRect方法

            4)当击中敌人坦克时,坦克被打死,子弹也死去

            5)增加控制Tank生死的量live

            6)如果死去就不画了

    注意: 不要照抄代码,沿着思路往里加入代码

    具体代码实现:

    Tank:

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

    未完待续。。。。。。

  • 相关阅读:
    C/C++中volatile关键字详解(转)
    Spring中 @Autowired标签与 @Resource标签 的区别(转)
    [转]各种互斥量的总结
    nginx限制ip访问(转)
    HDU 4833 Best Financing (DP)
    HDU 4832 Chess (DP)
    HDU 4831 Scenic Popularity
    POJ 2155 Matrix (二维线段树)
    POJ 2155 Matrix (二维树状数组)
    HDU 4819 Mosaic (二维线段树)
  • 原文地址:https://www.cnblogs.com/ysw-go/p/5509713.html
Copyright © 2011-2022 走看看