韩顺平–Java坦克大战

1、说明

  写了14个版本,终于完成了,项目结构如下
在这里插入图片描述

2、游戏效果

在这里插入图片描述
在这里插入图片描述

(1)击中敌人

在这里插入图片描述

(2)被敌人击中

在这里插入图片描述

3、代码如下

(1)TankGame 主方法

package cn.bloghut;

import cn.bloghut.component.MyPanel;
import cn.bloghut.service.Recorder;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;

/**
 * @Classname TankGame
 * @Description TODO
 * @Date 2022/5/8 8:25
 * @Created by 闲言
 */
public class TankGame extends JFrame {

    private MyPanel panel;

    public static void main(String[] args) {

        new TankGame();
    }

    public TankGame(){
        System.out.println("请输入选择: 1 表示新游戏,2是继续上局");
        Scanner scanner = new Scanner(System.in);
        //将panel放入到thread中
        this.panel = new MyPanel(scanner.next());
        scanner.close();

        new Thread(panel).start();
        //设置绑定监听器
        this.addKeyListener(panel);
        this.add(panel);
        //设置窗体关闭
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("闲言-坦克大战");
        //获取当前屏幕分辨率
        int width = Toolkit.getDefaultToolkit().getScreenSize().width;
        int height = Toolkit.getDefaultToolkit().getScreenSize().height;
        //设置窗体大小不可变
        this.setResizable(false);
        //设置窗体位置
        width = (width - 1300) / 2;
        height = (height - 750) / 2;
        this.setBounds(width,height,1300,750);
        this.setBackground(Color.black);
        //设置窗体显示
        this.setVisible(true);

        //在JFrame 中增加相关关闭窗口的处理
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                Recorder.keepRecord();
                System.exit(0);
            }
        });

    }
}

(2)MyPanel 视图

package cn.bloghut.component;

import cn.bloghut.pojo.*;
import cn.bloghut.service.PlayAudio;
import cn.bloghut.service.Recorder;
import cn.bloghut.service.Shot;

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

/**
 * @Classname MyPanel
 * @Description 坦克大战绘图区域
 * 为了让panel 不停的重绘子弹,需要将MyPanel
 * @Date 2022/5/8 8:44
 * @Created by 闲言
 */
public class MyPanel extends JPanel implements KeyListener, Runnable {
    //定义我的坦克
    Hero hero = null;
    //定义敌人坦克
    Vector<EnemyTank> enemyTanks = new Vector<>();
    //用于存放炸弹
    //当子弹击中坦克时,就加入一个bomb 对象
    Vector<Bomb> bombs = new Vector<>();
    //定义三种图片,用于显示炸弹
    Image img1 = null;
    Image img2 = null;
    Image img3 = null;

    //定义一个存放Node 对象的Vector,用于恢复敌人坦克的坐标和放向
    Vector<Node> nodes = null;
    //敌人坦克数量
    int enemyTankSize = 3;
    public MyPanel(String type) {
        //判断记录文件是否存在
        //如果存在就正常执行,如果文件不存在,提示只能开启新的游戏
        File file = new File(Recorder.getRecordFile());
        if (!file.exists()){
            type = "1";
            System.out.println("文件不存在只能开启新游戏");
        }else {
            nodes = Recorder.getNodesAndTanks();
        }

        //初始化我的坦克
        hero = new Hero(150, 150);
        //设置坦克速度
        hero.setSpeed(5);
        switch (type) {
            case "1":
                //初始化敌人坦克
                for (int i = 0; i < enemyTankSize; i++) {
                    EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
                    enemyTank.setDirection(2);
                    //启动敌人坦克线程
                    new Thread(enemyTank).start();
                    //给该enemyTank 加入一颗子弹
                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
                    //加入到
                    enemyTank.getShots().add(shot);
                    //为每个坦克,放入所有的敌人对象
                    enemyTank.setEnemyTanks(enemyTanks);
                    //启动shot
                    new Thread(shot).start();
                    enemyTanks.add(enemyTank);
                }
                break;
            case "2": //继续上局游戏
                //初始化敌人坦克
                for (int i = 0;i < nodes.size();i++){
                    Node node = nodes.get(i);
                    EnemyTank enemyTank = new EnemyTank(node.getX(),node.getY());
                    enemyTank.setDirection(node.getDirection());
                    //启动敌人坦克线程
                    new Thread(enemyTank).start();
                    //给该enemyTank 加入一颗子弹
                    Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
                    //加入到
                    enemyTank.getShots().add(shot);
                    //为每个坦克,放入所有的敌人对象
                    enemyTank.setEnemyTanks(enemyTanks);
                    //启动shot
                    new Thread(shot).start();
                    enemyTanks.add(enemyTank);
                }
                break;
            default:
                System.out.println("你的输入有误");
        }
        //获取项目路径
        //1.获取图片资源
        String parent = System.getProperty("user.dir");
        parent += "\";
        //2.初始化图片
        img1 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_1.gif");
        img2 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_2.gif");
        img3 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_3.gif");
        //存放敌人坦克信息
        Recorder.setEnemyTanks(enemyTanks);
        //播放指定的音乐
        new PlayAudio("bg.wav").start();
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        //填充矩形,默认黑色
        g.fillRect(0, 0, 1000, 750);
        //画出游戏信息
        showInfo(g);
        //画自己坦克
        if (hero != null && hero.isLive()) {
            drawTank(hero.getX(), hero.getY(), g, hero.getDirection(), 1);
        }
        //画出自己射击的子弹
        //不为空,且处于发射状态
        if (hero.getShot() != null && hero.getShot().isLive()) {
            g.draw3DRect(hero.getShot().getX(), hero.getShot().getY(), 2, 2, false);
        }
        if (hero.getShots().size() > 0) {
            for (int i = 0; i < hero.getShots().size(); i++) {
                Shot shot = hero.getShots().get(i);
                if (shot != null && shot.isLive()) {
                    g.draw3DRect(shot.getX(), shot.getY(), 2, 2, false);
                } else {
                    //如果shot对象已经无效,就从子弹集合中移除
                    hero.getShots().remove(shot);
                }
            }
        }

        //画敌人坦克
        for (int i = 0; i < enemyTanks.size(); i++) {
            EnemyTank enemyTank = enemyTanks.get(i);
            //判断当前坦克是否还存活,只有存活的时候才去画
            if (enemyTank.isLive()) {
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 0);
                //绘制敌人坦克子弹
                Vector<Shot> shots = enemyTank.getShots();
                for (int j = 0; j < shots.size(); j++) {
                    Shot shot = shots.get(j);
                    //子弹存活的时候才绘制
                    if (shot.isLive()) {
                        g.draw3DRect(shot.getX(), shot.getY(), 1, 1, false);
                    } else {
                        //子弹出边界了,移除子弹
                        enemyTank.getShots().remove(shot);
                    }
                }
            }
        }
        //如果bombs 集合中有对象,就画出
        for (int i = 0; i < bombs.size(); i++) {
            Bomb bomb = bombs.get(i);
            //根据当前炸弹的life值画出对应的图片
            if (bomb.getLife() > 6) {
                g.drawImage(img1, bomb.getX(), bomb.getY(), 60, 60, this);
            } else if (bomb.getLife() > 3) {
                g.drawImage(img1, bomb.getX(), bomb.getY(), 60, 60, this);
            } else {
                g.drawImage(img1, bomb.getX(), bomb.getY(), 60, 60, this);
            }
            //让这个炸弹的生命值减少
            bomb.lifeDown();
            //如果bomb 生命值为0,就从集合中删除
            if (bomb.getLife() == 0) {
                bombs.remove(bomb);
            }
        }
    }

    /**
     * 显示 击毁敌方的坦克信息
     *
     * @param g 画图
     */
    public void showInfo(Graphics g) {
        g.setColor(Color.BLACK);
        Font font = new Font("宋体", Font.BOLD, 25);
        g.setFont(font);
        g.drawString("您累计击毁敌方坦克", 1020, 30);
        drawTank(1020, 60, g, 0, 0);
        g.setColor(Color.BLACK);
        g.drawString(Recorder.getAllEnemyTankTotal() + "", 1080, 100);
    }

    /**
     * 绘制坦克
     *
     * @param x         坦克的左上角x坐标
     * @param y         坦克的左上角y坐标
     * @param g         画笔
     * @param direction 坦克方向(上下左右)
     * @param type      坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int direction, int type) {
        //根据不同类型的坦克设置不同颜色
        switch (type) {
            case 0://0 敌人的坦克
                g.setColor(Color.cyan);
                break;
            //
            case 1://1 我们的坦克
                g.setColor(Color.yellow);
                break;
        }
        //根据坦克的方向来绘制坦克
        //direction 0-向上,1-向右,2-向下,3-向左
        switch (direction) {
            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) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        //判断用户按下的按键
        if (KeyEvent.VK_W == code) { //向上
            //移动时判断不能重叠
            hero.setDirection(0);
            hero.moveUp();
        } else if (KeyEvent.VK_D == code) { //向右
            hero.setDirection(1);
            hero.moveRight();
        } else if (KeyEvent.VK_S == code) { //向下
            hero.setDirection(2);
            hero.moveDown();
        } else if (KeyEvent.VK_A == code) { //向左
            hero.setDirection(3);
            hero.moveLeft();
        }
        //判断是否是射击
        if (KeyEvent.VK_J == code) {
            //如果为空,说明是第一次发射
            //发送一颗子弹
//            if (hero.getShot() == null || !(hero.getShot().isLive())){
//                hero.shotEnemyTank();
//            }

            //发射多颗子弹
            hero.shotEnemyTank();
        }

        //重绘
        this.repaint();
    }


    //如果我们的坦克可以发射多发子弹
    //在判断我方子弹是否击中敌人坦克时,就需要把我们的子弹集合所有的子弹取出,都取出和敌人的所有坦克进行判断
    //编写方法,判断我方的子弹是否击中敌人坦克

    /**
     * 判断子弹和坦克
     *
     * @param shots 子弹集合
     * @param tank  坦克
     */
    public void hitTank(Vector<Shot> shots, Tank tank) {
        for (int i = 0; i < shots.size(); i++) {
            hitTank(shots.get(i), tank);
        }
    }

    /**
     * 判断子弹和坦克
     *
     * @param s    子弹
     * @param tank 坦克
     */
    public void hitTank(Shot s, Tank tank) {
        switch (tank.getDirection()) {
            case 0://坦克向上
            case 2://坦克向下
                if (s.getX() > tank.getX() && s.getX() < tank.getX() + 40 &&
                        s.getY() > tank.getY() && s.getY() < tank.getY() + 60) {
                    s.setLive(false);
                    tank.setLive(false);
                    //当我的子弹击中敌人坦克后,将enemyTank 坦克从集合中去掉
                    enemyTanks.remove(tank);
                    //当我方击毁一辆敌方坦克时,就对一个值++(前提不是我放坦克)
                    if (!(tank instanceof Hero)) {
                        Recorder.addlEnemyTankTotal();
                    }
                    //创建bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(tank.getX(), tank.getY());
                    bombs.add(bomb);
                }
                break;
            case 1://坦克向右
            case 3://坦克向左
                if (s.getX() > tank.getX() && s.getX() < tank.getX() + 60 &&
                        s.getY() > tank.getY() && s.getY() < tank.getY() + 40) {
                    s.setLive(false);
                    tank.setLive(false);
                    //打我的子弹击中敌人坦克后,将enemyTank 坦克从集合中去掉
                    enemyTanks.remove(tank);
                    //当我方击毁一辆敌方坦克时,就对一个值++(前提不是我放坦克)
                    if (!(tank instanceof Hero)) {
                        Recorder.addlEnemyTankTotal();
                    }
                    //创建bomb对象,加入到bombs集合
                    Bomb bomb = new Bomb(tank.getX(), tank.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void run() {
        //每隔100毫秒,重绘区域
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //判断是否击中敌人坦克
            hitEnemy();
            //判断敌人坦克是否击中我们
            hitHero();
            this.repaint();
        }
    }

    /**
     * 判断是否击中敌人坦克
     */
    public void hitEnemy() {
        if (hero.getShot() != null && hero.getShot().isLive()) {
            //遍历敌人所有的坦克
            for (int i = 0; i < enemyTanks.size(); i++) {
                EnemyTank enemyTank = enemyTanks.get(i);
                //发射单个子弹
//                    hitTank(hero.getShot(),enemyTank);
                //发射多颗子弹
                hitTank(hero.getShots(), enemyTank);
            }
        }
    }

    /**
     * 判断敌人坦克是否击中
     */
    public void hitHero() {
        if (enemyTanks.size() > 0) {
            //拿到所有敌人的坦克-下的子弹,判断是否重合如果重合则显示爆炸
            for (int i = 0; i < enemyTanks.size(); i++) {
                EnemyTank enemyTank = enemyTanks.get(i);
                //判断是否击中
                //敌人的子弹
                Vector<Shot> shots = enemyTank.getShots();
                if (shots.size() > 0) {
                    for (int j = 0; j < shots.size(); j++) {
                        Shot shot = shots.get(j);
                        if (hero.isLive() && shot.isLive()) {
                            //判断子弹和坦克是否重合
                            hitTank(shots, hero);
                        }
                    }
                }
            }
        }
    }
}

(3)Bomb 爆炸类

package cn.bloghut.pojo;

/**
 * @Classname Bomb
 * @Description TODO
 * @Date 2022/5/8 16:18
 * @Created by 闲言
 */
public class Bomb {
    private int x,y;//炸弹坐标
    private int life = 9;//炸弹生命周期
    private  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;
        }
    }

    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 getLife() {
        return life;
    }

    public void setLife(int life) {
        this.life = life;
    }

    public boolean isLive() {
        return isLive;
    }

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

(4)EnemyTank 敌方坦克类

package cn.bloghut.pojo;

import cn.bloghut.service.Shot;

import java.util.Vector;

/**
 * @Classname EnemyTank
 * @Description TODO
 * @Date 2022/5/8 11:06
 * @Created by 闲言
 */
@SuppressWarnings("All")
public class EnemyTank extends Tank implements Runnable {
    //在敌人坦克类,保存多个shot
    private Vector<Shot> shots = new Vector<>();
    //敌人坦克 可以得到敌人坦克的Vector
    //1.EnemyTank 在mypanel里面
    private Vector<EnemyTank> enemyTanks = new Vector<>();

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

    public Vector<Shot> getShots() {
        return shots;
    }

    public void setShots(Vector<Shot> shots) {
        this.shots = shots;
    }

    public Vector<EnemyTank> getEnemyTanks() {
        return enemyTanks;
    }

    /**
     * 提供一个方法,可以将mypanel 的成员 Vector<EnemyTank> enemyTanks = new Vector<>();
     * 设置到  private Vector<EnemyTank> enemyTanks = new Vector<>();
     * @param enemyTanks 敌人坦克集合
     */
    public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
        this.enemyTanks = enemyTanks;
    }

    //编写方法,判断当前的敌人坦克,是否和 enemyTanks 中2的 其他坦克发生了重叠 或者是碰撞
    public boolean isTouchEnemyTank(){
        //判断当前敌人坦克(this) 方向
        switch (this.getDirection()){
            case 0: //上
                //让当前的this 敌人坦克 和 其他所有的敌人坦克比较
                for (int i = 0;i< enemyTanks.size();i++){
                    //从vector中取出一辆敌人的坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (this != enemyTank){
                        /*
                        1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
                                                y的范围是什么【enemyTank.getY() ,enemyTank.getY() + 60】
                         */
                        if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
                            //2.当前坦克的左上角坐标【this.getX(),this.getY()】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40 &&
                                this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 60){
                                return true;
                            }
                            //3.当前坦克的右上角坐标【this.getX() + 40,this.getY()】
                            if (this.getX() + 40 >= enemyTank.getX() && this.getX()  + 40 <= enemyTank.getX() + 60 &&
                                    this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40){
                                return true;
                            }
                        }
                        /*
                        1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 60】
                                                y的范围是什么【enemyTank.getY() ,enemyTank.getY() + 40】
                         */
                        //如果敌人坦克是左/右方向
                        if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){
                            //2.当前坦克的左上角坐标【this.getX(),this.getY()】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60 &&
                                    this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40){
                                return true;
                            }
                            //3.当前坦克的右上角坐标【this.getX() + 40,this.getY()】
                            if (this.getX() + 40 >= enemyTank.getX() && this.getX()  + 40 <= enemyTank.getX() + 60 &&
                                    this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40){
                                return true;
                            }
                        }
                    }
                }
                break;
            case 1: //右
                //让当前的this 敌人坦克 和 其他所有的敌人坦克比较
                for (int i = 0;i< enemyTanks.size();i++){
                    //从vector中取出一辆敌人的坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (this != enemyTank){
                        /*
                        1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
                                                y的范围是什么【enemyTank.getY(),enemyTank.getY()  + 40】
                         */
                        if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
                            //2.当前坦克的右上角坐标【this.getX() + 60,this.getY()】
                            if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 40 &&
                                    this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 60){
                                return true;
                            }
                            //3.当前坦克的右下角坐标【this.getX() + 60,this.getY() + 40】
                            if (this.getX() + 60 >= enemyTank.getX() && this.getX()  + 60 <= enemyTank.getX() + 40 &&
                                    this.getY() + 40 >= enemyTank.getY() && this.getY()  + 40 <= enemyTank.getY() + 60){
                                return true;
                            }
                        }
                        /*
                        1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX(),enemyTank.getX() + 60】
                                                y的范围是什么【enemyTank.getY(),enemyTank.getX() + 40】
                         */
                        //如果敌人坦克是左/右方向
                        if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){
                            //2.当前坦克的右上角坐标【this.getX() + 60,this.getY()】
                            if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 60 &&
                                    this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40){
                                return true;
                            }
                            //3.当前坦克的右下角坐标【this.getX() + 60,this.getY()  + 40】
                            if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 60 &&
                                    this.getY() + 40 >= enemyTank.getY() && this.getY() + 40 <= enemyTank.getY() + 40){
                                return true;
                            }
                        }
                    }
                }
                break;
            case 2: //下
                //让当前的this 敌人坦克 和 其他所有的敌人坦克比较
                for (int i = 0;i< enemyTanks.size();i++){
                    //从vector中取出一辆敌人的坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (this != enemyTank){
                        /*
                        1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
                                                y的范围是什么【enemyTank.getY(),enemyTank.getY()  + 60】
                         */
                        if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
                            //2.当前坦克的左下角坐标【this.getX(),this.getY() + 60】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40 &&
                                    this.getY() + 60 >= enemyTank.getY() && this.getY() + 60 <= enemyTank.getY() + 60){
                                return true;
                            }
                            //3.当前坦克的右下角坐标【this.getX() + 40,this.getY() + 60】
                            if (this.getX() + 40 >= enemyTank.getX() && this.getX()  + 40 <= enemyTank.getX() + 40 &&
                                    this.getY() + 60 >= enemyTank.getY() && this.getY()  + 60 <= enemyTank.getY() + 60){
                                return true;
                            }
                        }
                        /*
                        1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX(),enemyTank.getX() + 60】
                                                y的范围是什么【enemyTank.getY(),enemyTank.getX() + 40】
                         */
                        //如果敌人坦克是左/右方向
                        if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){
                            //2.当前坦克的左下角坐标【this.getX(),this.getY() + 60】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60 &&
                                this.getY() + 60 >= enemyTank.getY() && this.getY() + 60 <= enemyTank.getY() + 40){
                                return true;
                            }
                            //3.当前坦克的右下角坐标【this.getX() + 40,this.getY() + 60】
                            if (this.getX() + 40 >= enemyTank.getX() && this.getX()  + 40 <= enemyTank.getX() + 60 &&
                                this.getY() + 60 >= enemyTank.getY() && this.getY()  + 60 <= enemyTank.getY() + 40){
                                return true;
                            }
                        }
                    }
                }
                break;
            case 3: //左
                //让当前的this 敌人坦克 和 其他所有的敌人坦克比较
                for (int i = 0;i< enemyTanks.size();i++){
                    //从vector中取出一辆敌人的坦克
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //不和自己比较
                    if (this != enemyTank){
                        /*
                        1.如果敌人坦克是上/下方向   x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
                                                y的范围是什么【enemyTank.getY(),enemyTank.getY()  + 60】
                         */
                        if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
                            //2.当前坦克的左上角坐标【this.getX(),this.getY()】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40 &&
                                    this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 60){
                                return true;
                            }
                            //3.当前坦克的左下角坐标【this.getX(),this.getY() + 40】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40 &&
                                    this.getY() + 40 >= enemyTank.getY() && this.getY()  + 40 <= enemyTank.getY() + 60){
                                return true;
                            }
                        }
                        /*
                        1.如果敌人坦克是左/右方向   x的范围是什么【enemyTank.getX(),enemyTank.getX() + 60】
                                                y的范围是什么【enemyTank.getY(),enemyTank.getX() + 40】
                         */
                        //如果敌人坦克是左/右方向
                        if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 3){
                            //2.当前坦克的左上角坐标【this.getX(),this.getY()】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60 &&
                                    this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40){
                                return true;
                            }
                            //3.当前坦克的左下角坐标【this.getX(),this.getY() + 40】
                            if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 60 &&
                                    this.getY() + 40 >= enemyTank.getY() && this.getY()  + 40 <= enemyTank.getY() + 40){
                                return true;
                            }
                        }
                    }
                }
                break;
        }
        return false;
    }

    @Override
    public void run() {
        while (true) {
            //这里我们判断如果shots size() == 0,创建一颗子弹,放入到shots集合,并启动
            if (isLive() && shots.size() < 3) {
                Shot s = null;
                //判断坦克的方向,创建对应的子弹
                switch (getDirection()) {
                    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();
            }
            //当前坦克的方向来继续移动
            for (int i = 0; i < 30; i++) {
                switch (getDirection()) {
                    case 0://向上
                        if (getY() > 0 && !isTouchEnemyTank()){
                            moveUp();
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        break;
                    case 1://向右
                        if (getX() + 60 < 1000  && !isTouchEnemyTank()){
                            moveRight();
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        break;
                    case 2://向下
                        if (getY() + 60 < 722  && !isTouchEnemyTank()){
                            moveDown();
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        break;
                    case 3://向左
                        if (getX() > 0  && !isTouchEnemyTank()){
                            moveLeft();
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        break;
                }
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //然后随机的改变方向
            int direction = (int) (Math.random() * 4);
            setDirection(direction);

            //一旦写并发程序,一定要考虑清楚该线程什么时候结束
            //被子弹打中了,结束线程
            if (!isLive()) {
                break;
            }
        }
    }
}

(5)Hero 我方坦克类

package cn.bloghut.pojo;

import cn.bloghut.service.Shot;

import java.util.Vector;

/**
 * @Classname Hero
 * @Description 自己坦克
 * @Date 2022/5/8 8:43
 * @Created by 闲言
 */
public class Hero extends Tank{
    //定义一个shot对象,表示射击行为
    private Shot shot = null;
    //可以发射多颗子弹
    private Vector<Shot> shots = new Vector<>();

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

    //射击
    public void shotEnemyTank(){

        //控制面板上子弹数量
        if (shots.size() >= 5){
            return;
        }

        //创建short对象,根据当前hero对象的位置方向来创建shot对象
        switch (getDirection()){
            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;
        }
        //把进创建的short放到集合中
        shots.add(shot);
        //启动shot线程
        new Thread(shot).start();
    }

    public Vector<Shot> getShots() {
        return shots;
    }

    public void setShots(Vector<Shot> shots) {
        this.shots = shots;
    }

    public Shot getShot() {
        return shot;
    }

    public void setShot(Shot shot) {
        this.shot = shot;
    }
}

(6)Node 记录敌方坦克类(继续上局游戏用)

package cn.bloghut.pojo;

/**
 * @Classname Node
 * @Description 一个node 对象,表示一个敌人坦克的信息
 * @Date 2022/5/9 10:47
 * @Created by 闲言
 */
public class Node {
    private int x;
    private int y;
    private int direction;

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

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

(7)Tank 坦克父类

package cn.bloghut.pojo;

/**
 * @Classname Tank
 * @Description 坦克实体
 * @Date 2022/5/8 8:43
 * @Created by 闲言
 */
public class Tank {
    private int x;
    private int y;
    private int direction;///坦克方向0-上 1-右 2-下 3-左
    private int speed = 1;//坦克速度
    private boolean isLive = true;

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

    public int getDirection() {
        return direction;
    }

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

    //上下左右移动方法
    public void moveUp(){
        //坦克不能出边界
        if (y > 0){
            y-=speed;
        }
    }
    public void moveRight(){
        if (x + 60 < 1000){
            x+=speed;
        }
    }
    public void moveDown(){
        if (y + 60 < 722){
            y+=speed;
        }
    }
    public void moveLeft(){
        if (x > 0){
            x-=speed;
        }
    }

    public boolean isLive() {
        return isLive;
    }

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

    public int getSpeed() {
        return speed;
    }

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

(8)PlayAudio 播放背景音乐类

package cn.bloghut.service;

import javax.sound.sampled.*;
import java.io.*;

/**
 * @author ajun
 * Date 2021/7/16
 * @version 1.0
 * 播放音乐
 */
public class PlayAudio extends Thread {

    private String filename;

    public PlayAudio(String wavfile) {
        String path = System.getProperty("user.dir");
        filename = path+"\"+wavfile;
    }

    @Override
    public void run() {
        // 从项目资源目录下加载背景音乐
        AudioInputStream audioInputStream = null;
        try {
            audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(filename)));
        } catch (Exception e1) {
            e1.printStackTrace();
            return;
        }

        AudioFormat format = audioInputStream.getFormat();
        SourceDataLine auline = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        try {
            auline = (SourceDataLine) AudioSystem.getLine(info);
            auline.open(format);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        auline.start();
        int nBytesRead = 0;
        //缓存
        byte[] abData = new byte[512];

        try {
            while (nBytesRead != -1) {
                nBytesRead = audioInputStream.read(abData, 0, abData.length);
                if (nBytesRead >= 0)
                    auline.write(abData, 0, nBytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } finally {
            auline.drain();
            auline.close();
        }
    }
}

(9)Recorder 记录游戏数据类

package cn.bloghut.service;

import cn.bloghut.pojo.EnemyTank;
import cn.bloghut.pojo.Node;

import java.io.*;
import java.util.Vector;

/**
 * @Classname Recorder
 * @Description 用于记录
 * @Date 2022/5/9 10:00
 * @Created by 闲言
 */
public class Recorder {
    //定义变量,记录我方击毁敌人坦克数量
    private static int allEnemyTankTotal = 0;
    //定义IO 对象,准备写数据到文件中
    private static BufferedWriter bufferedWriter = null;
    private static BufferedReader bufferedReader = null;
    private static String recordFile;
    //存储敌人坦克
    private static Vector<EnemyTank> enemyTanks = null;
    //定义一个Node 的Vector ,用于保存敌人的信息node
    private static Vector<Node> nodes = new Vector<>();
    static {
        String parentPath = System.getProperty("user.dir");
        recordFile = parentPath + "\record.txt";
    }

    /**
     *  该方法在继续上局时调用
     *  用于读取record.txt 文件,恢复相关信息
     * @return 敌人坦克信息
     */
    public static Vector<Node> getNodesAndTanks(){
        try {
            bufferedReader = new BufferedReader(new FileReader(recordFile));
            //击毁数量
            allEnemyTankTotal = Integer.parseInt(bufferedReader.readLine());
            //获取敌人坦克信息
            String dataLine = "";
            while ((dataLine = bufferedReader.readLine()) != null){
                String[] split = dataLine.split(" ");
                if (split.length == 3){
                    Node node = new Node(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
                    nodes.add(node);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (bufferedReader != null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return nodes;
    }

    public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
        Recorder.enemyTanks = enemyTanks;
    }

    public static int getAllEnemyTankTotal() {
        return allEnemyTankTotal;
    }

    public static void setAllEnemyTankTotal(int allEnemyTankTotal) {
        Recorder.allEnemyTankTotal = allEnemyTankTotal;
    }

    /**
     * 当我方坦克击毁一辆敌人坦克,就应当对这个值++
     */
    public static void addlEnemyTankTotal(){
        allEnemyTankTotal++ ;
    }
    /**
     * 当游戏退出时,我们将 allEnemyTankTotal 保存到
     */
    public static void keepRecord(){
        try {
            bufferedWriter = new BufferedWriter(new FileWriter(recordFile));
            bufferedWriter.write(allEnemyTankTotal+"rn");
            //变量敌人坦克集合,然后根据情况保存
            //OOP 编程思想,定义一个属性,通过SET 方法得到敌人的坦克集合
            if (enemyTanks.size() > 0){
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    //为了保险,判断一下是否存活
                    if (enemyTank.isLive()){
                        //保存enemy坦克信息
                        String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirection();
                        bufferedWriter.write(record);
                        bufferedWriter.newLine();
                    }
                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (bufferedWriter != null){
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static String getRecordFile() {
        return recordFile;
    }

    public static void setRecordFile(String recordFile) {
        Recorder.recordFile = recordFile;
    }
}

(10)Shot 子弹类

package cn.bloghut.service;

/**
 * @Classname Shot
 * @Description TODO
 * @Date 2022/5/8 14:15
 * @Created by 闲言
 */
public class Shot implements Runnable{
    private int x;//子弹x坐标
    private int y;//子弹x坐标
    private int direction = 0;//子弹方向
    private int speed = 2;//子弹速度
    private boolean isLive = true; //子弹是否还存活

    @Override
    public void run() {//射击行为
        while (true){
            //线程休眠 50 毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //根据方向来改变x ,y坐标
            switch (direction){
                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;
                System.out.println("子弹线程退出");
                break;
            }

        }
    }

    //构造子弹
    public Shot(int x, int y, int direction) {
        this.x = x;
        this.y = y;
        this.direction = direction;
    }

    public boolean isLive() {
        return isLive;
    }

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

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

    @Override
    public String toString() {
        return "Shot{" +
                "x=" + x +
                ", y=" + y +
                ", direction=" + direction +
                ", speed=" + speed +
                ", isLive=" + isLive +
                '}';
    }
}


   注意:本工程是模块化进行开发的,所以一些文件(
图片、存档路径、音乐)的路径需要改成自己对应。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>