Java坦克大战

Posted 长河落日圆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java坦克大战相关的知识,希望对你有一定的参考价值。

这是我的坦克游戏大战的最后一版,里面添加很多新的功能。这个坦克大战的有很多不足之处,但是对于初学者来说依然是一个很好的练习项目,从中我们可以学习Java基础知识,将知识与项目结合,学习面向对象编程思想,最主要的是编程的逻辑练习,代码往往不像是写文章从上到下一气呵成完成,中间很可能为增加一个功能来添加一个类一个方法等,中间有很多细节需要我们考虑。文章最后会附加该坦克大战涉及的相关素材。

功能:

1.防止坦克重叠

2.可以分关(闪烁效果)

3.记录成绩(小型游戏都是写在文件中)

4.存盘退出,可以记录但是敌人坦克的坐标

5.可以恢复上局,继续玩

6.坦克的声音

坦克大战最终版本(2.1)

MyTanKGame类:

/*
 * 功能:
 * 1.防止坦克重叠
 * 2.可以分关(闪烁效果)
 * 3.记录成绩(小型游戏都是写在文件中)
 * 4.存盘退出,可以记录但是敌人坦克的坐标
 * 5.可以恢复上局,继续玩
 * 6.坦克的声音
 */
package com.fanghua6;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Vector;
import javax.swing.*;

public class MyTankGame1_7 extends JFrame implements ActionListener {

    Mypanel1_2 mp = null;

    // 定义开始面板
    MyStartPanel msp = null;
    // 做出菜单
    JMenuBar jmb = null;
    // 开始游戏
    JMenu jm1 = null;
    JMenuItem jmi1 = null;
    // 退出游戏
    JMenuItem jmi2 = null;
    // 存盘退出
    JMenuItem jmi3 = null;
    JMenuItem jmi4 = null;

    public static void main(String[] args) {
        new MyTankGame1_7();
    }

    // 构造函数
    public MyTankGame1_7() {
        // mp = new Mypanel1_2();

        // 启动mp线程
        // Thread t = new Thread(mp);
        // t.start();

        // this.add(mp);
        // 注册监听
        // this.addKeyListener(mp);
        // 创建菜单及菜单选项
        jmb = new JMenuBar();
        jm1 = new JMenu("游戏(G)");
        jm1.setMnemonic(\'G\');
        jmi1 = new JMenuItem("开始新游戏(N)");
        jmi1.setMnemonic(\'N\');

        jmi2 = new JMenuItem("退出游戏(E)");
        jmi2.setMnemonic(\'E\');

        jmi3 = new JMenuItem("存盘退出(C)");
        jmi3.setMnemonic(\'C\');

        jmi4 = new JMenuItem("继续上局(S)");
        jmi4.setMnemonic(\'S\');

        // jmi1相应
        jmi1.addActionListener(this);
        jmi1.setActionCommand("newgame");
        jmi2.addActionListener(this);
        jmi2.setActionCommand("exit");
        jmi3.addActionListener(this);
        jmi3.setActionCommand("saveExit");
        jmi4.addActionListener(this);
        jmi4.setActionCommand("conGame");

        jm1.add(jmi1);
        jm1.add(jmi2);
        jm1.add(jmi3);
        jm1.add(jmi4);

        jmb.add(jm1);

        // 加了开始面板(上面的全注释掉)
        msp = new MyStartPanel();
        this.add(msp);
        // 启动msp面板
        Thread t = new Thread(msp);
        t.start();

        this.setJMenuBar(jmb);

        this.setSize(600, 500);
        this.setTitle("我的坦克大战");
        ImageIcon icon = new ImageIcon("images\\\\tanke.png");
        this.setIconImage(icon.getImage());
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        // 对用户不同的点击做出不同的处理
        if (e.getActionCommand().equals("newgame")) {

            // 创建战场面板
            mp = new Mypanel1_2("newGame");
            // 启动mp线程
            Thread t = new Thread(mp);
            t.start();
            // 先把msp删掉,再加mp
            this.remove(msp);
            this.add(mp);
            // 注册监听
            this.addKeyListener(mp);
            // 显示,刷新JFrame(这个很重要)
            this.setVisible(true);
        } else if (e.getActionCommand().equals("exit")) {

            // 用户退出系统的菜单(保存击毁敌人数量)
            Recorder.keepRecording();

            System.exit(0);
        }// 对存盘退出的处理
        else if (e.getActionCommand().equals("saveExit")) {

            /*
             * 当时这里这样处理的,大错特错。new两次 工作 new Recorder().setEts(mp.ets);new
             * 保存击毁敌人的数量和敌人的坐标 Recorder().keepRecAndEnemyTank();
             */

            // 工作
            Recorder rd = new Recorder();
            rd.setEts(mp.ets);
            // 保存击毁敌人的数量和敌人的坐标
            rd.keepRecAndEnemyTank();

            // 退出
            System.exit(0);
        } else if (e.getActionCommand().equals("conGame")) {
            // 继续游戏
            // 创建战场面板
            mp = new Mypanel1_2("con");

            // 不在这:mp.nodes = new Recorder().getNodesAndEnNums();
            // 启动mp线程
            Thread t = new Thread(mp);
            t.start();
            // 先把msp删掉,再加mp
            this.remove(msp);
            this.add(mp);
            // 注册监听
            this.addKeyListener(mp);
            // 显示,刷新JFrame(这个很重要)
            this.setVisible(true);

        }
    }
}

// 提示面板(用线程来实现闪烁效果)
class MyStartPanel extends JPanel implements Runnable {
    // 做一个开关
    int times = 0;

    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 400, 300);
        // 提示信息
        if (times % 2 == 0) {
            g.setColor(Color.yellow);
            // 开关信息的字体
            Font myFont = new Font("华文新魏", Font.BOLD, 30);
            g.setFont(myFont);// 别忘了
            g.drawString("stage: 1", 140, 200);
        }
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            // 休眠
            try {
                Thread.sleep(500);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            times++;
            // 重画
            this.repaint();
        }
    }

}

// 我的面板,拓宽思路:Panel本身就是一个刷新体
class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {

    // 定义我的坦克
    Hero1_2 hero = null;

    // 判断是续上局,还是新游戏

    // 定义敌人的坦克(不止一辆,线程安全,集合)
    Vector<EnemyTank> ets = new Vector<EnemyTank>();
    Vector<Node> nodes = new Vector<Node>();

    // 定义炸弹集合
    Vector<Bomb> bombs = new Vector<Bomb>();

    int enSize = 4;// 敌人坦克保持4个

    // 定义三张图片(三张图片才能组成一颗炸弹)
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    // 构造函数(续局,变成含参的构造函数)
    public Mypanel1_2(String flag) {

        // 恢复记录(写在这里)
        Recorder.getRecoring();

        hero = new Hero1_2(70, 100);

        if (flag.equals("newGame")) {
            // 初始化敌人的坦克
            for (int i = 0; i < enSize; i++) {
                // 创建一辆敌人的坦克
                EnemyTank et = new EnemyTank((i + 1) * 50, 0);
                et.setColor(0);
                // 坦克默认反向是0(向上),这里改一下
                et.setDirect(2);

                // 将MyPanel的敌人坦克向量交给该敌人坦克
                et.setEts(ets);

                // 启动敌人的坦克
                Thread t = new Thread(et);
                t.start();
                // 给敌人坦克添加一颗子弹
                Shot s = new Shot(et.x + 10, et.y + 30, 2);
                // 加入给敌人的坦克
                et.ss.add(s);

                Thread t2 = new Thread(s);
                t2.start();
                ets.add(et);
            }
        } else {

            nodes = new Recorder().getNodesAndEnNums();

            for (int i = 0; i < nodes.size(); i++) {

                Node node = nodes.get(i);
                // 创建一辆敌人的坦克
                EnemyTank et = new EnemyTank(node.x, node.y);
                et.setColor(0);
                et.setDirect(node.direct);

                // 将MyPanel的敌人坦克向量交给该敌人坦克
                et.setEts(ets);

                // 启动敌人的坦克
                Thread t = new Thread(et);
                t.start();
                // 给敌人坦克添加一颗子弹
                Shot s = new Shot(et.x + 10, et.y + 30, 2);
                // 加入给敌人的坦克
                et.ss.add(s);

                Thread t2 = new Thread(s);
                t2.start();
                ets.add(et);
            }
        }
        // 初始话图片,这样做击中第一个坦克,爆炸的效果不明显。下面优化
        image1 = Toolkit.getDefaultToolkit().getImage(
                Panel.class.getResource("/bomb_1.gif"));
        image2 = Toolkit.getDefaultToolkit().getImage(
                Panel.class.getResource("/bomb_2.gif"));
        image3 = Toolkit.getDefaultToolkit().getImage(
                Panel.class.getResource("/bomb_3.gif"));

        // 引包:import javax.imageio.ImagesssIO;
        // try {
        // image1=ImageIO.read(new File("/bomsb_1.gif"));
        // image2=ImageIO.read(new File("/bomb_2.gif"));
        // image3=ImageIO.read(new File("/bomb_3.gif"));
        // } catch (IOException e) {
        // // TODO Auto-generated catch block
        // e.printStackTrace();
        // }

        // 在Mypanel1_2初始化里,放置开战音效,加载即播放
        // 以后再添加爆炸效果的声音也是这样做的思路
        AePlayWave apw = new AePlayWave("E:\\\\111.wav");
        apw.start();

    }

    // 提示信息(只需要画笔即可)
    public void showInfo(Graphics g) {
        // 画出提示信息坦克
        this.drawTank(70, 310, g, 0, 0);
        g.setColor(Color.black);
        g.drawString(Recorder.getEnNum() + "", 100, 330);

        this.drawTank(70, 360, g, 0, 1);
        g.setColor(Color.black);
        g.drawString(Recorder.getMyLife() + "", 100, 380);

        // 画出玩家的总成绩
        g.setColor(Color.black);
        Font f = new Font("宋体", Font.BOLD, 20);
        g.setFont(f);
        g.drawString("你的总成绩", 410, 30);
        this.drawTank(410, 60, g, 0, 0);

        g.setColor(Color.black);
        g.drawString(Recorder.getAllEnNum() + "", 440, 80);
    }

    // 重写paint函数
    public void paint(Graphics g) {
        // 一定要调用
        super.paint(g);
        g.fillRect(0, 0, 400, 300);
        // 画出提示信息
        this.showInfo(g);

        // 画出自己的坦克(将方向填进去)
        if (hero.isLive == true) {
            this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
        }
        // 从ss中取出每一颗子弹,并画出
        for (int i = 0; i < hero.ss.size(); i++) {

            Shot myShot = hero.ss.get(i);
            if (myShot != null && myShot.isLive == true) {
                g.draw3DRect(myShot.x, myShot.y, 1, 1, false);

                /*
                 * 画出一颗子弹(后添加 hero.s.isLive==true,节省资源) if (hero.s != null
                 * &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
                 * 1, 1,false); }
                 */
            }
            if (myShot.isLive == false) {
                // 从ss(向量)中删除该子弹
                // hero.ss.remove(i);会报异常。
                hero.ss.remove(myShot);
            }
        }

        // 画出炸弹
        for (int i = 0; i < bombs.size(); i++) {
            // 取出炸弹
            Bomb b = bombs.get(i);
            if (b.life > 6) {
                g.drawImage(image1, b.x, b.y, 30, 30, this);
            } else if (b.life > 4) {
                g.drawImage(image2, b.x, b.y, 30, 30, this);
            } else {
                g.drawImage(image3, b.x, b.y, 30, 30, this);
            }
            // 让b的生命值减小
            b.lifeDown();
            // 如果炸弹生命值为零,就把该炸弹从bombs向量中去掉
            if (b.life == 0) {
                bombs.remove(b);
            }

        }

        // 画出敌人的坦克
        for (int i = 0; i < ets.size(); i++) {
            EnemyTank et = ets.get(i);
            if (et.isLive) {
                this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);

                // 画出敌人的子弹
                for (int j = 0; j < et.ss.size(); j++) {
                    // 取出子弹
                    Shot enemyShot = et.ss.get(j);
                    if (enemyShot != null && enemyShot.isLive == true) {
                        g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false);
                    }
                    if (enemyShot.isLive == false) {
                        // 如果敌人的坦克死亡了,就从Vector中删除
                        et.ss.remove(enemyShot);
                    }
                }
            }
        }
    }

    // 敌人的坦克是否击中我
    public void hitMe() {
        // 取出每一个敌人的坦克
        for (int i = 0; i < this.ets.size(); i++) {
            // 取出坦克
            EnemyTank et = ets.get(i);

            // 取出每一颗子弹
            for (int j = 0; j < et.ss.size(); j++) {
                // 取出子弹
                Shot enemyShot = et.ss.get(j);
                if (hero.isLive) {
                    if (this.hitTank(enemyShot, hero)) {

                    }
                }
            }
        }
    }

    // 判断我的子弹是否击中敌人的坦克
    public void hitEnemyTank() {
        // 判断是否击中敌人的坦克
        for (int i = 0; i < hero.ss.size(); i++) {
            // 取出子弹
            Shot myShot = hero.ss.get(i);
            // 判断子弹是否有效
            if (myShot.isLive) {
                // 取出每个坦克,与它判断
                for (int j = 0; j < ets.size(); j++) {
                    // 取出坦克
                    EnemyTank et = ets.get(j);

                    if (et.isLive) {
                        if (this.hitTank(myShot, et)) {

                            // 减少敌人数量
                            Recorder.reduceEnNum();
                            // 增加我的记录
                            Recorder.addEnNumRec();
                        }
                    }

                }
            }
        }
    }

    // 写一个函数 专门判断是否击中敌人坦克(原来第二参数: EnemyTank et)
    // void改成boolean 判断击中的目标是谁

    public boolean hitTank(Shot s, Tank1_2 et) {
        boolean b2 = false;

        // 判断该坦克的方向
        switch (et.direct) {
        // 如果敌人坦克的方向是上或者是下
        case 0:
        case 2:
            if (s.x > et.x && s.x < et.x + 20 && s.y > et.y && s.y < et.y + 30) {
                // 击中
                // 子弹死亡
                s.isLive = false;
                // 敌人坦克死亡
                et.isLive = false;
                b2 = true;
                // 创建一颗炸弹,放入Vector
                Bomb b = new Bomb(et.x, et.y);
                // 放入Vector
                bombs.add(b);

            }

            break;
        case 1:
        case 3:
            if (s.x > et.x && s.x < et.x + 30 && s.y > et.y && s.y < et.y + 20) {
                // 击中
                // 子弹死亡
                s.isLive = false;
                // 敌人坦克死亡
                et.isLive = false;
                b2 = true;
                // 创建一颗炸弹,放入Vector
                Bomb b = new Bomb(et.x, et.y);
                // 放入Vector
                bombs.add(b);

            }
            break;
        }

        return b2;

    }

    // 画出坦克的函数
    public void drawTank(int x, int y, Graphics g, int direct, int type) {
        // 坦克类型
        switch (type) {
        case 0:
            g.setColor(Color.green);
            break;
        case 1:
            g.setColor(Color.yellow);
            break;
        }
        // 方向设置
        switch (direct) {
        // 向上
        case 0:
            g.fill3DRect(x, y, 5, 30, false);
            g.fill3DRect(x + 15, y, 5, 30, false);
            g.fill3DRect(x + 5, y + 5, 10, 20, false);
            g.fillOval(x + 5, y + 10, 10, 10);
            g.drawLine(x + 10, y + 15, x + 10, y);
            break;
        // 向右
        case 1:
            g.fill3DRect(x, y, 30, 5, false);
            g.fill3DRect(x, y + 15, 30, 5, false);
            g.fill3DRect(x + 5, y + 5, 20, 10, false);
            g.fillOval(x + 10, y + 5, 10, 10);
            g.drawLine(x + 15, y + 10, x + 30, y + 10);
            break;
        // 向下
        case 2:
            g.fill3DRect(x, y, 5, 30, false);
            g.fill3DRect(x + 15, y, 5, 30, false);
            g.fill3DRect(x + 5, y + 5, 10, 20, false);
            g.fillOval(x + 5, y + 10, 10, 10);
            g.drawLine(x + 10, y + 15, x + 10, y + 30);
            break;
        // 向左
        case 3:
            g.fill3DRect(x, y, 30, 5, false);
            g.fill3DRect(x, y + 15, 30, 5, false);
            g.fill3DRect(x + 5, y + 5, 20, 10, false);
            g.fillOval(x + 10, y + 5, 10, 10);
            g.drawLine(x + 15, y + 10, x, y + 10);
            break;
        }

    }

    @Override
    public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub
        // 已更正为顺时针
        if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
            this.hero.moveUp();
            this.hero.setDirect(0);
        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT
                || e.getKeyCode() == KeyEvent.VK_D) {
            this.hero.setDirect(1);
            this.hero.moveRight();
        } else if (e.getKeyCode() == KeyEvent.VK_DOWN
                || e.getKeyCode() == KeyEvent.VK_S) {
            this.hero.moveDown();
            this.hero.setDirect(2);
        } else if (e.getKeyCode() == KeyEvent.VK_LEFT
                || e.getKeyCode() == KeyEvent.VK_A) {
            this.hero.moveLeft();
            this.hero.setDirect(3);
        } else if (e.getKeyCode() == KeyEvent.VK_J) {
            // 将J键设置为发出子弹
            // 子弹连发,J被按几下,发几颗:this.hero.shotEnemy();
            // this.repaint();在run函数里,不应该设计在这里
            if (this.hero.ss.size() <= 4) {
                this.hero.shotEnemy();
            }
        }
        // 必须重新绘制Panel
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        // 每隔100毫秒去重绘
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            // 谨记这里:由于这里多写了这些,线程每次都被重新调用
            // showInfo的信息不会动态改变 调了好久好久。苦笑脸
            // 判断是否击中(写在这里,虽然在每次重绘的时候都要调用,但是没办法)
            // 每一颗子弹都要和每个坦克进行匹配
            // for (int i = 0; i < hero.ss.size(); i++) {
            // // 取出子弹
            // Shot myShot = hero.ss.get(i);
            // // 判断子弹是否有效
            // if (myShot.isLive) {
            // // 取出每个坦克,与它判断
            // for (int j = 0; j < ets.size(); j++) {
            // // 取出坦克
            // EnemyTank et = ets.get(j);
            //
            // if (et.isLive) {
            // this.hitTank(myShot, et);
            // }
            // }
            // }
            // }
            this.hitEnemyTank();

            this.hitMe();

            // 重绘
            this.repaint();
        }
    }
}

Menbers类:

package com.fanghua6;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Vector;
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 = nullJava坦克大战

Java坦克大战 跟学韩顺平老师视频开发

Java__线程---基础知识全面实战---坦克大战系列为例

Java坦克大战

java课程设计--坦克大战

java之坦克大战