Java学习Day15 坦克大战ver0.5

这篇文章介绍了Java编程中的坦克大战游戏版本0.5的升级,包括玩家坦克的自由发射子弹功能、子弹和敌方坦克的碰撞检测以及我方坦克被击中后的爆炸效果。代码展示了如何在JFrame中实现多线程和游戏逻辑的更新。
摘要由CSDN通过智能技术生成

Java学习Day15 坦克大战ver0.5

新增功能 自由发射子弹 我方爆炸

Game方法

/*
1.我方坦克在发射的子弹消亡后,才能发射新的子弹.=>
扩展(发多颗子弹怎么办.控制在我们的面板上,最多只有5颗)
2.让敌人坦克发射的子弹消亡后,可以再发射子弹
3.当敌人的坦克击中我方坦克时,我方坦克消失,并出现爆炸效果.
 */
public class TankGame05 extends JFrame {
    //定义一个面板
    MyPanel mp = null;

    public static void main(String[] args) {
        TankGame05 tankGame05 = new TankGame05();

    }
    public TankGame05() {
        mp = new MyPanel();
        Thread thread = new Thread(mp);
        thread.start();
        //启动mp
        this.add(mp);//加入游戏的绘图区域

        this.setSize(1000, 750);
        this.addKeyListener(mp);//增加一个监听
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

MyPanel 我方爆炸

只需要写一个方法判断敌方子弹是否打到我方 在run方法里调用即可

//绘图
//为了不停地重绘子弹 需要让MyPanel成为线程
public class MyPanel extends JPanel implements KeyListener, Runnable {
    //定义p1 tank
    P1 p1 = null;

    //    Bullet bullet = null;
    //定义enemy tank
    Vector<EnemyTank> enemyTanks = new Vector<>();
    int enemyTankSize = 3;
    //定义一个集合 存放炸弹
    Vector<Boom> booms = new Vector<>();
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    public MyPanel() {

        p1 = new P1(100, 100);//初始化自己坦克

        p1.setSpeed(4);
        //初始化敌人tank
        for (int i = 0; i < enemyTankSize; i++) {
//            enemyTanks.add(new EnemyTank(300 * (i + 1), 0));

            //也可以在这里初始化tank方向
            //创建一个敌人tank
            EnemyTank enemyTank = new EnemyTank((300 * (i + 1)), 0);

            //设置方向
            enemyTank.setDirection(2);

            enemyTank.setSpeed(1);

            //启动
            new Thread(enemyTank).start();

            //给加入的tank加入一个bullet
            Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 80, enemyTank.getDirection());
            enemyTank.shots.add(shot);
            //加入一个tank
            new Thread(shot).start();

            enemyTanks.add(enemyTank);

        }
        //初始化图形
        image1 = Toolkit.getDefaultToolkit().getImage("out/production/Hello/com/yuhuw/tankwar/1.png");
        image2 = Toolkit.getDefaultToolkit().getImage("out/production/Hello/com/yuhuw/tankwar/2.png");
        image3 = Toolkit.getDefaultToolkit().getImage("out/production/Hello/com/yuhuw/tankwar/3.png");
    }

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

        g.fillRect(0, 0, 1000, 750);//填充矩形 默认是黑色
        //画出p1的tank
        if (p1 !=null&&p1.isLive) {
            drawTank(p1.getX(), p1.getY(), g, p1.getDirection(), 0);
            //画出enemy的tank
        }

        /*
        1.enemy tank可以单开一个类继承tank并且有自己的属性和方法
        2.敌人tank数量多且多线程考虑安全使用vector
        3.遍历取出所有集合的tank
         */
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出tank
            EnemyTank enemyTank = enemyTanks.get(i);
            //判断当前tank是否存活
            if (enemyTank.isLive) {
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);
                for (int j = 0; j < enemyTank.shots.size(); j++) {
                    //取出bullet
                    Shot shot = enemyTank.shots.get(j);
                    //画出bullet
                    if (shot.isLive) {
                        g.fill3DRect(shot.x, shot.y, 2, 2, false);
                    } else {
                        //移除bullet
                        enemyTank.shots.remove(shot);
                    }
                }
            }
            this.repaint();
        }

        //画出P1的bullet

        for (int i = 0; i < p1.shots.size(); i++) {
            if (p1.shots.get(i) != null && p1.shots.get(i).isLive) {
                g.setColor(Color.yellow);
                g.fill3DRect(p1.shots.get(i).x, p1.shots.get(i).y, 2, 2, false);
            } else {
                p1.shots.remove(i);
            }
        }

        //画出爆炸效果
        for (int i = 0; i < booms.size(); i++) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Boom boom = booms.get(i);
            //根据life画出对应图片
            if (boom.life > 6) {
                g.drawImage(image3, boom.x, boom.y, 50, 50, this);
            } else if (boom.life > 3) {
                g.drawImage(image2, boom.x, boom.y, 50, 50, this);
            } else {
                g.drawImage(image1, boom.x, boom.y, 50, 50, this);
            }
            boom.lifeDown();
            if (boom.life == 0) {//若life==0,就删除
                booms.remove(boom);
            }
        }
    }

    //编写画出tank的方法
    /*
    1.x y 左上角坐标
    2.g 画笔
    3.direction 方向
    4.type 类型
    */
    public void drawTank(int x, int y, Graphics g, int direction, int type) {
        switch (type) {
            case 0://我们的tank
                g.setColor(Color.yellow);
                break;
            case 1://敌人的tank
                g.setColor(Color.red);
                break;
        }

        //根据tank的方向绘制不同的tank
        switch (direction) {
            case 0://表示向上
                //填充当前颜色的高亮矩形   宽    高       表面色泽
                g.fill3DRect(x, y, 10, 60, false);//画出tank左轮
                g.fill3DRect(x + 30, y, 10, 60, false);//tank右轮
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//tank身体
                g.fillOval(x + 10, y + 20, 20, 20);//tank出口盖
                g.drawLine(x + 20, y + 20, x + 20, y);
                //画出tank炮筒
                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 + 20, y + 20, x + 60, y + 20);
                break;
            case 2://向下
                g.fill3DRect(x, y, 10, 60, false);//画出tank左轮
                g.fill3DRect(x + 30, y, 10, 60, false);//tank右轮
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//tank身体
                g.fillOval(x + 10, y + 20, 20, 20);//tank出口盖
                g.drawLine(x + 20, y + 20, 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 + 20, y + 20, x, y + 20);
                break;
            default:
                System.out.println("没有处理");
        }
    }

    //子弹击中tank 判断我们子弹是否击中tank
    public void hitTank(Shot s, Tank tank) {
        switch (tank.getDirection()) {
            case 0:
            case 2:
                if (s.x > tank.getX() && s.x < tank.getX() + 40 &&
                        s.y > tank.getY() && s.y < tank.getY() + 60) {
                    s.isLive = false;
                    tank.isLive = false;
                    //从集合中移除这个tank
                    enemyTanks.remove(tank);
                    //创建Boom对象 加入到booms集合
                    Boom boom = new Boom(tank.getX(), tank.getY());
                    booms.add(boom);
                }
                break;
            case 1:
            case 3:
                if (s.x > tank.getX() && s.x < tank.getX() + 60 &&
                        s.y > tank.getY() && s.y < tank.getY() + 40) {
                    s.isLive = false;
                    tank.isLive = false;
                    enemyTanks.remove(tank);
                    Boom boom = new Boom(tank.getX(), tank.getY());
                    booms.add(boom);
                }
                break;
        }

    }

    //编写方法判断敌人子弹是否打到p1
    public void hitP1() {
        for (int i = 0; i < enemyTankSize; i++) {
            EnemyTank enemyTank = enemyTanks.get(i);
            for (int j = 0; j < enemyTank.shots.size(); j++) {
                Shot shot = enemyTank.shots.get(j);

                if (p1.isLive && shot.isLive) {
                    hitTank(shot, p1);
                }
            }
        }
    }


    @Override
    public void keyTyped(KeyEvent e) {

    }

    //读取键盘的wasd改变tank的方向
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
            //键盘按键 0w 2s 3a 1d
            p1.setDirection(0);
            //p1.setY(getY()-1);不优雅
            if (p1.getY() > 0) {
                p1.moveUp();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_S) {
            p1.setDirection(2);
            if (p1.getY() < 650) {
                p1.moveDown();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
            p1.setDirection(3);
            if (p1.getX() > 0) {
                p1.moveLeft();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_D) {
            p1.setDirection(1);
            if (p1.getX() < 920) {
                p1.moveRight();
            }
        }
        if (e.getKeyCode() == KeyEvent.VK_J) {
            //控制tank只能发射一颗子弹
//            if (p1.shot == null || p1.shot.isLive == false) {
//                p1.shotEnemyTank();
//            }
            //发射多颗子弹
            p1.shotEnemyTank();
        }
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //判断p1是否击中enemytank
            for (int j = 0; j < p1.shots.size(); j++) {
                //遍历p1所有的子弹
                if (p1.shots.get(j) != null && p1.shots.get(j).isLive) {
                    //遍历敌人所有的tank 因为不知道子弹击中了敌人的哪一个tank
                    for (int i = 0; i < enemyTanks.size(); i++) {
                        EnemyTank enemyTank = enemyTanks.get(i);
                        hitTank(p1.shots.get(j), enemyTank);
                    }
                }

            }
            //判断enemy tank是否击中p1
            hitP1();
            this.repaint();
        }
    }
}

P1类 发射多颗子弹

给shot创建一个集合每个shot启动一个线程 用集合大小控制子弹个数

public class P1 extends Tank {

    //定义一个shot对象 我们只有一个子弹
    Shot shot = null;
    Vector<Shot> shots =new Vector<>();

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

    public void shotEnemyTank() {

        //创建shot对象 根据P1的位置确定
        switch (getDirection()) {
            case 0:
                shot = new Shot(getX() + 20, getY() - 20, 0);
                break;
            case 1:
                shot = new Shot(getX() + 80, getY() +20, 1);
                break;
            case 2:
                shot = new Shot(getX() + 20, getY() + 80, 2);
                break;
            case 3:
                shot = new Shot(getX() - 20, getY() + 20, 3);
                break;
        }
        //控制p1可发出子弹的个数
        if (shots.size() == 5) {
            return;
        }
        //把新创建的shot放入集合中
        shots.add(shot);
        //启动shot
        Thread thread = new Thread(shot);
        thread.start();

    }
}

Shot类

public class Shot implements Runnable {
    int x;
    int y;
    int direction = 0;
    int speed = 10;
    boolean isLive = true;//子弹是否存活

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

    @Override
    public void run() {
        while (true) {
            switch (direction) {
                case 0:
                    y -= speed;
                    break;
                case 1:
                    x += speed;
                    break;
                case 2:
                    y += speed;
                    break;
                case 3:
                    x -= speed;
                    break;
            }

            //离开面板就退出
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750&&isLive)) {
                isLive = false;
                break;
            }
            //当子弹碰到敌人tank也要退出

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

EnemyTank类 敌人发射多颗子弹

让敌人发射的子弹也成为一个集合 每一个子弹也启动一个线程

public class EnemyTank extends Tank implements Runnable {
    public EnemyTank(int x, int y) {
        super(x, y);
    }

    private int direction = 2;
    boolean isLive = true;


    Vector<Shot> shots = new Vector<Shot>();

    private void enemyShot() {

    }

    //重写enemy tank的方向
    @Override
    public int getDirection() {
        return direction;
    }

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

    @Override
    public void run() {
        while (true) {
            //当enemy tank没有子弹创建一个子弹
            if (isLive && shots.size() < 10){
                //判断tank的方向
                Shot s =null;
                switch (getDirection()){
                    case 0:
                        s = new Shot(getX() + 20, getY() - 20, 0);
                        break;
                    case 1:
                        s = new Shot(getX() + 80, getY() +20, 1);
                        break;
                    case 2:
                        s = new Shot(getX() + 20, getY() + 80, 2);
                        break;
                    case 3:
                        s = new Shot(getX() - 20, getY() + 20, 3);
                        break;
                }
                shots.add(s);
                new Thread(s).start();
            }
            int moveSpeed = 30;
            int sleepTime = 300;
            switch (getDirection()) {


                case 0:
                    for (int i = 0; i < moveSpeed; i++) {
                        if (getY() > 0) {
                            moveUp();
                        }
                    }
                    try {
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
                case 1:
                    for (int i = 0; i < moveSpeed; i++) {
                        if (getX() < 920) {
                            moveRight();
                        }
                    }
                    try {
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
                case 2:
                    for (int i = 0; i < moveSpeed; i++) {
                        if (getY() < 650) {
                            moveDown();
                        }
                    }
                    try {
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
                case 3:
                    for (int i = 0; i < moveSpeed; i++) {
                        if (getX() > 0) {
                            moveLeft();
                        }
                    }
                    try {
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    break;
            }
//            try {
//                Thread.sleep(2000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            setDirection(new Random().nextInt(4));
            if (isLive == false) {
                break;
            }
        }

    }
}

其余类

Boom

public class Boom {
    int x, y;
    int life = 9;
    boolean isLive = true;

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

    //减少生命值
    public void lifeDown() {
        if (life > 0) {
            life--;
        } else {
            isLive = false;
        }

    }
}

Tank类

public class Tank {
    private int x;//横纵坐标
    private int y;

    boolean isLive =true;
    private int direction = 0;//坦克方向

    private int speed = 1;

    public int getSpeed() {
        return speed;
    }

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

    //移动方法
    public void moveUp(){
        y-=speed;
    }
    public void moveDown(){
        y+=speed;
    }
    public void moveLeft(){
        x-=speed;
    }
    public void moveRight(){
        x+=speed;
    }
    public int getDirection() {
        return direction;
    }

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

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

    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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值