Java Note 034-Tank Battle【2】

Table of contents

Tank battle【2】

Thread - Applied to Tank Wars

Tank Battle 0.3

Idea analysis:

Code:

Tank Battle 0.4

add feature

Special Note

Idea analysis:

Code:

Tank Battle 0.5

add feature

Idea analysis:

Code:


Tank battle【2】

Thread - Applied to Tank Wars

Tank Battle 0.3

Add the following function on the basis of the tank battle game (version 0.2): when the player presses the j key, a bullet will be fired

Idea analysis:

  1. When a bullet is fired, it is equivalent to a thread started
  2. Hero is an object with bullets. When J is pressed, a launch behavior (thread) is started, so that the bullets move continuously to form a shooting effect.
  3. MyPanel needs to be redrawn continuously to have this effect
  4. When the bullet moves to the border of the panel, it should be destroyed (destroy the thread of the started bullet)

Code:

package com18.tank_game03;

/**
 * @author 甲柒
 * @version 1.0
 * @title Shot
 * @package com18.tank_game03
 * @time 2023/3/29 21:11
 * 射击子弹
 */
public class Shot implements Runnable {
    int x;//子弹x坐标
    int y;//子弹y坐标
    int direct = 0;//子弹方向
    int speed = 5;//子弹速度
    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) {
            //子弹线程休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //根据方向改变x,y坐标
            switch (direct) {
                case 0://上
                    y -= speed;
                    break;
                case 1://右
                    x += speed;
                    break;
                case 2://下
                    y += speed;
                    break;
                case 3://左
                    x -= speed;
                    break;
            }
            //测试,输出子弹的坐标
            System.out.println("子弹 x=" + x + " y=" + y);
            //当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750)) {
                isLive = false;
                break;
            }

        }
    }
}
package com18.tank_game03;

/**
 * @author 甲柒
 * @version 1.3
 * @title Tank
 * @package com18.tank_game03
 * @time 2023/3/29 22:27
 */
public class Tank {
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标
    private int direct;//坦克方向 0 上 1 右 2 下 3 左
    private int speed = 1;

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //上下移动方法
    public void moveUp() {
        y -= speed;
    }

    public void moveRight() {
        x += speed;
    }

    public void moveDown() {
        y += speed;
    }

    public void moveLeft() {
        x -= speed;
    }

    public int getDirect() {
        return direct;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}
package com18.tank_game03;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

/**
 * @author 甲柒
 * @version 1.3
 * @title MyPanel
 * @package com18.tank_game03
 * @time 2023/3/29 22:30
 */
//为了监听 键盘事件,实现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);
        }
        hero.setSpeed(10);
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色

        //画出坦克-封装方法
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 0);

        //画出hero射击的子弹
        if (hero.shot != null && hero.shot.isLive == true) {
            System.out.println("子弹被绘制~~~~~");
            g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);
        }
        //画出敌人的坦克,遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);
        }
    }

    //编写方法,画出坦克

    /**
     * @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) {

    }

    //处理ADWS键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        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() {//每隔100ms 重绘区域 刷新绘图区域
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            this.repaint();
        }
    }
}
package com18.tank_game03;

/**
 * @author 甲柒
 * @version 1.3
 * @title Hero
 * @package com18.tank_game03
 * @time 2023/3/29 22:29
 */
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()) {
            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();

    }
}
package com18.tank_game03;

/**
 * @author 甲柒
 * @version 1.3
 * @title EnemyTank
 * @package com18.tank_game03
 * @time 2023/3/29 12:06
 * 敌人的坦克
 */
public class EnemyTank extends Tank {
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}
package com18.tank_game03;

import javax.swing.*;

/**
 * @author 甲柒
 * @version 1.3
 * @title TankGame03
 * @package com18.tank_game03
 * @time 2023/3/29 22:33
 */
public class TankGame03 extends JFrame {
    //定义MyPanel
    MyPanel mp = null;

    public TankGame03() {
        mp = new MyPanel();
        //将mp 放入到Thread,并启动
        Thread thread = new Thread(mp);
        thread.start();

        this.add(mp);//把面板(就是游戏的绘图区域)
        this.setSize(1000, 750);
        this.addKeyListener(mp);//让JFrame监听mp的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        TankGame03 tankGame03 = new TankGame03();
    }
}

Tank Battle 0.4

add feature

  1. Let enemy tanks also fire bullets (multiple bullets are possible)
  2. When our tank hits the enemy, the enemy's tank will disappear. It would be better if we can make an explosion
  3. Let the enemy's tanks also freely move up and down, left and right randomly
  4. Control our tanks and enemy tanks to move within the specified range

Special Note

  1. as long as it can be achieved
  2. complete the task above

Idea analysis:

Let enemy tanks also fire bullets (multiple bullets are possible)

  1. In enemy tank class, use Vector to save multiple Shots
  2. Whenever an enemy tank object is created, a Shot object is initialized for the enemy tank object, and Shot is started at the same time
  3. When drawing the enemy tank, it is necessary to traverse the Vector of the enemy tank object, draw all the bullets, and when the bullet isLive == false, remove it from the Vector

Let the enemy's tanks also freely move up and down, left and right randomly

  1. Need to use enemy tanks as threads
  2. 需要EnemyTank implements Runnable
  3. Write the corresponding business code in the run method
  4. When the enemy tank object is created, start the thread

Code:

package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.4
 * @title Tank
 * @package com18.tank_game04
 * @time 2023/3/29 22:27
 */
public class Tank {
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标
    private int direct;//坦克方向 0 上 1 右 2 下 3 左
    private int speed = 1;

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //上下移动方法
    public void moveUp() {
        y -= speed;
    }

    public void moveRight() {
        x += speed;
    }

    public void moveDown() {
        y += speed;
    }

    public void moveLeft() {
        x -= speed;
    }

    public int getDirect() {
        return direct;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}
package com18.tank_game04;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

/**
 * @author 甲柒
 * @version 1.4
 * @title MyPanel
 * @package com18.tank_game04
 * @time 2023/3/29 22:30
 */
//为了监听 键盘事件,实现KeyListener
//为了让Panel 不停的重绘子弹,需要将MyPanel实现Runnable,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener, Runnable {
    //定义我的坦克
    Hero hero = null;
    //定义敌人的坦克,放到Vector
    Vector<EnemyTank> enemyTanks = new Vector<>();
    //定义一个Vector 用于存放炸弹
    //说明 当子弹击中坦克时,加入一个Bomb对象到bombs
    Vector<Bomb> bombs = new Vector<>();
    int enemyTankSize = 3;

    //定义三张炸弹图片,用于显示爆炸效果
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    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);
            //启动敌人坦克进程
            new Thread(enemyTank).start();
            //给该enemyTank 加入一颗子弹
            Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
            //加入enemyTank的Vector成员
            enemyTank.shots.add(shot);
            //启动shot对象
            new Thread(shot).start();
            //加入
            enemyTanks.add(enemyTank);

        }

        //初始化图片对象
        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"));

        //设置我方坦克速度
        hero.setSpeed(10);
    }

    //编写方法,判断我方的子弹是否击中敌方的坦克
    public void hiTank(Shot s, EnemyTank enemyTank) {
        //判断s击中坦克
        switch (enemyTank.getDirect()) {
            case 0://坦克向上
            case 2://坦克向下
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 40
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //当我的子弹击中敌人坦克后,将enemyTank 从 Vector 拿掉
                    enemyTanks.remove(enemyTank);
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
            case 1://坦克向右
            case 3://坦克向左
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 60
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }

    //编写方法,画出坦克

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色

        //画出坦克-封装方法
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 0);

        //画出hero射击的子弹
        if (hero.shot != null && hero.shot.isLive == true) {
            System.out.println("子弹被绘制~~~~~");
            g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);
        }

        //如果bombs 集合中有对象,就画出
        for (int i = 0; i < bombs.size(); i++) {
            //取出炸弹
            Bomb bomb = bombs.get(i);
            //根据当前这个bomb对象的life值去画出对应的的图片
            if (bomb.life > 6) {
                g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);
            } else if (bomb.life > 3) {
                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);
            }
        }

        //画出敌人的坦克,遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
            //从 Vector 取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            if (enemyTank.isLive) {//当敌人坦克是存活的,才画出该坦克
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);
                //画出 enemyTank 所有子弹
                for (int j = 0; j < enemyTank.shots.size(); j++) {
                    //取出子弹
                    Shot shot = enemyTank.shots.get(j);
                    //绘制
                    if (shot.isLive) {//isLive == true
                        g.draw3DRect(shot.x, shot.y, 1, 1, false);
                    } else {
                        //从Vector中移除
                        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) {

    }

    //处理ADWS键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键
            //改变坦克的方向
            hero.setDirect(0);
            //修改坦克坐标 y+=1
            if (hero.getY() > 0) {
                hero.moveUp();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//D键
            hero.setDirect(1);
            if (hero.getX() + 60 < 1000) {
                hero.moveRight();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键
            hero.setDirect(2);
            if (hero.getY() + 60 < 750) {
                hero.moveDown();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键
            hero.setDirect(3);
            if (hero.getX() > 0) {
                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() {//每隔100ms 重绘区域 刷新绘图区域
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //判断是否击中了敌人的坦克
            if (hero.shot != null && hero.shot.isLive) {//当我的子弹还存活

                //遍历敌人的所有坦克
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    hiTank(hero.shot, enemyTank);
                }
            }

            this.repaint();
        }
    }
}
package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.4
 * @title Hero
 * @package com18.tank_game04
 * @time 2023/3/29 22:29
 */
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()) {
            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();

    }
}
package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.4
 * @title Shot
 * @package com18.tank_game04
 * @time 2023/3/29 21:11
 * 射击子弹
 */
public class Shot implements Runnable {
    int x;//子弹x坐标
    int y;//子弹y坐标
    int direct = 0;//子弹方向
    int speed = 5;//子弹速度
    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) {
            //子弹线程休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //根据方向改变x,y坐标
            switch (direct) {
                case 0://上
                    y -= speed;
                    break;
                case 1://右
                    x += speed;
                    break;
                case 2://下
                    y += speed;
                    break;
                case 3://左
                    x -= speed;
                    break;
            }
            //测试,输出子弹的坐标
            System.out.println("子弹 x=" + x + " y=" + y);
            //当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)
            //当子弹碰到敌人坦克时,也应该结束线程
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {
                isLive = false;
                break;
            }

        }
    }
}
package com18.tank_game04;

import java.util.Vector;

/**
 * @author 甲柒
 * @version 1.4
 * @title EnemyTank
 * @package com18.tank_game04
 * @time 2023/3/29 12:06
 * 敌人的坦克
 */
public class EnemyTank extends Tank implements Runnable {
    //在敌人的坦克类,使用Vector保存多个Shot
    Vector<Shot> shots = new Vector<>();
    boolean isLive = true;

    public EnemyTank(int x, int y) {
        super(x, y);
    }

    @Override
    public void run() {
        while (true) {
            //根据坦克的方向来继续移动
            switch (getDirect()) {
                case 0://向上
                    for (int i = 0; i < 100; i++) {
                        if (getY() > 0) {
                            moveUp();
                        }
                        //让坦克保持一个方向 走30步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
                case 1://向右
                    for (int i = 0; i < 100; i++) {
                        if (getX() + 60 < 1000) {
                            moveRight();
                        }
                        //让坦克保持一个方向 走30步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
                case 2://向下
                    for (int i = 0; i < 100; i++) {
                        if (getY() + 60 < 750) {
                            moveDown();
                        }
                        //让坦克保持一个方向 走30步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
                case 3://向左
                    for (int i = 0; i < 100; i++) {
                        if (getX() > 0) {
                            moveLeft();
                        }
                        //让坦克保持一个方向 走30步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
            }

            //休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            //然后随机地改变坦克方向 0-3
            setDirect((int) (Math.random() * 4));
            //注意 写并发程序 一定要考虑清楚 该线程什么时候结束
            if (!isLive) {
                break;//退出程序
            }
        }
    }
}
package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.0
 * @title Bomb
 * @package com18.tank_game04
 * @time 2023/3/29 22:47
 * 炸弹
 */
public class Bomb {
    int x, y;//炸弹的坐标
    int life = 9;//炸弹的生命周期
    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;
        }
    }
}
package com18.tank_game04;

import javax.swing.*;

/**
 * @author 甲柒
 * @version 1.4
 * @title TankGame04
 * @package com18.tank_game04
 * @time 2023/3/29 22:33
 */
public class TankGame04 extends JFrame {
    //定义MyPanel
    MyPanel mp = null;

    public TankGame04() {
        mp = new MyPanel();
        //将mp 放入到Thread,并启动
        Thread thread = new Thread(mp);
        thread.start();

        this.add(mp);//把面板(就是游戏的绘图区域)
        this.setSize(1000, 750);
        this.addKeyListener(mp);//让JFrame监听mp的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        TankGame04 tankGame04 = new TankGame04();
    }
}

Tank Battle 0.5

add feature

  1. Our tanks can only fire new bullets after the fired bullets die = "Expansion (fire multiple bullets, control 5 bullets)
  2. After killing the bullet fired by the enemy tank, the bullet can be fired again
  3. When an enemy tank hits our tank, our tank disappears and an explosion effect appears

Idea analysis:

Our tanks can only fire new bullets after the fired bullets die = "Expansion (fire multiple bullets, control 5 bullets)

  1. Press the J key to judge whether the bullet of the current hero object has been destroyed
  2. If not destroyed, do not trigger shotEnemyTank
  3. Only trigger shotEnemyTank if it has been destroyed
  4. If you want to fire multiple bullets, use Vector to save
  5. When drawing our bullets, we need to traverse the Vector collection

When an enemy tank hits our tank, our tank disappears and an explosion effect appears

  1. Write a method to judge whether the enemy tank hits our tank

Code:

package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.4
 * @title Tank
 * @package com18.tank_game04
 * @time 2023/3/29 22:27
 */
public class Tank {
    boolean isLive = true;
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标
    private int direct;//坦克方向 0 上 1 右 2 下 3 左
    private int speed = 1;

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    //上下移动方法
    public void moveUp() {
        y -= speed;
    }

    public void moveRight() {
        x += speed;
    }

    public void moveDown() {
        y += speed;
    }

    public void moveLeft() {
        x -= speed;
    }

    public int getDirect() {
        return direct;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
}
package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.4
 * @title Hero
 * @package com18.tank_game04
 * @time 2023/3/29 22:29
 */
public class Hero extends Tank {
    //定义一个Shot对象,表示一个射击(线程)
    Shot shot = null;
    //可以发射多颗子弹
//    Vector<Shot> shots = new Vector<>();

    public Hero(int x, int y) {
        super(x, y);
    }

    //射击
    public void shotEnemyTank() {

        //控制只有5颗子弹
//        if (shots.size() == 5) {
//            return;
//        }
        //创建Shot对象,根据当前Hero对象的位置和方向来创建Shot
        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;
        }
        //把新创建的shot加入到集合shots中
//        shots.add(shot);
        //启动Shot线程
        new Thread(shot).start();

    }
}
package com18.tank_game04;

import java.util.Vector;

/**
 * @author 甲柒
 * @version 1.4
 * @title EnemyTank
 * @package com18.tank_game04
 * @time 2023/3/29 12:06
 * 敌人的坦克
 */
@SuppressWarnings({"all"})
public class EnemyTank extends Tank implements Runnable {
    //在敌人的坦克类,使用Vector保存多个Shot
    Vector<Shot> shots = new Vector<>();
    boolean isLive = true;

    public EnemyTank(int x, int y) {
        super(x, y);
    }

    @Override
    public void run() {
        while (true) {

            //这里判断如果shots size() == 0
            //创建一颗子弹 放入到shots 集合 并启动
            if (isLive && shots.size() < 1) {
                Shot s = null;
                //判断坦克的方向,创建对应的子弹
                switch (getDirect()) {
                    case 0://上
                        s = new Shot(getX() + 20, getY(), 0);
                        break;
                    case 1://右
                        s = new Shot(getX() + 60, getY() + 20, 1);
                        break;
                    case 2://下
                        s = new Shot(getX() + 20, getY() + 60, 2);
                        break;
                    case 3://左
                        s = new Shot(getX(), getY() + 20, 3);
                        break;
                }
                shots.add(s);
                //启动
                new Thread(s).start();
            }


            //根据坦克的方向来继续移动
            switch (getDirect()) {
                case 0://向上
                    for (int i = 0; i < 50; i++) {
                        if (getY() > 0) {
                            moveUp();
                        }
                        //让坦克保持一个方向 走50步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
                case 1://向右
                    for (int i = 0; i < 50; i++) {
                        if (getX() + 60 < 1000) {
                            moveRight();
                        }
                        //让坦克保持一个方向 走30步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
                case 2://向下
                    for (int i = 0; i < 50; i++) {
                        if (getY() + 60 < 750) {
                            moveDown();
                        }
                        //让坦克保持一个方向 走30步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
                case 3://向左
                    for (int i = 0; i < 50; i++) {
                        if (getX() > 0) {
                            moveLeft();
                        }
                        //让坦克保持一个方向 走30步
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    break;
            }

            //休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            //然后随机地改变坦克方向 0-3
            setDirect((int) (Math.random() * 4));
            //注意 写并发程序 一定要考虑清楚 该线程什么时候结束
            if (!isLive) {
                break;//退出程序
            }
        }
    }
}
package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.4
 * @title Shot
 * @package com18.tank_game04
 * @time 2023/3/29 21:11
 * 射击子弹
 */
public class Shot implements Runnable {
    int x;//子弹x坐标
    int y;//子弹y坐标
    int direct = 0;//子弹方向
    int speed = 5;//子弹速度
    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) {
            //子弹线程休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //根据方向改变x,y坐标
            switch (direct) {
                case 0://上
                    y -= speed;
                    break;
                case 1://右
                    x += speed;
                    break;
                case 2://下
                    y += speed;
                    break;
                case 3://左
                    x -= speed;
                    break;
            }
            //测试,输出子弹的坐标
            System.out.println("子弹 x=" + x + " y=" + y);
            //当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)
            //当子弹碰到敌人坦克时,也应该结束线程
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {
                isLive = false;
                break;
            }

        }
    }
}
package com18.tank_game04;

/**
 * @author 甲柒
 * @version 1.0
 * @title Bomb
 * @package com18.tank_game04
 * @time 2023/3/29 22:47
 * 炸弹
 */
public class Bomb {
    int x, y;//炸弹的坐标
    int life = 9;//炸弹的生命周期
    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;
        }
    }
}
package com18.tank_game04;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

/**
 * @author 甲柒
 * @version 1.4
 * @title MyPanel
 * @package com18.tank_game04
 * @time 2023/3/29 22:30
 */
//为了监听 键盘事件,实现KeyListener
//为了让Panel 不停的重绘子弹,需要将MyPanel实现Runnable,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener, Runnable {
    //定义我的坦克
    Hero hero = null;
    //定义敌人的坦克,放到Vector
    Vector<EnemyTank> enemyTanks = new Vector<>();
    //定义一个Vector 用于存放炸弹
    //说明 当子弹击中坦克时,加入一个Bomb对象到bombs
    Vector<Bomb> bombs = new Vector<>();
    int enemyTankSize = 3;

    //定义三张炸弹图片,用于显示爆炸效果
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    public MyPanel() {
        hero = new Hero(600, 100);//初始化自己的坦克
        //初始化敌人的坦克
        for (int i = 0; i < enemyTankSize; i++) {
            //创建一个敌人的坦克
            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
            //设置方向
            enemyTank.setDirect(2);
            //启动敌人坦克进程
            new Thread(enemyTank).start();
            //给该enemyTank 加入一颗子弹
            Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
            //加入enemyTank的Vector成员
            enemyTank.shots.add(shot);
            //启动shot对象
            new Thread(shot).start();
            //加入
            enemyTanks.add(enemyTank);

        }

        //初始化图片对象
        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"));

        //设置我方坦克速度
        hero.setSpeed(10);
    }

    //如果我方坦克可以发射多个子弹
    //在判断我方子弹是否击中敌方坦克时,就需要把我们的子弹集合中
    //所有的子弹,都取出和敌人的所有坦克,进行判断
    public void hitEnemyTank() {
//        //遍历我们的子弹
//        for (int j = 0; j < hero.shots.size(); j++) {
//            Shot shot = hero.shots.get(j);
//            //判断我方子弹是否击中了敌人的坦克
//            if (shot != null && shot.isLive) {//当我的子弹还存活
//
//                //遍历敌人的所有坦克
//                for (int i = 0; i < enemyTanks.size(); i++) {
//                    EnemyTank enemyTank = enemyTanks.get(i);
//                    hiTank(shot, enemyTank);
//                }
//            }
//        }
        //单颗子弹
        if (hero.shot != null && hero.shot.isLive) {//当我的子弹还存活

            //遍历敌人的所有坦克
            for (int i = 0; i < enemyTanks.size(); i++) {
                EnemyTank enemyTank = enemyTanks.get(i);
                hiTank(hero.shot, enemyTank);
            }
        }

    }

    //编写方法,判断敌方坦克是否击中我方坦克
    public void hitHero() {
        //遍历所有敌方坦克
        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.isLive) {
                    hiTank(shot, hero);
                }
            }
        }
    }

    //编写方法,判断我方的子弹是否击中敌方的坦克
    public void hiTank(Shot s, Tank enemyTank) {
        //判断s击中坦克
        switch (enemyTank.getDirect()) {
            case 0://坦克向上
            case 2://坦克向下
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 40
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //当我的子弹击中敌人坦克后,将enemyTank 从 Vector 拿掉
                    enemyTanks.remove(enemyTank);
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
            case 1://坦克向右
            case 3://坦克向左
                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 60
                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {
                    s.isLive = false;
                    enemyTank.isLive = false;
                    //创建Bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }

    //编写方法,画出坦克

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 1000, 750);//填充矩形,默认黑色

        if (hero != null && hero.isLive) {
            //画出坦克-封装方法
            drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 0);
        }
        //画出hero射击的子弹,单颗子弹
        if (hero.shot != null && hero.shot.isLive == true) {
            System.out.println("子弹被绘制~~~~~");
            g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);
        }

        //多颗子弹
        //将hero的子弹集合shots,遍历取出绘制
//        for (int i = 0; i < hero.shots.size(); i++) {
//            Shot shot = hero.shots.get(i);
//            if (shot != null && shot.isLive) {
//                System.out.println("子弹被绘制~~~~~");
//                g.draw3DRect(shot.x, shot.y, 2, 2, false);
//            } else {//如果该shot对象已经无效,就从shots集合中拿掉
//                hero.shots.remove(shot);
//            }
//        }

        //如果bombs 集合中有对象,就画出
        for (int i = 0; i < bombs.size(); i++) {
            //取出炸弹
            Bomb bomb = bombs.get(i);
            //根据当前这个bomb对象的life值去画出对应的的图片
            if (bomb.life > 6) {
                g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);
            } else if (bomb.life > 3) {
                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);
            }
        }

        //画出敌人的坦克,遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
            //从 Vector 取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            if (enemyTank.isLive) {//当敌人坦克是存活的,才画出该坦克
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 1);
                //画出 enemyTank 所有子弹
                for (int j = 0; j < enemyTank.shots.size(); j++) {
                    //取出子弹
                    Shot shot = enemyTank.shots.get(j);
                    //绘制
                    if (shot.isLive) {//isLive == true
                        g.draw3DRect(shot.x, shot.y, 1, 1, false);
                    } else {
                        //从Vector中移除
                        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) {

    }

    //处理ADWS键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键
            //改变坦克的方向
            hero.setDirect(0);
            //修改坦克坐标 y+=1
            if (hero.getY() > 0) {
                hero.moveUp();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//D键
            hero.setDirect(1);
            if (hero.getX() + 60 < 1000) {
                hero.moveRight();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键
            hero.setDirect(2);
            if (hero.getY() + 60 < 750) {
                hero.moveDown();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键
            hero.setDirect(3);
            if (hero.getX() > 0) {
                hero.moveLeft();
            }
        }
        //如果用户按下J,就发射
        if (e.getKeyCode() == KeyEvent.VK_J) {
            System.out.println("用户按下了J开始射击~~~~");

            //判断hero的子弹是否销毁,发射一颗子弹
            if (hero.shot == null || !hero.shot.isLive) {
                hero.shotEnemyTank();
            }
            //发射多颗子弹
//            hero.shotEnemyTank();
        }
        //重绘
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void run() {//每隔100ms 重绘区域 刷新绘图区域
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //判断敌我方坦克是否击中敌方坦克
            hitEnemyTank();
            //判断敌方坦克是否击中了我方坦克
            hitHero();
            this.repaint();
        }
    }
}
package com18.tank_game04;

import javax.swing.*;

/**
 * @author 甲柒
 * @version 1.4
 * @title TankGame04
 * @package com18.tank_game04
 * @time 2023/3/29 22:33
 */
public class TankGame04 extends JFrame {
    //定义MyPanel
    MyPanel mp = null;

    public TankGame04() {
        mp = new MyPanel();
        //将mp 放入到Thread,并启动
        Thread thread = new Thread(mp);
        thread.start();

        this.add(mp);//把面板(就是游戏的绘图区域)
        this.setSize(1200, 950);
        this.addKeyListener(mp);//让JFrame监听mp的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        TankGame04 tankGame04 = new TankGame04();
    }
}

Guess you like

Origin blog.csdn.net/qq_59621600/article/details/129845335