B站韩顺平java学习笔记(十七)-- 坦克大战【2】章节

目录

一  线程 - 应用到坦克大战

1  坦克大战3.0版本

(1)增强功能

(2)思路

(3)实现代码

2  坦克大战4.0版本

(1)增强功能

(2)思路

(3)实现代码

3  坦克大战5.0版本

(1)增强功能

(2)思路

(3)实现代码

知识点

1  初始化并创建图片对象


一  线程 - 应用到坦克大战

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 <= 1000 && 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, 1000, 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);
            //加入
            //新建子弹对象    
            Bullet bullet = new Bullet((enemyTank.getX()+20),(enemyTank.getY()+60),1);
            //将子弹对象加入到敌人坦克的子弹集合
            enemyTank.bullets.add(bullet);
            //新建并启动线程
            Thread thread = new Thread(bullet);
            thread.start();
            enemyTanks.add(enemyTank);
        }
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 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<Bullet> bullets = new Vector<>();
    boolean isLive = true;
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}

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

public static 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;
            }
        }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;
            }
        }
    }

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

@Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (hero.bullet != null && hero.bullet.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++) {
                    Bullet bullet= enemyTank.bullets.get(j);
                    if (bullet.isLive != false) {
                        g.drawRect(bullet.x, bullet.y, 1, 1);
                    } else {
                        enemyTank.bullets.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();
                        }
                        upMove();
                    }
                    break;
                case 1:
                    for (int i = 0; i < 30; i++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        downMove();
                    }
                    break;
                case 2:
                    for (int i = 0; i < 30; i++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        leftMove();
                    }
                    break;
                case 3:
                    for (int i = 0; i < 30; i++) {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        rightMove();
                    }
                    break;
            }
            setDirect((int) (Math.random() * 4));
            if (!isLive) {
                break;
            }
        }

    }

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

new Thread(enemyTank).start();

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

public void upMove(){
        if (y > 0) {
            y -= speed;
        }
    }
    public void downMove(){
        if (y + 60 < 600) {
            y += speed;
        }
    }
    public void leftMove(){
        if (x > 0) {
            x -= speed;
        }
    }
    public void rightMove(){
        if (x + 60 < 600) {
            x += speed;
        }
    }

3  坦克大战5.0版本

(1)增强功能:

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

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

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

(2)思路:

 

(3)实现代码:

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

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

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

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

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

Vector<Bullet> bullets = new Vector<>();
//在ShotEnemyTank()方法后
bullets.add(bullet);

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

for (int i = 0; i < hero.bullets.size(); i++) {
            Bullet bullet = hero.bullets.get(i);
            if (bullet != null && bullet.isLive == true) {
                System.out.println("子弹被绘制");
                g.drawRect(bullet.x,bullet.y,1,1);
            }else {//子弹无效后需要将其移除
                hero.bullets.remove(bullet);
            }
        }

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

for (int i = 0; i < hero.bullets.size(); i++) {
    Bullet bullet = hero.bullets.get(i);
        if (bullet != null && bullet.isLive) {
            for (int j = 0; j < enemyTanks.size(); j++) {
                EnemyTank enemyTank = enemyTanks.get(j);
                shotEnemyTank(bullet, enemyTank);
            }
        }
}

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

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

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

if(isLive && bullets.size() < 1){
                Bullet bullet= null;
                switch (getDirect()){
                    case 0://向上
                        bullet = new Bullet((getX()+20),getY(),0);
                        break;
                    case 1://下
                        bullet = new Bullet((getX()+20),(getY()+60),1);
                        break;
                    case 2://左
                        bullet = new Bullet((getX()-10),(getY()+30),2);
                        break;
                    case 3://右
                        bullet = new Bullet((getX()+50),(getY()+30),3);
                        break;
                }
                bullets.add(bullet);
                Thread thread = new Thread(bullet);
                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.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);

}

知识点

1  初始化并创建图片对象

Image image1 = new Image();
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
//照片放在根目录
//Panel为本类名

人狗大战是一款经典的游戏,这个游戏要求玩家控制一个战士与一只狗进行战斗。以下是一个简单的Java代码实现: ``` public class Main { public static void main(String[] args) { // 创建一个战士对象 Warrior warrior = new Warrior("战士", 100, 20); // 创建一个狗对象 Dog dog = new Dog("狗", 50, 10); // 开始战斗直到一方死亡 while (warrior.isAlive() && dog.isAlive()) { // 战士攻击狗 warrior.attack(dog); // 判断狗是否死亡 if(!dog.isAlive()) { System.out.println("战士胜利!"); break; } // 狗攻击战士 dog.attack(warrior); // 判断战士是否死亡 if(!warrior.isAlive()) { System.out.println("狗胜利!"); break; } } } } // 定义战士类 class Warrior { private String name; private int health; private int damage; public Warrior(String name, int health, int damage) { this.name = name; this.health = health; this.damage = damage; } public boolean isAlive() { return health > 0; } public void attack(Dog dog) { dog.takeDamage(damage); System.out.println(name + "攻击了" + dog.getName() + ",造成了" + damage + "点伤害!"); } public void takeDamage(int damage) { health -= damage; } } // 定义狗类 class Dog { private String name; private int health; private int damage; public Dog(String name, int health, int damage) { this.name = name; this.health = health; this.damage = damage; } public String getName() { return name; } public boolean isAlive() { return health > 0; } public void attack(Warrior warrior) { warrior.takeDamage(damage); System.out.println(name + "攻击了" + warrior.getName() + ",造成了" + damage + "点伤害!"); } public void takeDamage(int damage) { health -= damage; } } ``` 以上代码实现了一个简单的人狗大战游戏,战士和狗分别具有自己的属性和方法,包括攻击、受伤和判断是否存活等。在主方法中,创建了一个战士对象和一个狗对象,然后通过循环进行连续攻击并判断胜负。当一方死亡时,输出相应的胜利信息。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值