Java基础 - 坦克大战(第五章,坦克移动、与被击中效果功能)

文章目录

坦克大战0.3

陆游曾说:纸上得来终觉浅,绝知此事要躬行。前面已经了解Java线程基础知识,现在我们来实际运用一下。

在坦克大战游戏(0.2版)基础上添加如下功能:当玩家按一下j键,就发射一颗子弹。

  • 为了能射出子弹,需要把每个子弹做成一个线程,并根据KeyListener事件判断用户输入,之后循环判断子弹位置,repaint()子弹,并要根据坦克的每个方向调整x,y轴

新建Shot类

package tankgame3;

/**
 * Create By 刘鸿涛
 * 2022/1/17 5:19
 */
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){
            //子弹休眠
            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)){
                isLive = false;
                break;
            }
        }
    }
}

Java基础 - 坦克大战(第五章,坦克移动、与被击中效果功能)

坦克大战0.4版

  • 增加功能
  1. 让敌人的坦克也能够发射子弹(可以有多颗子弹)
  2. 当我方坦克击中敌人坦克时,敌人的坦克就消失,如果能做出爆炸效果更好
  3. 让敌人的坦克也可以*随机的上下左右移动
  4. 控制我方的坦克和敌人的坦克在规定的范围移动
  • 特别说明
  1. 只要能实现就行,方法的好坏我们后面评讲
  2. 完成上面的任务,不会有没有讲过的知识点,这里主要是锻炼大伙灵活运用技术点能力
  3. 一定要自己先动脑筋想想,试着做做。再听老师的评讲才有意义,时间自己掌控(再次提醒,一定要先自己思考,再听老师讲收获会很大)

1.让敌人坦克发射子弹(多颗子弹)

思路

  • 为了使敌方坦克射出子弹,需要把敌方坦克的所有子弹做成一个线程集合里,这里的集合我们用的vector(为了线程安全),敌人坦克是一个独立的集合,敌人子弹也是一个独立的集合,每个子弹线程都被Thread代理,并执行start()。根据判断敌人坦克子弹的状态,判断是否需要移出此线程集合元素,比如是否碰到边缘、是否碰到玩家、是否碰到障碍物

EnemyTank类

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

MyPanel类无参构造器

    public MyPanel(){
        hero = new Hero(500,500);   //初始化自己的坦克
        hero.setSpeed(50);               //初始化坦克速度

        //初始化敌人坦克
        for (int i = 0; i < enemyTanksSize; i++) {
            //创建一个敌人的坦克
            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
            //设置方向
            enemyTank.setDirect(2);
            //给该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);
        }
    }

MyPanel类paint()方法

  @Override
    public void paint(Graphics g){
        super.paint(g);
        g.fillRect(0,0,1000,750);    //填充矩形,默认黑色
        //画出坦克 - 封装方法
        //自己的坦克
        drawTank(hero.getX(),hero.getY(),g,hero.getDirect(),1);        //type坦克类型

        //画出hero射击的子弹
        if (hero.shot != null && hero.shot.isLive == true){
            g.draw3DRect(hero.shot.x,hero.shot.y,5 ,5,false);
        }
        //画出敌人的坦克,遍历Vector
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(),enemyTank.getY(),g,enemyTank.getDirect(),0);
            //画出 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,2,2,false);
                }else {
                    //从Vector 移除
                    enemyTank.shots.remove(shot);
                }
            }
        }
    }

2.当我方坦克击中敌人坦克时,敌人的坦克就消失

实现子弹击中敌方坦克消失,我们需要写一个方法,判断我方子弹是否碰到敌方坦克,需要考虑敌方坦克面向问题。我们在paint方法中也加入判断语句,如果上面条件为真,则返回敌方坦克isLive属性为false,根据情况paint敌方坦克是否执行。而我们的线程集合每隔100毫秒遍历一次敌方坦克集合,刷新整个游戏区域,实现敌方坦克被击中后消失

hitTank()方法

    public static void hitTank(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;
                }
                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;
                }
                break;
        }
    }

3.实现敌人坦克爆炸后消失

当敌方坦克被击中后出现爆炸效果,我们新建一个爆炸效果类,这个类需要有x,y大小,需要一个生命周期的方法,来让爆炸效果动态化。当然了,我们的爆炸效果也在一个集合中,也有自己的isLive属性,判断存活时间,我们用Image来初始化三张图片,并路径赋值,在坦克被击中方法里,我们添加执行效果-> 坦克被击中消失后,我们开始执行爆炸类的“生命周期方法”,按条件执行图片放映顺序

新建Bomb类

package tankgame4;

/**
 * Create By 刘鸿涛
 * 2022/1/19 4:56
 */
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;
        }
    }
}

注意图片位置

Java基础 - 坦克大战(第五章,坦克移动、与被击中效果功能)

当敌方坦克被击中后出现爆炸效果,我们新建一个爆炸效果类,这个类需要有x,y大小,需要一个生命周期的方法,来让爆炸效果动态化。当然了,我们的爆炸效果也在一个集合中,也有自己的isLive属性,判断存活时间,我们用Image来初始化三张图片,并路径赋值,在坦克被击中方法里,我们添加执行效果-> 坦克被击中消失后,我们开始执行爆炸类的“生命周期方法”,按条件执行图片放映顺序

4.实现敌人坦克*移动

  1. 因为要求敌人的坦克,可以*移动,因此需要将敌人坦克当做线程使用
  2. 因此,我们需要EnemyTank implements Runnable
  3. 在run方法写上我们相应的业务代码
  4. 在创建敌人坦克对象时,启动线程

为了使敌方坦克*活动,我们需要为敌方每个坦克做成一个线程,因此,我们的敌人坦克类要实现Runnable接口,我们的run实现逻辑,通过setDirect封装方法,我们用switch循环加上Math.Random随机生成数,随机生成坦克方向,并按for循环来进行移动,每次朝一个方向移动后休眠50毫秒,体现缓冲效果,当然了,如果此线程坦克被击中,那么我们让此线程while循环break,不再执行

5.实现坦克站规定范围内移动

为了能使敌方坦克在游戏范围内移动,我们只需要在敌方坦克随机循环移动时,加入一个if条件即可,当超过范围,则不执行此次循环

package tankgame4;

import java.util.Vector;

/**
 * Create By 刘鸿涛
 * 2022/1/13 2:16
 */
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://向上
                    //让坦克保存一个方向,走30步
                    for (int i = 0; i < 30; i++) {
                        if (getY() > 0) {
                            moveUp();
                            //休眠50毫秒
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                    break;
                case 1://右

                    for (int i = 0; i < 30; i++) {
                        if (getX() < 902) {
                            moveRight();
                            //休眠50毫秒
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    break;
                case 2://下

                    for (int i = 0; i < 30; i++) {
                        if (getY() < 620) {
                            moveDown();
                            //休眠50毫秒
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    break;
                case 3://左

                    for (int i = 0; i < 30; i++) {
                        if (getX() > 0) {
                            moveLeft();
                            //休眠50毫秒
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    break;
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //随机改变坦克方向0 - 3
            setDirect((int) (Math.random() * 4));
            //如果坦克被击中线程终止
            if (!isLive) {
                break;
            }
        }


    }
}

上一篇:artillery


下一篇:SharePoint 2013 术语和术语集介绍