java实现坦克大战

 初学者必学的一个小项目,通过编写坦克大战能体会面向对象(oop)的精妙之处,同时也能理解集合,多线程,io流,GUI编程等知识的运用,是一个很好的一个学习体验。

这里先放图给大家看看实际运行出来的效果,先开始游戏

然后我们击败了两个坦克,并记录在游戏中,下次可以继续上局游戏 

 

 这里把源码分享给大家,可以自由修改坦克属性,变成地狱难度,挑战自己!

首先是 主方法  实现画框等设置和游戏的响应

package com.tankgame;

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

public class TankGameShot extends JFrame  {
    MyPanel mp = null;
    static Scanner scanner = new Scanner(System.in);
    public static void main(String[] args) { //主方法
        new TankGameShot();
        //调用构造器
    }
    //构造器
    public TankGameShot(){  //设置画框
        System.out.println("请输入选择 1:新游戏 2:继续上局");
        String key = scanner.next();
        mp=new MyPanel(key);
       //将mp放入到Thread中实现代理模式启动线程
        Thread thread = new Thread(mp);
        thread.start(); //启动重汇界面线程
        this.add(mp);  //将画板加到画框里
        // 窗口JFrame,可以把对象(画板)传入监听器中实现监听面板事件
        this.addKeyListener(mp);
       this.setSize(1300,750); //定义画框的大小
       this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗口关闭后退出程序
       this.setVisible(true);  //设置能显示

        //添加键盘响应事件
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                Recorder.keepRecorder(); //将数据保存并退出
                System.exit(0);
            }
        });
    }
}

画笔类 用于实现坦克和子弹的绘制

package com.tankgame;

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

public class MyPanel extends JPanel implements KeyListener,Runnable { //这里实现线程接口启动第二个线程repaint(一直刷新界面)
    //定义我的坦克
    Hero hero = null;
    //将敌人坦克加入集合中,vector可以避免多线程问题
    Vector<EnemyTank> enemyTanks = new Vector<>();
    //定义一个存放node 对象的vector,用于恢复敌人坦克的坐标和方向
    Vector<Node> nodes=null;
    //敌人坦克数量
    int enemyTankSize = 6;

    //定义vector用于存放炸弹(当子弹击中坦克时就加入一个Bomb对象)
    Vector<Bomb> bombs = new Vector<>();
    //定义这三张图片,显示爆炸效果
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    //初始化自己的坦克
    public MyPanel(String key) {  //构造器
        //将MyPanel的enemyTanks集合传给 Recorder的enemyTanks
        Recorder.setEnemyTanks(enemyTanks);
        hero = new Hero(100, 500);
        hero.setSpeed(5); //定义坦克移动速度

        //判断记录文件是否存在
        File file = new File(Recorder.getRecorderFile());
        if (!file.exists()){
            key="1";
            System.out.println("文件不存在,只能开启新游戏");
        }else { //如果存在则可以继续游戏
            nodes = Recorder.getNodeAndEnemyTankRec(); //将敌人剩余坦克信息传给nodes集合
        }
        switch (key) {
            case "1":
                //初始化敌人坦克
                Recorder.setAllEnemyTankNum(0);
                for (int i = 0; i < enemyTankSize; i++) {
                    EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
                    //将vector集合传给enemyTank对象
                    enemyTank.setEnemyTanks(enemyTanks);
                    enemyTank.setDirect(2); //设置坦克的炮筒向下
                    //启动坦克线程让它动起来
                    new Thread(enemyTank).start();
                    //给坦克加入子弹
                    shot shot = new shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
                    //加入shot成员
                    enemyTank.shots.add(shot);
                    //启动shot线程
                    new Thread(shot).start();
                    //加入集合里
                    enemyTanks.add(enemyTank);
                }
                break;
            case "2":
                //初始化敌人坦克
                    for (Node node : nodes) {
                        EnemyTank enemyTank = new EnemyTank(node.getX(), node.getY());
                        //将vector集合传给enemyTank对象
                        enemyTank.setEnemyTanks(enemyTanks);
                        enemyTank.setDirect(node.getDirect()); //设置坦克的炮筒向下
                        //启动坦克线程让它动起来
                        new Thread(enemyTank).start();
                        //给坦克加入子弹
                        shot shot = new shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
                        //加入shot成员
                        enemyTank.shots.add(shot);
                        //启动shot线程
                        new Thread(shot).start();
                        //加入集合里
                        enemyTanks.add(enemyTank);
                    }
                    break;
            default:
                System.out.println("输入有误");
        }

        //在构造器中初始化图片对象
        image1 = Toolkit.getDefaultToolkit().getImage(MyPanel.class.getResource("/bg1.png"));
        image2 = Toolkit.getDefaultToolkit().getImage(MyPanel.class.getResource("/bg2.png"));
        image3 = Toolkit.getDefaultToolkit().getImage(MyPanel.class.getResource("/bg3.png"));
        //播放指定的音乐
        new AePlayWave("d://坦克大战//src//good.wav").start();
    }
    //记录击败坦克信息
    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,50,g,0,0); //画出敌人的一个坦克
        g.setColor(Color.black); //重置画笔颜色
        g.drawString(Recorder.getAllEnemyTankNum()+"",1080,100);
    }
    @Override
    public void paint(Graphics g) { //生成画笔(画板)
        super.paint(g);
        g.fillRect(0, 0, 1000, 750); //填充矩形画板(当背景,默认黑色)
        showInfo(g); //调用击败坦克界面
        //画出自己的坦克
        if (hero.alive) {
            drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
        }
        //画出hero坦克射击的子弹
            for (int i = 0; i < hero.shots.size(); i++) { //遍历子弹集合
                shot shot = hero.shots.get(i); //取出子弹
                if (shot != null && shot.alive) {
                    g.draw3DRect(shot.x, shot.y, 2, 2, false);
                } else { //如果子弹以及销毁就要把它从集合拿掉
                    hero.shots.remove(shot);
                }
            }
        //画出爆炸效果,取出集合的对象
        for (int i = 0; i < bombs.size(); i++) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //取出炸弹
            Bomb bomb = bombs.get(i);
            if (bomb.life > 6) {
                g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);
            } else if (bomb.life > 3) {
                g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);
            } else {
                g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);
            }
            //让炸弹生命值减少实现动态
            bomb.LifeDown();
            //如果bomb为0则将其从集合移除
            if (bomb.life == 0) {
                bombs.remove(bomb);
            }
        }

        //画出敌人坦克
        for (int i = 0; i < enemyTanks.size(); i++) { //遍历敌人坦克、
            //取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            //判断坦克是否存活
            if (enemyTank.alive) { //如果true则画
                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
                //画出所有坦克的子弹(遍历子弹的vector)
                for (int j = 0; j < enemyTank.shots.size(); j++) {
                    //取出子弹
                    shot shot = enemyTank.shots.get(j);
                    //绘制
                    if (shot.alive) {
                        g.draw3DRect(shot.x, shot.y, 1, 1, false);
                    } else {
                        //从vector移除
                        enemyTank.shots.remove(shot);
                    }
                }
            }
        }
    }

    //有字符输出会触发
    @Override
    public void keyTyped(KeyEvent e) {

    }

    //当某个键被按下,会触发
    @Override
    public void keyPressed(KeyEvent e) {

        //根据用户不同的键来使坦克移动
        if (e.getKeyCode() == KeyEvent.VK_W) { //向上
            //改变坦克方向
            hero.setDirect(0);
            //调用hero的移动方法
            hero.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {
            hero.setDirect(2);
            hero.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
            hero.setDirect(3);
            hero.moveLift();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {
            hero.setDirect(1);
            hero.moveRight();
        }
        //如果按下J就发射子弹即调用shotEnemyTank方法
        if (e.getKeyCode() == KeyEvent.VK_J) {
            //发射一颗子弹情况
            //判断子弹是否销毁
            //if (hero.shot==null || !hero.shot.alive) {
            //这里null为第一次射击为空则创建对象发射,但随着线程销毁后,无法继续发射了,因为对象已经创建,而且不会随着线程结束而销毁
            //因此需要另一个判断条件判断子弹的生命是否为假(即线程是否被销毁)这样就可以继续发子弹,并且保证子弹销毁前只能发射一个
            //hero.showEnemyTank();
            //发射多颗子弹情况
            hero.showEnemyTank();
        }
            //让面板重绘
            this.repaint();
    }
    //当某个键松开会触发
    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //通过线程来同时判断子弹是否击中坦克
            hitEnemyTank();
            hitHero();
            //线程重绘实现动态
            this.repaint();
        }
    }

    //将子弹和坦克从集合拿出来依次比较是否击中
    public void hitEnemyTank() {
        //遍历我们的子弹
        for (int j = 0; j < hero.shots.size(); j++) {
           shot shot =  hero.shots.get(j);  //取出子弹
            if (shot != null && shot.alive) { //当我的子弹还存活且不为空
                //遍历敌人所有的坦克
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    hitTank(shot, enemyTank); //遍历坦克后调用方法
                }
            }
        }
    }

    //判断我方坦克是否被击中
    public void hitHero() {
        //遍历敌人坦克和所有的子弹
        for (int i = 0; i < enemyTanks.size(); i++) {
            EnemyTank enemyTank = enemyTanks.get(i);//取出敌人坦克
            for (int j = 0; j < enemyTank.shots.size(); j++) {
                shot shot = enemyTank.shots.get(j); //取出每个坦克的子弹
                //判断敌人子弹是否击中我的坦克
                if (hero.alive && shot.alive) {
                    hitTank(shot,hero);
                }
            }
        }
    }

    public  void hitTank(shot s,Tank enemyTank){
        //判断s击中坦克
        switch (enemyTank.getDirect()){
            //上和下坦克xy范围一致
            case 0: //上
            case 2: //下
                if (s.x>enemyTank.getX()&&s.x<enemyTank.getX()+40
                        &&s.y>enemyTank.getY()&&s.y<enemyTank.getY()+60){
                    s.alive=false;
                    enemyTank.alive=false;
                    //如果击中将其从集合里移除
                    enemyTanks.remove(enemyTank);
                    //如果我方坦克击毁敌方坦克就将allEnemyTankNum加1,但此时要向下转型来判断
                    if (enemyTank instanceof EnemyTank){
                        Recorder.addallEnemyTankNum(); //调用静态方法
                    }
                    //爆炸效果是随坦克被击中时产生,因此在这里new一个Bomb对象将其加入到集合里
                    Bomb bomb = new Bomb(enemyTank.getX(),enemyTank.getY()); //获取此时坦克坐标
                    bombs.add(bomb); //把对象加入集合里
                }
                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.alive=false;
                     enemyTank.alive=false;
                    //如果击中将其从集合里移除
                    enemyTanks.remove(enemyTank);
                    //如果我方坦克击毁敌方坦克就将allEnemyTankNum加1,但此时要向下转型来判断
                    if (enemyTank instanceof EnemyTank){
                        Recorder.addallEnemyTankNum(); //调用静态方法
                    }
                    Bomb bomb = new Bomb(enemyTank.getX(),enemyTank.getY()); //获取此时坦克坐标
                    bombs.add(bomb); //把对象加入集合里
                }
                break;
        }
    }

    public void  peng(Tank tank){
        switch (tank.getDirect()){
            //获取坦克方向
        }
    }
    /**
     * 坦克属性
     * @param x 横坐标
     * @param y 纵坐标
     * @param g 画笔
     * @param direct 移动方向
     * @param type 敌我类型
     */
    //坦克绘制方法
    public void drawTank(int x,int y,Graphics g,int direct,int type){
        switch (type){ //给坦克设置颜色
            case 0:  //敌人的坦克
                 g.setColor(Color.cyan); //青色
                break;
            case 1://我们的坦克
                 g.setColor(Color.yellow);
                break;
        }
        //通过改变direct来控制坦克方向,我们规定 (0:向上 1:向右 2:向下 3:向左)
        switch (direct){//根据坦克方向来绘制坦克
            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("没有处理");
        }
    }
}

 坦克父类 定义基本的属性,速度,方向,移动等

package com.tankgame;

public class Tank {
    //私有变量需要提供getter和setter方法
    private int x;
    private int y;
    private int direct;  //0:向上 1:向右 2:向下 3:向左\
    private int speed=1; //坦克速度初始化为1
    boolean alive =true;
    //让坦克移动的方法(通过改变x,y的值来实现)
    public void moveUp(){ //上
        if (y>0) { //如果y大于0则继续移动
            y -= speed;
        }
    }
    public void moveRight(){
        if (x+80<1000) { //这里加60是算入坦克自身长度因为坐标的定义是在左上角,小于1000是车头(x+60)小于右边边界
            x += speed;
        }
    }
    public void moveDown(){
        if (y+105<750) {
            y += speed;
        }
    }
    public void moveLift(){
        if (x>0) {
            x -= speed;
        }
    }
    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getSpeed() {
        return speed;
    }

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

    public int getDirect() {
        return direct;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

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

我的坦克类 继承父类,并实现射击方法

package com.tankgame;

import java.util.Vector;

public class Hero extends Tank {  //此类继承了Tank类可以使用其所有的公有方法
     shot shot=null; //定义子弹对象(线程)
    //将子弹加入集合里实现连续发射
    Vector<shot> shots = new Vector<>();
    public Hero(int x, int y) {
        super(x, y);
    }
    //提供一个子弹射击的方法
    public void showEnemyTank(){
        //规定子弹发射数量直到销毁为止
        if (shots.size()==10){
            return;
        }
        //根据hero对象的位置和方向来创建shot对象
        switch (getDirect()){
            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;
        }
        //把新创建的shot放入到集合里
        shots.add(shot);
        //启动shot线程
        Thread thread = new Thread(shot);
        thread.start();
    }
}

敌人坦克类 继承父类,实现了坦克射击和自由移动方法

package com.tankgame;

import java.util.Vector;

import static java.lang.Thread.sleep;

public class EnemyTank extends Tank implements Runnable{ //实现线程接口让坦克动起来
    //在敌人坦克类中使用vector保存多个shot线程
    Vector <shot> shots=new Vector<>();
    //新增属性用来获取敌人坦克的vector
    Vector<EnemyTank> enemyTanks = new Vector<>();
    public boolean alive=true; //生命力
    public EnemyTank(int x, int y) {
        super(x, y);
    }
    //把myPanel的vector成员传入到EnemyTank的enemyTanks中
    public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
        this.enemyTanks = enemyTanks;
    }
    //编写方法判断vector里坦克是否接触
    public boolean isTouchEnemyTank() {

        //根据当前坦克方向来判断
        switch (this.getDirect()) {
            case 0: //上
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);//将一个坦克对象取出,并依次与其他坦克坐标比较
                    if (enemyTank != this) {
                        //如果是比较的敌人坦克是上下
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //当前坦克的左上坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
                                return true;
                            }
                            //当前坦克右上坐标
                            if (this.getX() + 40 >= enemyTank.getX() &&
                                    this.getX() + 40 <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
                                return true;
                            }
                        }
                        //如果敌人坦克是左右
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //当前坦克的左上坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
                                return true;
                            }
                            //当前坦克右上坐标
                            if (this.getX() + 40 >= enemyTank.getX() &&
                                    this.getX() + 40 <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
                                return true;
                            }
                        }
                    }
                }
            case 1: //右
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);//将一个坦克对象取出,并依次与其他坦克坐标比较
                    if (enemyTank != this) {
                        //如果是比较的敌人坦克是上下
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //当前坦克的右上坐标
                            if (this.getX() + 60 >= enemyTank.getX() &&
                                    this.getX() + 60 <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
                                return true;
                            }
                            //当前坦克右下坐标
                            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;
                            }
                        }
                        //如果敌人坦克是左右
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //当前坦克的右上坐标
                            if (this.getX() + 60 >= enemyTank.getX() &&
                                    this.getX() + 60 <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
                                return true;
                            }
                            //当前坦克右下坐标
                            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;
                            }
                        }
                    }
                }
            case 2: //下
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);//将一个坦克对象取出,并依次与其他坦克坐标比较
                    if (enemyTank != this) {
                        //如果是比较的敌人坦克是上下
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //当前坦克的左下坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 40
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 60) {
                                return true;
                            }
                            //当前坦克右下坐标
                            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;
                            }
                        }
                        //如果敌人坦克是左右
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //当前坦克的左下坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 60
                                    && this.getY() + 60 >= enemyTank.getY()
                                    && this.getY() + 60 <= enemyTank.getY() + 40) {
                                return true;
                            }
                            //当前坦克右下坐标
                            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;
                            }
                        }
                    }
                }
            case 3: //左
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);//将一个坦克对象取出,并依次与其他坦克坐标比较
                    if (enemyTank != this) {
                        //如果是比较的敌人坦克是上下
                        if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
                            //当前坦克的左上坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 40
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 60) {
                                return true;
                            }
                            //当前坦克左下坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 40
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 60) {
                                return true;
                            }
                        }
                        //如果敌人坦克是左右
                        if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
                            //当前坦克的左上坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 60
                                    && this.getY() >= enemyTank.getY()
                                    && this.getY() <= enemyTank.getY() + 40) {
                                return true;
                            }
                            //当前坦克左下坐标
                            if (this.getX() >= enemyTank.getX() &&
                                    this.getX() <= enemyTank.getX() + 60
                                    && this.getY() + 40 >= enemyTank.getY()
                                    && this.getY() + 40 <= enemyTank.getY() + 40) {
                                return true;
                            }
                        }
                    }
                }
        }
        //如果上述都没满足则没碰撞
        return false;
    }
    @Override
    public void run() {
        while (true) {
            //判断敌方坦克子弹是否为零如果没有则创建一个子弹并放入集合中
            if (alive&&shots.size()<5){
                shot s =null;
                //判断坦克方向并创建相应的子弹
                switch (getDirect()){
                    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();
            }
            //根据坦克方向来移动
                switch (getDirect()) {
                    case 0:
                            //让坦克保持在一个方向时多走几步
                            for (int i = 0; i < 30; i++) {
                                //如果坦克没有碰撞则继续走
                                if (!isTouchEnemyTank()) {
                                    moveUp();
                                }
                                try {
                                    Thread.sleep(50); //每次要休眠
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        break; //让一个坦克走完防止坦克之间穿透
                    case 1:
                            for (int i = 0; i < 30; i++) {
                                if (!isTouchEnemyTank()) {
                                    moveRight();
                                }
                                try {
                                    Thread.sleep(50);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        break;
                    case 2:
                            for (int i = 0; i < 30; i++) {
                                if (!isTouchEnemyTank()){
                                    moveDown();
                                }
                                try {
                                    Thread.sleep(50);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        break;
                    case 3:
                            for (int i = 0; i < 30; i++) {
                                if (!isTouchEnemyTank()) {
                                    moveLift();
                                }
                                try {
                                    Thread.sleep(50);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        break;
                }

                //随机移动的改变坦克方向(0~3)
                setDirect((int) (Math.random() * 4));
                //写多线程要考虑线程结束条件,当坦克被击中
                if (alive == false) {
                    break; //退出线程
                    //
                }
        }
    }
}

射击类 实现子弹射击线程

package com.tankgame;

public class shot implements Runnable{//坦克射击子弹线程
     int x; //横坐标
     int y; //纵坐标
    int direct =0; //方向
    int speed  =3; //初始化速度
    boolean alive = true; //子弹默认存活
    //构造器
    public shot(int x, int y, int direct) {
        this.x = x;
        this.y = y;
        this.direct = direct;
    }

    @Override
    //一颗子弹的线程
    public void run() { //射击
        while (alive) {
            try {
                Thread.sleep(50); //让线程休眠50ms
            } 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;
            }
            //当子弹到边界时销毁或者碰到坦克时
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && alive)) {
                alive = false; //此子弹的线程终止
                break;
            }
        }
    }
}

 爆炸类 通过图片来实现坦克爆炸效果

package com.tankgame;

public class Bomb { //定义爆炸效果
    int x,y;
    int life =9 ; //设置生命周期
    boolean alive =true;
    public Bomb(int x, int y) {
        this.x = x;
        this.y = y;
    }
    //减少生命值
    public void LifeDown(){ //配合出现图片爆炸效果
        if (life>0){
            life--;
        }else {
            alive=false;
        }
    }
}

记录类  记录类用于和文件交互,实现游戏的记录

package com.tankgame;

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

//记录数据和文件交互
public class Recorder {

    //定义变量记录击毁坦克数
    private static int allEnemyTankNum = 0;
    //定义IO对象 读入数据到文件中
    private static BufferedWriter bw = null;
    private static BufferedReader br = null;
    private static String recorderFile = "d://坦克大战//data//data.txt";
    //定义vector指向MyPanel对象的敌人坦克vector
    private static Vector<EnemyTank> enemyTanks = null;
    //定义node的vector记录坦克信息
    private static Vector<Node> nodes = new Vector<>();

    //提供其set方法
    public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
        Recorder.enemyTanks = enemyTanks;
    }
    //判断文件是否存在
    public static String getRecorderFile() {
        return recorderFile;
    }

    //当游戏退出时,将allEnemyTankNum保存到recorderFile中
        public static void keepRecorder () {
            try {
                bw = new BufferedWriter(new FileWriter(recorderFile));
                bw.write(allEnemyTankNum + "\r\n"); //换行
                //遍历敌人的坦克的vector,然后根据情况保存即可
                //oop设置一个属性,然后通过setXxx得到 敌人坦克的vector
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirect();
                    //写入到文件
                    bw.write(record + "\r\n");
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (bw != null) {
                        bw.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    //读取文件恢复相关信息(继续上局游戏)
    public static Vector<Node> getNodeAndEnemyTankRec(){
        try {
            br = new BufferedReader(new FileReader(recorderFile));
            allEnemyTankNum = Integer.parseInt(br.readLine()); //将第一行字符串读取(即坦克击毁数量)
            //循环读取文件生成node集合
            String line = "";
            while ((line = br.readLine()) != null){ //每一行代表一个坦克信息
                String[] xyd =line.split(" ");
                Node node = new Node(Integer.parseInt(xyd[0]),Integer.parseInt(xyd[1]),Integer.parseInt(xyd[2]));
                nodes.add(node);//加入集合中
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (br!=null) {
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return nodes;
    }
    public static int getAllEnemyTankNum() {
        return allEnemyTankNum;
    }
    public static void setAllEnemyTankNum(int allEnemyTankNum) {
        Recorder.allEnemyTankNum = allEnemyTankNum;
    }
    //当我方坦克击毁坦克将allEnemyTankNum加1
    public static void addallEnemyTankNum(){
        allEnemyTankNum++;
    }
}

结点类 实现记录一个坦克的信息用于文件交互

package com.tankgame;

/**
 * 一个node对象表示一个坦克的信息
 */
public class Node {
    private int x;
    private int y;
    private int direct;

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

    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 getDirect() {
        return direct;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

}

最后是音乐类  实现游戏音乐的播放

package com.tankgame;

import java.io.*;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

    //播放声音的类
    class AePlayWave extends Thread {

        private String filename;
        public AePlayWave(String wavfile) {
            filename = wavfile;
        }

        public void run() {

            File soundFile = new File(filename);

            AudioInputStream audioInputStream = null;
            try {
                audioInputStream = AudioSystem.getAudioInputStream(soundFile);
            } 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();
            }

        }


    }


最后需要把三张爆炸图片和音乐下载,导入到项目中的同级目录中使用,路径格式等都需要修改

声明:坦克大战也是我的跟着老韩学习的成果,十分感谢! 

 

 

 

 

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值