Java-敌方坦克攻击(Vector实现发射多颗子弹并绘制)

文章介绍了如何在Java中使用Vector实现坦克游戏中的多子弹发射和并发绘图功能,包括子弹的有效性管理、坦克攻击方法、子弹发射线程以及处理边界碰撞和资源释放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java-敌方坦克攻击(Vector实现发射多颗子弹并绘制)

实现过程

  • 子弹类(Bullet)
    • 新增属性:
      • (1)isLive:子弹是否有效
        • 当子弹超出边界后,子弹失效,不应该继续占用资源;
/**
 * 子弹类
 * @author: SEA
 * @date: 2023/3/18
 */
public class Bullet {
    //子弹坐标和发射方向
    int x;
    int y;
    int direction;

    int speed = 5;//子弹初始速度为 5

    boolean isLive = false;//子弹是否有效
    public Bullet(int x, int y, int direction) {
        this.x = x;
        this.y = y;
        this.direction = direction;
    }

    public int getSpeed() {
        return speed;
    }

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

    public boolean isLive() {
        return isLive;
    }

    public void setLive(boolean live) {
        isLive = live;
    }
}

  • 普通坦克类(Tank)
    • 新增属性:
      • (1)子弹对象集合bullets;
    • 新增方法:
      • (1)setBullets() 和 getBullets();
    • 修改:
      • (1)坦克攻击方法attack()中,每调用一次attack()方法:
        • 1)生成一个子弹对象bullet,并设置isLive为true;
        • 2)将新生成的子弹对象bullet加入子弹对象集合bullets中;
import java.util.Vector;

/**
 * 坦克
 * @author: SEA
 * @date: 2023/3/2
 */
public class Tank{
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标

    private int direction;//坦克的朝向:0 => 向上 ,1 => 向下 ,2 => 向左 , 3 => 向右

    private int speed = 5;//坦克速度

    private Bullet bullet;//坦克子弹

    private Vector<Bullet> bullets = new Vector<Bullet>();//子弹集合,使坦克可以发射多颗子弹并在panel绘制

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

    public void moveUp(){
        this.y -= this.speed;
    }

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

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

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

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

    public int getDirection() {
        return direction;
    }

    public void setDirection(int direction) {
        this.direction = direction;
    }

    public int getSpeed() {
        return speed;
    }

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

    public Bullet getBullet() {
        return bullet;
    }

    public void setBullet(Bullet bullet) {
        this.bullet = bullet;
    }

    public Vector<Bullet> getBullets() {
        return bullets;
    }

    public void setBullets(Vector<Bullet> bullets) {
        this.bullets = bullets;
    }

    public void attack(){//坦克攻击
        int bullet_x = -10, bullet_y = -10;
        switch (this.getDirection()){//根据当前坦克的位置和方向来计算子弹的发射方向
            case 0:
                bullet_x = this.getX()+20;
                bullet_y = this.getY()-6;
                break;
            case 1:
                bullet_x = this.getX()+20;
                bullet_y = this.getY()+64;
                break;
            case 2:
                bullet_x = this.getX()-6;
                bullet_y = this.getY()+20;
                break;
            case 3:
                bullet_x = this.getX()+64;
                bullet_y = this.getY()+20;
                break;
            default:
                break;
        }
        //这样写只能发射一颗子弹,因为每次攻击都会重新给子弹分配新的对象,repaint()后旧的对象将不会被绘制,但实际上仍然存在;
        //1.我一开始想的是,怎么让本次攻击不影响上一次攻击,没想出来怎么实现;
        //2.韩老师的思路:每次攻击创建一颗子弹,用vector保存,绘制的时候再取出来,到边界后再移除;
        this.bullet = new Bullet(bullet_x, bullet_y, this.direction);
        this.bullet.isLive = true;
        this.bullets.add(this.bullet);

        TankAttackThread tankAttackThread = new TankAttackThread(bullet);
        Thread thread = new Thread(tankAttackThread);
        thread.start();
    }
}
  • 子弹发射:

    • 修改:
      • (1)当子弹超出边界时,设置子弹的isLive属性为false,该子弹应释放资源;
    /**
     * 子弹发射(多线程)
     * @author: SEA
     * @date: 2023/3/18
     */
    public class TankAttackThread implements Runnable{
        Bullet bullet;
    
        public TankAttackThread(Bullet bullet) {
            this.bullet = bullet;
        }
    
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                switch (this.bullet.direction){
                    case 0:
                        this.bullet.y -= this.bullet.speed;
                        break;
                    case 1:
                        this.bullet.y += this.bullet.speed;
                        break;
                    case 2:
                        this.bullet.x -= this.bullet.speed;
                        break;
                    case 3:
                        this.bullet.x += this.bullet.speed;
                        break;
                }
                System.out.println(this.bullet.x+"==asa=" + this.bullet.y);
    
                if(this.bullet.x < -3 || this.bullet.y < -3 || this.bullet.x > 1003 || this.bullet.y > 803  ){
                    this.bullet.setLive(false);
                    break;
                }
            }
    
        }
    }
    
  • 坦克大战绘图区域:

  • 修改:

    • (1)使用for循环,绘制玩家坦克子弹;

    • (2)使用for循环,绘制敌方坦克子弹;

    • (3)需要注意的点:

      • 遍历时,如果使用增强for遍历,会爆ConcurrentModificationException错误;
      • 绘制时,当子弹的isLive属性为false时,及时移除子弹,释放资源;
/**
 * 坦克大战绘图区域
 * @author: SEA
 * @date: 2023/3/2
 */
class GamePanel extends JPanel implements KeyListener, Runnable{//画板

......

    //绘制    
    @Override
    public void paint(Graphics g) {
        super.paint(g);

        //游戏窗口背景
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, 1000, 800);

        //标题
        g.setFont(new Font("楷体", Font.BOLD, 32));
        g.setColor(Color.RED);
        g.drawString("TankGame V0.2 by SEA-365", 60, 40);

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

        //绘制玩家坦克的子弹
        for (int i = 0; i < heroTank.getBullets().size(); i++) {
            Bullet bullet = heroTank.getBullets().get(i);//取出子弹
            if(bullet!=null && bullet.isLive)
                drawBullet(bullet.x, bullet.y, g, 0);//绘制
            else
                heroTank.getBullets().remove(bullet);//子弹超出边界,移除
        }

        //绘制敌方坦克子弹
        for (int i = 0; i < enemyTankSize; i++) {
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);
            System.out.println("====================================【" + enemyTank.getBullets().size() + "】==========");
            for (int j = 0; j < enemyTank.getBullets().size(); j++) {//这里应使用for遍历,不然会爆并发错误
                Bullet bullet = enemyTank.getBullets().get(j);//取出子弹
                if(bullet != null && bullet.isLive)
                    drawBullet(bullet.x, bullet.y, g, 1);//绘制
                else
                    enemyTank.getBullets().remove(bullet);//子弹超出边界,移除
            }

        }
    }
    
    ......
        
   	//绘制子弹具体实现
    public void drawBullet(int x, int y, Graphics g, int direction, int type){
        //不同坦克类型,子弹颜色不同
        switch (type){
            case 0://玩家坦克
                g.setColor(Color.YELLOW);
                break;
            case 1://敌方坦克
                g.setColor(Color.CYAN);
                break;
        }
       
        g.fill3DRect(x, y, 6, 6, false);//绘制矩形子弹
      
    }

    ......
}



//最后,在GameFrame中启动GamePanel线程

实现效果

在这里插入图片描述

待优化

  • 子弹击中敌方坦克后:

    • 1.爆炸效果;
    • 2.敌方坦克消失;
  • 敌方坦克需要能够随机移动;

  • 坦克移动范围未限制,可能移动至边界外;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SEA-365

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值