Java-坦克攻击(敌方坦克消失)

Java-坦克攻击(敌方坦克消失)

实现过程

  • 子弹类(Bullet)
/**
 * 子弹类
 * @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)坦克是否存活isLive;
    • 新增方法:
      • (1)setLive() 和 isLive();
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 boolean isLive = true;//坦克是否有效(是否被子弹击中)

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

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

    ......

    public boolean isLive() {
        return isLive;
    }

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

    public void attack(){//坦克攻击
        ......
    }

    public void attack(Vector<EnemyTank> enemyTanks){//坦克攻击
        ......
    }
}
  • 子弹发射:

    • 修改:
      • (1)增加子弹击中时销毁子弹的判断;
      • (2)考虑到是否击中敌方坦克判断属于玩家坦克特有,因此将判断代码放到了GamePanel类中;
    import java.util.Vector;
    
    /**
     * 子弹发射(多线程)
     * @author: SEA
     * @date: 2023/3/18
     */
    public class TankAttackThread implements Runnable{
        Bullet bullet;
        Vector<EnemyTank> enemyTanks = new Vector<EnemyTank>();
    
        public TankAttackThread(Bullet bullet) {
            this.bullet = bullet;
        }
    
        public TankAttackThread(Bullet bullet, Vector<EnemyTank> enemyTanks) {
            this.bullet = bullet;
            this.enemyTanks = enemyTanks;
        }
    
        @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 + ", " + this.bullet.y + "] ====");
    
                //到达边界以及子弹击中,销毁子弹
                if((!this.bullet.isLive()) || this.bullet.x < -3 || this.bullet.y < -3 || this.bullet.x > 1003 || this.bullet.y > 803  ){
                    this.bullet.setLive(false);
                    break;
                }
            }
    
        }
    }
    
    
  • 坦克大战绘图区域:

  • 修改:

    • (1)为了测试子弹是否击中敌方坦克,将敌方坦克的方向修改为各个方向都有;
    • (2)绘制玩家坦克的子弹时,增加子弹是否存活判断;
    • (3)绘制敌方坦克时,增加敌方坦克是否存活判断;
  • 新增:

    • (1)增加玩家坦克子弹是否击中敌方坦克的判断函数EnemyTank isHitted(Bullet bullet, Vector enemyTanks);
    • (2)在每次重绘前遍历玩家子弹集合和敌方坦克集合,判断玩家坦克是否击中任意敌方坦克;(双重遍历)
  • 删除:

    • (1)标题的绘制改为设置游戏窗口标题
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

/**
 * 坦克大战绘图区域
 * @author: SEA
 * @date: 2023/3/2
 */


class GamePanel extends JPanel implements KeyListener, Runnable{//画板

    //定义玩家的坦克
    HeroTank heroTank = null;

    //考虑多线程问题,使用Vector来保存敌方坦克
    Vector<EnemyTank> enemyTanks = null;
    int enemyTankSize = 5;


    public GamePanel() {
        heroTank = new HeroTank(250, 400);//初始化玩家坦克

        enemyTanks = new Vector<EnemyTank>();

        for (int i = 0; i < enemyTankSize; i++) {
            EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 100);
            enemyTank.setDirection(i % 4);
            //让敌方坦克也能攻击
            enemyTank.attack();

            enemyTanks.add(enemyTank);
        }
    }

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

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

        //画出坦克-封装成方法
        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 < enemyTanks.size(); i++) {
            EnemyTank enemyTank = enemyTanks.get(i);
            if(enemyTank.isLive())
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);
            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);//子弹超出边界,移除
            }

        }
    }

    /**
     *
     * @param x 坦克左上方x轴坐标
     * @param y 坦克左上方y轴坐标
     * @param g 画笔
     * @param direction 坦克的朝向:0 => 向上 ,1 => 向下 ,2 => 向左 , 3 => 向右
     * @param type 坦克类型:0 => 玩家坦克,1 => 敌方坦克
     */
    public void drawTank(int x, int y, Graphics g, int direction, int type){
       ......
    }

    public void drawBullet(int x, int y, Graphics g, int type){
       ......
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        ......
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

        private EnemyTank isHitted(Bullet bullet, Vector<EnemyTank> enemyTanks) {
            int enemyTank_x_left;//敌方坦克的左边缘x坐标
            int enemyTank_x_right;//敌方坦克的右边缘x坐标
            int enemyTank_y_top;//敌方坦克的上边缘y坐标
            int enemyTank_y_bottom;//敌方坦克的下边缘y坐标

            for (int i = 0; i < enemyTanks.size(); i++) {
                EnemyTank cur_enemyTank = enemyTanks.get(i);
                if(cur_enemyTank.getDirection() == 0 || cur_enemyTank.getDirection() == 1){
                    enemyTank_y_bottom = cur_enemyTank.getY() + 60;
                    enemyTank_x_right = cur_enemyTank.getX() + 44;
                }
                else {
                    enemyTank_y_bottom = cur_enemyTank.getY() + 44;
                    enemyTank_x_right = cur_enemyTank.getX() + 60;
                }

                enemyTank_x_left = cur_enemyTank.getX();
                enemyTank_y_top = cur_enemyTank.getY();


                switch (bullet.direction){//发射子弹的方向
                    case 0://向上
                        if(bullet.x+6 >= enemyTank_x_left && bullet.x + 6 <= enemyTank_x_right && bullet.y <= enemyTank_y_bottom)
                            return cur_enemyTank;
                        break;
                    case 1://向下
                        if(bullet.x+6 >= enemyTank_x_left && bullet.x + 6 <= enemyTank_x_right && bullet.y+6 >= enemyTank_y_top)
                            return cur_enemyTank;
                        break;
                    case 2://向左
                        if(bullet.y+6 <= enemyTank_y_bottom && bullet.y+6 >= enemyTank_y_top && bullet.x+6 <= enemyTank_x_right)
                            return cur_enemyTank;
                        break;
                    case 3://向右
                        if(bullet.y+6 <= enemyTank_y_bottom && bullet.y+6 >= enemyTank_y_top && bullet.x <= enemyTank_x_left)
                            return cur_enemyTank;
                        break;
                }
            }
            return null;
        }

        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if(heroTank.getBullets() != null){
                    for (int i = 0; i < heroTank.getBullets().size(); i++) {
                        Bullet cur_bullet = heroTank.getBullets().get(i);
                        if (cur_bullet != null && cur_bullet.isLive()){
                            //是否击中敌方坦克判断
                            EnemyTank hittedTank = isHitted(cur_bullet, enemyTanks);
                            if (cur_bullet.isLive() && hittedTank != null) {
                                System.out.println("======击中了["+ hittedTank.getX() + ", " + hittedTank.getY() +"]=======");
                                //销毁被击中的坦克以及该子弹
                                hittedTank.setLive(false);
                                cur_bullet.setLive(false);
                                enemyTanks.remove(hittedTank);
                                heroTank.getBullets().remove(cur_bullet);
                            }
                        }
                    }
                }

                this.repaint();
            }

        }
    }

实现效果

在这里插入图片描述

待优化

  • 子弹击中敌方坦克后:
    • 1.爆炸效果;
  • 敌方坦克需要能够随机移动;
  • 坦克移动范围未限制,可能移动至边界外;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SEA-365

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

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

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

打赏作者

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

抵扣说明:

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

余额充值