韩顺平Java-第十八章:坦克大战2

一 线程 - 应用到坦克大战

1 坦克大战3.0版本
(1)增强功能:

​ 用户按下J键,我方坦克发射一颗子弹

(2)思路:

在这里插入图片描述

(3)实现代码:

① 首先要创建shot类,实现Runnable接口,在run()方法中实现发射子弹的过程,注意碰壁的效果。

public class Shot implements Runnable {
    int x; //子弹x坐标
    int y; //子弹y坐标
    int direct = 0; //子弹方向
    int speed = 2; //子弹的速度
    boolean isLive = true; //子弹是否还存活

    //构造器
    public Shot(int x, int y, int direct) {
        this.x = x;
        this.y = y;
        this.direct = direct;
    }
     
    @Override
    public void run() {//射击
        while (true) {
     
            //休眠 50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //根据方向来改变x,y坐标
            switch (direct) {
                case 0://上
                    y -= speed;
                    break;
                case 1://右
                    x += speed;
                    break;
                case 2://下
                    y += speed;
                    break;
                case 3://左
                    x -= speed;
                    break;
            }
            //测试,这里我们输出x,y的坐标
            System.out.println("子弹 x=" + x + " y=" + y);
            //当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)
            if (!(x >= 0 && x <= 1300 && y >= 0 && y <= 750)) {
                System.out.println("子弹线程退出");
                isLive = false;
                break;
            }
        }
    }
}

② 在hero类中创建一个shot对象,并根据方向为其赋初值,最后创建,启动线程,发射子弹。

public class Hero extends Tank {
    //定义一个Shot对象, 表示一个射击(线程)
    Shot shot = null;

    public Hero(int x, int y) {
        super(x, y);
    }
     
    //射击
    public void shotEnemyTank() {
        //创建 Shot 对象, 根据当前Hero对象的位置和方向来创建Shot
        switch (getDirect()) {//得到Hero对象方向
            case 0: //向上
                shot = new Shot(getX() + 20, getY(), 0);
                break;
            case 1: //向右
                shot = new Shot(getX() + 60, getY() + 20, 1);
                break;
            case 2: //向下
                shot = new Shot(getX() + 20, getY() + 60, 2);
                break;
            case 3: //向左
                shot = new Shot(getX(), getY() + 20, 3);
                break;
        }
        //启动我们的Shot线程
        new Thread(shot).start();
    }
}

③ 在MyPanel类中,在keyPressed方法中添加摁J键调用hero中创建子弹并调用线程发射的方法,并添加绘制子弹的代码(注意判断子弹是否为空和子弹是否碰壁),并且要求不断重绘来显示子弹(需要使得MyPanel实现Runable类,在该类中不断重绘)。

//为了监听 键盘事件, 实现KeyListener
//为了让Panel 不停的重绘子弹,需要将 MyPanel 实现Runnable ,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener,Runnable {
    //定义我的坦克
    Hero hero = null;
    //定义敌人坦克,放入到Vector
    Vector<EnemyTank> enemyTanks = new Vector<>();
    int enemyTankSize = 3;

    public MyPanel() {
        hero = new Hero(100, 100);//初始化自己坦克
        //初始化敌人坦克
        for (int i = 0; i < enemyTankSize; i++) {
            //创建一个敌人的坦克
            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
            //设置方向
            enemyTank.setDirect(2);
            //加入
            enemyTanks.add(enemyTank);
        }
    }
     
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1300, 750);//填充矩形,默认黑色
     
        //画出自己坦克-封装方法
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
     
        //画出hero射击的子弹
        if(hero.shot != null && hero.shot.isLive == true) {
            System.out.println("子弹被绘制...");
            g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);
        }
     
        //画出敌人的坦克, 遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
        }
    }
     
    //编写方法,画出坦克
     
    /**
     * @param x      坦克的左上角x坐标
     * @param y      坦克的左上角y坐标
     * @param g      画笔
     * @param direct 坦克方向(上下左右)
     * @param type   坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int direct, int type) {
     
        //根据不同类型坦克,设置不同颜色
        switch (type) {
            case 0: //敌人的坦克
                g.setColor(Color.cyan);
                break;
            case 1: //我的坦克
                g.setColor(Color.yellow);
                break;
        }
     
        //根据坦克方向,来绘制对应形状坦克
        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )
        //
        switch (direct) {
            case 0: //表示向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒
                break;
            case 1: //表示向右
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒
                break;
            case 2: //表示向下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒
                break;
            case 3: //表示向左
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒
                break;
            default:
                System.out.println("暂时没有处理");
        }
     
    }
     
    @Override
    public void keyTyped(KeyEvent e) {
     
    }
     
    //处理wdsa 键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println(e.getKeyCode());
        if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键
            //改变坦克的方向
            hero.setDirect(0);//
            //修改坦克的坐标 y -= 1
            hero.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//D键, 向右
            hero.setDirect(1);
            hero.moveRight();
     
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键
            hero.setDirect(2);
            hero.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键
            hero.setDirect(3);
            hero.moveLeft();
        }
     
        //如果用户按下的是J,就发射
        if(e.getKeyCode() == KeyEvent.VK_J) {
            System.out.println("用户按下了J, 开始射击.");
            hero.shotEnemyTank();
        }
        //让面板重绘
        this.repaint();
     
    }
     
    @Override
    public void keyReleased(KeyEvent e) {
     
    }
     
    @Override
    public void run() { //每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹就移动
     
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.repaint();
        }
     
    }

}
2 坦克大战4.0版本
(1)增强功能:

① 让敌人的坦克也能够发射子弹(可以有多颗子弹);

② 当我方坦克击中敌人坦克时候,敌人的坦克就消失,如果能做出爆炸效果更好;

③ 让敌人的坦克也可以自由随机的上下左右移动;

④ 控制我方的坦克和敌人的坦克在规定的范围移动。

(2)思路:

在这里插入图片描述

(3)实现代码:

① 需要在敌人坦克EnemyTank类中添加一个Vector集合来存放子弹线程(之所以用Vector来存放子弹线程是因为它是线程安全的,不会出现多线程安全问题)

//EnemyTank类
public class EnemyTank extends Tank {
    Vector<Shot> shots = new Vector<>();
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}

在MyPanel的构造器中初始化子弹对象,并将子弹对象添加到敌人坦克的子弹集合当中,启动线程。在paint方法中,将每个敌人坦克对象的子弹集合绘制出来,注意if条件

//为了监听 键盘事件, 实现KeyListener
//为了让Panel 不停的重绘子弹,需要将 MyPanel 实现Runnable ,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener,Runnable {
    //定义我的坦克
    Hero hero = null;
    //定义敌人坦克,放入到Vector
    Vector<EnemyTank> enemyTanks = new Vector<>();
    int enemyTankSize = 3;

    public MyPanel() {
        hero = new Hero(100, 100);//初始化自己坦克
        //初始化敌人坦克
        for (int i = 0; i < enemyTankSize; i++) {
            //创建一个敌人的坦克
            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
            //设置方向
            enemyTank.setDirect(2);
			//加入
            //新建子弹对象
            Shot shot = new Shot(enemyTank.getX()+20,(enemyTank.getY()+60),1);
            //将子弹对象加入到敌人坦克的子弹集合
            enemyTank.shots.add(shot);
            //新建并启动线程
            Thread thread = new Thread(shot);
            thread.start();
            enemyTanks.add(enemyTank);
        }
    }
     
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1300, 750);//填充矩形,默认黑色
     
        //画出自己坦克-封装方法
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
     
        //画出hero射击的子弹
        if(hero.shot != null && hero.shot.isLive == true) {
            System.out.println("子弹被绘制...");
            g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);
        }
     
        //画出敌人的坦克, 遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
            for (int j = 0; j < enemyTank.shots.size(); j++) {
                Shot shot = enemyTank.shots.get(j);
                if (shot.isLive != false) {
                    g.drawRect(shot.x, shot.y, 1, 1);
                }else {
                    enemyTank.shots.remove(shot);
                }
            }
        }

 

    }
     
    //编写方法,画出坦克
     
    /**
     * @param x      坦克的左上角x坐标
     * @param y      坦克的左上角y坐标
     * @param g      画笔
     * @param direct 坦克方向(上下左右)
     * @param type   坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int direct, int type) {
     
        //根据不同类型坦克,设置不同颜色
        switch (type) {
            case 0: //敌人的坦克
                g.setColor(Color.cyan);
                break;
            case 1: //我的坦克
                g.setColor(Color.yellow);
                break;
        }
     
        //根据坦克方向,来绘制对应形状坦克
        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )
        //
        switch (direct) {
            case 0: //表示向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒
                break;
            case 1: //表示向右
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒
                break;
            case 2: //表示向下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒
                break;
            case 3: //表示向左
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒
                break;
            default:
                System.out.println("暂时没有处理");
        }
     
    }
     
    @Override
    public void keyTyped(KeyEvent e) {
     
    }
     
    //处理wdsa 键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println(e.getKeyCode());
        if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键
            //改变坦克的方向
            hero.setDirect(0);//
            //修改坦克的坐标 y -= 1
            hero.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//D键, 向右
            hero.setDirect(1);
            hero.moveRight();
     
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键
            hero.setDirect(2);
            hero.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键
            hero.setDirect(3);
            hero.moveLeft();
        }
     
        //如果用户按下的是J,就发射
        if(e.getKeyCode() == KeyEvent.VK_J) {
            System.out.println("用户按下了J, 开始射击.");
            hero.shotEnemyTank();
        }
        //让面板重绘
        this.repaint();
     
    }
     
    @Override
    public void keyReleased(KeyEvent e) {
     
    }
     
    @Override
    public void run() { //每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹就移动
     
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.repaint();
        }
     
    }

}

② 在敌人坦克中添加Boolean的isLive属性,初始化为true;

public class EnemyTank extends Tank {
    Vector<Shot> shots  = new Vector<>();
    boolean isLive = true;
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}

在MyPanel类中添加一个判断我方坦克子弹是否击中敌人坦克,如果击中,将敌人坦克的isLive和我方坦克的子弹isLive设置为false,这样就不会再绘制了

public void shotEnemyTank(Shot shot,EnemyTank enemyTank){//射击敌人坦克
        if((enemyTank.getDirect() == 0)  || (enemyTank.getDirect() == 2)){//上和下以及左和右的坦克位置一样
            if ((shot.x > enemyTank.getX())
                    && (shot.x < (enemyTank.getX() + 40))
                    &&(shot.y > enemyTank.getY())
                    && (shot.y < (enemyTank.getY() + 60)))
            {
                System.out.println("一辆敌人坦克被消灭");
                enemyTank.isLive = false;
                bullet.isLive = false;
            }
        }else if ((enemyTank.getDirect() == 1) || (enemyTank.getDirect() == 3)){
            if ((shot.x > enemyTank.getX())
                    && (shot.x < (enemyTank.getX() + 60))
                    &&(shot.y > enemyTank.getY())
                    && (shot.y < (enemyTank.getY() + 40)))
            {
                System.out.println("一辆敌人坦克被消灭");
                enemyTank.isLive = false;
                shot.isLive = false;
            }
        }
    }


在MyPanel的run方法中添加判断使用该方法的判断

@Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (hero.shot != null && hero.shot.isLive){
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    shotEnemyTank(hero.bullet, enemyTank);
                }
            }
            this.repaint();
        }
    }

在敌人坦克的绘制循环代码中添加if条件来判断是否要绘制该坦克和子弹。

for (int i = 0; i < enemyTanks.size(); i++) {
            EnemyTank enemyTank = enemyTanks.get(i);
            if (enemyTank.isLive == true) {//当敌人坦克是活的
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);
                for (int j = 0; j < enemyTank.bullets.size(); j++) {
                    Shot shot= enemyTank.bullets.get(j);
                    if (shot.isLive != false) {
                        g.drawRect(bullet.x, bullet.y, 1, 1);
                    } else {
                        enemyTank.shot.remove(bullet);
                    }
                }
            }
        }

创建一个Bomb类,用于爆炸的显示

public class Bomb {
    int x, y; //炸弹的坐标
    int life = 18; //炸弹的生命周期
    boolean isLive = true; //是否还存活

    public Bomb(int x, int y) {
        this.x = x;
        this.y = y;
    }
     
    //减少生命值
    public void lifeDown() { //配合出现图片的爆炸效果
        if(life > 0) {
            life--;
        } else {
            isLive = false;
        }
    }
}

在MyPanel中定义

 //定义一个Vector ,用于存放炸弹
    //说明,当子弹击中坦克时,加入一个Bomb对象到bombs
    Vector<Bomb> bombs = new Vector<>();
 //定义三张炸弹图片,用于显示爆炸效果
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

在构造器中初始化image对象

//初始化图片对象
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));
image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));

在shotEnemyTank方法中在确定我方子弹击中敌方坦克后,新建一个bomb,并将该对象加入到bombs当中,并将该方法设置为非静态的。

public void shotEnemyTank(Bullet bullet,EnemyTank enemyTank){//射击敌人坦克
        if((enemyTank.getDirect() == 0)  || (enemyTank.getDirect() == 1)){//上和下以及左和右的坦克位置一样
            if ((bullet.x > enemyTank.getX())
                    && (bullet.x < (enemyTank.getX() + 40))
                    &&(bullet.y > enemyTank.getY())
                    && (bullet.y < (enemyTank.getY() + 60)))
            {
                System.out.println("一辆敌人坦克被消灭");
                enemyTank.isLive = false;
                bullet.isLive = false;
                Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                bombs.add(bomb);
            }
        }else if ((enemyTank.getDirect() == 2) || (enemyTank.getDirect() == 3)){
            if ((bullet.x > enemyTank.getX())
                    && (bullet.x < (enemyTank.getX() + 60))
                    &&(bullet.y > enemyTank.getY())
                    && (bullet.y < (enemyTank.getY() + 40)))
            {
                System.out.println("一辆敌人坦克被消灭");
                enemyTank.isLive = false;
                bullet.isLive = false;
                Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                bombs.add(bomb);
            }
        }
    }

在paint方法中添加绘制的判断

//如果bombs 集合中有对象,就画出
        for (int i = 0; i < bombs.size(); i++) {
            //取出炸弹
            Bomb bomb = bombs.get(i);
            //根据当前这个bomb对象的life值去画出对应的图片
            if (bomb.life > 12) {
                g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);
            } else if (bomb.life > 6) {
                g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);
            } else {
                g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);
            }
            //让这个炸弹的生命值减少
            bomb.lifeDown();
            //如果bomb life 为0, 就从bombs 的集合中删除
            if (bomb.life == 0) {
                bombs.remove(bomb);
            }
		}

③ 让敌人坦克可以换方向并且动起来。

在这里插入图片描述

@Override
public void run() {
       while (true) {
            switch (getDirect()) {
                case 0:
                    for (int i = 0; i < 30; i++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        moveUp();
                    }
                    break;
                case 1:
                    for (int i = 0; i < 30; i++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        moveRight();
                    }
                    break;
                case 2:
                    for (int i = 0; i < 30; i++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        moveDown();
                    }
                    break;
                case 3:
                    for (int i = 0; i < 30; i++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        moveLeft();
                    }
                    break;
            }
            setDirect((int) (Math.random() * 4));
            if (!isLive) {
                break;
            }
        }
   }

在MyPanel中定义敌人坦克的时候启动线程。

new Thread(enemyTank).start();

④ 在Tank类中对移动加条件。

//上右下左移动方法
    public void moveUp(){
        if (y > 0) {
            y -= speed;
        }
    }

    public void moveLeft(){
        if (x > 0) {
            x -= speed;
        }
    }
    public void moveRight(){
        if (x + 60 < 1300) {
            x += speed;
        }
    }
    public void moveDown(){
        if (y + 60 < 750) {
            y += speed;
        }
    }
3 坦克大战5.0版本
(1)增强功能:

① 我方坦克在发射的子弹消亡后,才能发射新的子弹;【扩展,发射多颗子弹怎么办】

② 让敌人坦克发射的子弹消亡后,可以再发射子弹;

③ 当敌人的坦克击中我方坦克时,我方坦克消亡,并出现爆炸效果。

(2)思路:

在这里插入图片描述

(3)实现代码:

① 我防坦克在发射的子弹消亡后,才能发射新的子弹

MyPanel中加入 如下的判断即可。

//控制J发射子弹
        if (e.getKeyCode() == KeyEvent.VK_J) {
            if (hero.shot == null || hero.shot.getIsLive() == false) {
                hero.shotEnemyTank();
            }
        }

​ 发射多颗子弹【最多5颗子弹】

在Hero类中 添加子弹集合Shot,并且将新建的子弹对象添加到该集合中

Vector<Shot> shots = new Vector<>();
//在ShotEnemyTank()方法后
shots.add(shot);

​ 在绘制子弹时候,要遍历shots集合,并且判断如果子弹已经消亡,要将它移除。

 for (int i = 0; i < hero.shots.size(); i++) {
	Shot shot = hero.shots.get(i);
     if (shot != null && shot.getIsLive() == true) {
     	g.drawRect(shot.getX(), shot.getY(), 1, 1);
      } else {//子弹无效后需要将其移除
        hero.shots.remove(shot);
      }
 }

​ 在MyPanel类的run()方法中,判断子弹是否击中敌人坦克时候,外层要使用shots集合的for循环。

for (int i = 0; i < hero.shots.size(); i++) {
    Shot shot = hero.shots.get(i);
        if (shot != null && shot.getIsLive()) {
            for (int j = 0; j < enemyTanks.size(); j++) {
                EnemyTank enemyTank = enemyTanks.get(j);
                shotEnemyTank(shot, enemyTank);
            }
        }
}

​ 在摁J键控制子弹代码当中,修改如下。

//控制J发射子弹
        if (e.getKeyCode() == KeyEvent.VK_J) {
            if (hero.shots.size() < 5) {
                 hero.ShotEnemyTank();
            }
        }

② 在EnemyTank类的run()方法中加入如下的代码,如果敌人坦克还存活并且其子弹集合的子弹数量小于1,新建一个子弹对象加入到该子弹集合当中,并新建启动线程。

	if(isLive && shots.size() < 1){
            Shot shot= null;
            switch (getDirect()){
                    case 0://上
                        shot = new Shot((getX()+20),getY(),0);
                        break;
                    case 1://右
                        shot = new Shot((getX()+60),(getY()+20),1);
                        break;
                    case 2://下
                        shot = new Shot((getX()+20),(getY()+60),2);
                        break;
                    case 3://左
                        shot = new Shot((getX()),(getY()+20),3);
                        break;
            }
            shots.add(shot);
            Thread thread = new Thread(shot);
            thread.start();
	}

③ 首先将isLive属性提到父类Tank里面,将MyPanel中的hitEnemyTank代码改为hitTank,然后MyPanel类中添加hitHeroTank()方法,在MyPanel类的run()方法当中调用该方法即可。

//编写方法,判断敌人坦克是否击中我的坦克
//编写方法,判断敌人坦克是否击中我的坦克
    public void hitHeroTank() {
        //遍历所有的敌人坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出敌人坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //遍历enemyTank 对象的所有子弹
            for (int j = 0; j < enemyTank.shots.size(); j++) {
                //取出子弹
                Shot shot = enemyTank.shots.get(j);
                //判断 shot 是否击中我的坦克
                if (hero.isLive && shot.getIsLive()) {
                    hitTank(shot , hero);
                }
            }
        }
    }

在绘制子弹时要进行条件的判断。

if (shot != null && shot.getIsLive() == true) {
	g.drawRect(shot.getX(), shot.getY(), 1, 1);
}
知识点
1 初始化并创建图片对象
Image image1 = new Image();
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
//照片放在根目录
//Panel为本类名

nk()方法,在MyPanel类的run()方法当中调用该方法即可。

//编写方法,判断敌人坦克是否击中我的坦克
public void hitHeroTank() {
    //遍历所有的敌人坦克
    for (int i = 0; i < enemyTanks.size(); i++) {
        //取出敌人坦克
        EnemyTank enemyTank = enemyTanks.get(i);
        //遍历enemyTank 对象的所有子弹
        for (int j = 0; j < enemyTank.bullets.size(); j++) {
            //取出子弹
            Bullet bullet = enemyTank.bullets.get(j);
            //判断 shot 是否击中我的坦克
            if (hero.isLive && bullet.isLive) {
                hitTank(bullet , hero);
            }
        }
    }
}

在绘制我方坦克时候要进行条件的判断。

if (hero.bullet != null && hero.bullet.isLive == true) {
            g.draw3DRect(hero.bullet.x, hero.bullet.y, 1, 1, false);

}
  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值