这是我的坦克游戏大战的最后一版,里面添加很多新的功能。这个坦克大战的有很多不足之处,但是对于初学者来说依然是一个很好的练习项目,从中我们可以学习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);}@Overridepublic 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删掉,再加mpthis.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删掉,再加mpthis.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);}}@Overridepublic void run() {// TODO Auto-generated method stubwhile (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;// 创建一颗炸弹,放入VectorBomb 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;// 创建一颗炸弹,放入VectorBomb 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;}}@Overridepublic 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();}}// 必须重新绘制Panelthis.repaint();}@Overridepublic void keyReleased(KeyEvent e) {// TODO Auto-generated method stub
}@Overridepublic void keyTyped(KeyEvent e) {// TODO Auto-generated method stub
}@Overridepublic 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 = 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();}}
}// 继续上一局的记记录点的类
class Node {int x;int y;int direct;public Node(int x, int y, int direct) {this.x = x;this.y = y;this.direct = direct;}
}// 记录类,同时也可以保存玩家的设置(一般都是事先写在缓存里面的)
class Recorder {// 记录每关有多少敌人private static int enNum = 20;// 设置我有多少可以用的坦克private static int myLife = 3;// 记录一共消灭多少敌人private static int allEnNum = 0;// 从文件中恢复记录点static Vector<Node> nodes = new Vector<Node>();private static FileWriter fw = null;private static BufferedWriter bw = null;private static FileReader fr = null;private static BufferedReader br = null;private Vector<EnemyTank> ets = new Vector<EnemyTank>();// 完成读取的函数(记录点和敌人的数量)public Vector<Node> getNodesAndEnNums() {try {fr = new FileReader("E:/Tanke.txt");br = new BufferedReader(fr);String n = "";n = br.readLine();// 设置先读第一行allEnNum = Integer.parseInt(n);// 接着读while ((n = br.readLine()) != null) {String[] xyz = n.split(" ");// 在知道只有三条数据的情况下,用了这个方法。否则要用for循环Node node = new Node(Integer.parseInt(xyz[0]),Integer.parseInt(xyz[1]), Integer.parseInt(xyz[2]));nodes.add(node);}} catch (Exception e) {// TODO Auto-generated catch block
            e.printStackTrace();} finally {try {br.close();fr.close();} catch (Exception e) {// TODO Auto-generated catch block
                e.printStackTrace();}}return nodes;}public Vector<EnemyTank> getEts() {return ets;}public void setEts(Vector<EnemyTank> ets) {this.ets = ets;}// 保存击毁敌人的数量和击毁敌人坦克的坐标、方向public void keepRecAndEnemyTank() {try {fw = new FileWriter("E:/Tanke.txt");bw = new BufferedWriter(fw);bw.write(allEnNum + "\r\n");// 保存当前的敌人坦克的坐标和方向for (int i = 0; i < ets.size(); i++) {// 取出第一个坦克EnemyTank et = ets.get(i);if (et.isLive) {// 活的就保存String recode = et.x + " " + et.y + " " + et.direct;// 写入bw.write(recode + "\r\n");}}} catch (IOException e) {// TODO Auto-generated catch block
            e.printStackTrace();} finally {try {bw.close();} catch (IOException e) {// TODO Auto-generated catch block
                e.printStackTrace();}try {fw.close();} catch (IOException e) {// TODO Auto-generated catch block
                e.printStackTrace();}}}// 从文件中读取,记录public static void getRecoring() {try {fr = new FileReader("E:/Tanke.txt");br = new BufferedReader(fr);String n = br.readLine();allEnNum = Integer.parseInt(n);} catch (Exception e) {// TODO Auto-generated catch block
            e.printStackTrace();} finally {try {br.close();fr.close();} catch (Exception e) {// TODO Auto-generated catch block
                e.printStackTrace();}}}// 把玩家击毁敌人坦克数量保存到文件中public static void keepRecording() {try {fw = new FileWriter("E:/Tanke.txt");bw = new BufferedWriter(fw);bw.write(allEnNum + "\r\n");} catch (IOException e) {// TODO Auto-generated catch block
            e.printStackTrace();} finally {try {bw.close();} catch (IOException e) {// TODO Auto-generated catch block
                e.printStackTrace();}try {fw.close();} catch (IOException e) {// TODO Auto-generated catch block
                e.printStackTrace();}}}public static int getAllEnNum() {return allEnNum;}public static void setAllEnNum(int allEnNum) {Recorder.allEnNum = allEnNum;}public static int getEnNum() {return enNum;}public static void setEnNum(int enNum) {Recorder.enNum = enNum;}public static int getMyLife() {return myLife;}public void setMyLife(int myLife) {Recorder.myLife = myLife;}// 减少敌人数public static void reduceEnNum() {enNum--;}// 消灭敌人public static void addEnNumRec() {allEnNum++;}}// 炸弹类(没必要定义为线程,因为它不会移动,没有坐标改变)
class Bomb {// 定义炸弹的坐标int x, y;int life = 9;// 炸弹的生命(三张图片)// 可以看出isLive很有用,它可以决定类(或者对象)要不要展现在面板上boolean isLive = true;public Bomb(int x, int y) {this.x = x;this.y = y;}// 炸弹减少生命值public void lifeDown() {if (life > 0) {life--;} else {this.isLive = false;}}}// 子弹类
class Shot implements Runnable {int x;int y;int direct;// 设置子弹的消亡(默认活着的)boolean isLive = true;// speed要给个初始值1,之前给0,按J键,子弹没有动int speed = 1;public Shot(int x, int y, int direct) {super();this.x = x;this.y = y;this.direct = direct;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {// 设置子弹休息50毫秒try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch block
                e.printStackTrace();}switch (direct) {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 > 400 || y < 0 || y > 300) {this.isLive = false;break;}}}
}// 坦克类
class Tank1_2 {int x = 0;int y = 0;boolean isLive = true;// 坦克方向:0表示上,1表示右,2表示下,3表示左int direct = 0;int speed = 1;// 坦克的颜色int color;public int getColor() {return color;}public void setColor(int color) {this.color = color;}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;}// 构造函数public Tank1_2(int x, int y) {this.x = x;this.y = y;}}// 敌人的坦克(做成线程,会移动)
class EnemyTank extends Tank1_2 implements Runnable {int times = 0;// 定义一个向量,可以访问MyPanel上所有敌人的坦克Vector<EnemyTank> ets = new Vector<EnemyTank>();// 定义向量,可以存放敌人的子弹Vector<Shot> ss = new Vector<Shot>();// 敌人添加子弹,应该刚刚创建坦克和敌人子弹死亡后public EnemyTank(int x, int y) {super(x, y);}// 得到MyPaneld的敌人坦克向量public void setEts(Vector<EnemyTank> vv) {// 此时拥有一种能力,可以拿到yPan el上所有敌人的坦克this.ets = vv;}// 判断是否碰到别的敌人的坦克public boolean isTouchOtherEnemy() {boolean b = false;switch (this.direct) {case 0:// 我的坦克向上for (int i = 0; i < ets.size(); i++) {// 取出第一个坦克(很有可能是自己哦)EnemyTank et = ets.get(i);// 如果不是自己if (et != this) {// 如果敌人的方向是向下或者向下if (et.direct == 0 || et.direct == 2) {if (this.x >= et.x && this.x <= et.x + 20&& this.y >= et.y && this.y <= et.y + 30) {return true;}if (this.x + 20 >= et.x && this.x + 20 <= et.x + 20&& this.y >= et.y && this.y <= et.y + 30) {return true;}}if (et.direct == 1 || et.direct == 3) {if (this.x >= et.x && this.x <= et.x + 30&& this.y >= et.y && this.y <= et.y + 20) {return true;}if (this.x + 20 >= et.x && this.x + 20 <= et.x + 30&& this.y >= et.y && this.y <= et.y + 20) {return true;}}}}break;case 1:for (int i = 0; i < ets.size(); i++) {EnemyTank et = ets.get(i);if (et != this) {if (et.direct == 0 || et.direct == 2) {if (this.x + 30 >= et.x && this.x + 30 <= et.x + 20&& this.y >= et.y && this.y <= et.y + 30) {return true;}if (this.x + 30 >= et.x && this.x + 30 <= et.x + 20&& this.y + 20 >= et.y&& this.y + 20 <= et.y + 30) {return true;}}if (et.direct == 1 || et.direct == 3) {if (this.x + 30 >= et.x && this.x + 30 <= et.x + 30&& this.y >= et.y && this.y <= et.y + 20) {return true;}if (this.x + 30 >= et.x && this.x + 30 <= et.x + 30&& this.y + 20 >= et.y&& this.y + 20 <= et.y + 20) {return true;}}}}break;case 2:for (int i = 0; i < ets.size(); i++) {EnemyTank et = ets.get(i);if (et != this) {if (et.direct == 0 || et.direct == 2) {if (this.x >= et.x && this.x <= et.x + 20&& this.y + 30 >= et.y&& this.y + 30 <= et.y + 30) {return true;}if (this.x + 20 >= et.x && this.x + 20 <= et.x + 20&& this.y + 30 >= et.y&& this.y + 30 <= et.y + 30) {return true;}}if (et.direct == 1 || et.direct == 3) {if (this.x >= et.x && this.x <= et.x + 30&& this.y + 30 >= et.y&& this.y + 30 <= et.y + 20) {return true;}if (this.x + 20 >= et.x && this.x + 20 <= et.x + 30&& this.y + 30 >= et.y&& this.y + 30 <= et.y + 20) {return true;}}}}break;case 3:for (int i = 0; i < ets.size(); i++) {EnemyTank et = ets.get(i);if (et != this) {if (et.direct == 0 || et.direct == 2) {if (this.x >= et.x && this.x <= et.x + 20&& this.y >= et.y && this.y <= et.y + 30) {return true;}if (this.x >= et.x && this.x <= et.x + 20&& this.y + 20 >= et.y&& this.y + 20 <= et.y + 30) {return true;}}if (et.direct == 1 || et.direct == 3) {if (this.x >= et.x && this.x <= et.x + 30&& this.y >= et.y && this.y <= et.y + 20) {return true;}if (this.x >= et.x && this.x <= et.x + 30&& this.y + 20 >= et.y&& this.y + 20 <= et.y + 20) {return true;}}}}break;}return b;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {try {// 设置坦克休息一会Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch block
                e.printStackTrace();}switch (this.direct) {case 0:// 说明坦克正在向上运动(继续往上走,符合实际)// y -= speed;设置坦克平滑移动的效果for (int i = 0; i < 30; i++) {if (y > 0 && !this.isTouchOtherEnemy()) {y -= speed;}try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch block
                        e.printStackTrace();}}break;case 1:for (int i = 0; i < 30; i++) {// 这里注意坐标起点问题不是(400x300)if (x < 400 && !this.isTouchOtherEnemy()) {x += speed;}try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch block
                        e.printStackTrace();}}break;case 2:for (int i = 0; i < 30; i++) {if (y < 300 && !this.isTouchOtherEnemy()) {y += speed;}try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch block
                        e.printStackTrace();}}break;case 3:for (int i = 0; i < 30; i++) {if (x > 0 && !this.isTouchOtherEnemy()) {x -= speed;}try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch block
                        e.printStackTrace();}}break;}this.times++;// 设置3秒发一颗子弹if (times % 2 == 0) {if (isLive) {if (ss.size() < 5) {Shot s = null;// 没有子弹,添加switch (direct) {case 0:s = new Shot(x + 10, y, 0);ss.add(s);break;case 1:s = new Shot(x + 30, y + 10, 1);ss.add(s);break;case 2:s = new Shot(x + 10, y + 30, 2);ss.add(s);break;case 3:s = new Shot(x, y + 10, 3);ss.add(s);break;}// 启动子弹线程Thread t = new Thread(s);t.start();}}}// 让坦克随机产生一个新的方向this.direct = (int) (Math.random() * 4);// 判断敌人坦克是否死亡了(双等号)if (this.isLive == false) {// 让坦克死亡,后退出线程return;}}}
}// 我的坦克
class Hero1_2 extends Tank1_2 {// 多个子弹,用向量创建Vector<Shot> ss = new Vector<Shot>();// 子弹Shot s = null;public Hero1_2(int x, int y) {super(x, y);}// 坦克开火public void shotEnemy() {switch (this.direct) {case 0:s = new Shot(x + 10, y, 0);// 把子弹加入向量
            ss.add(s);break;case 1:s = new Shot(x + 30, y + 10, 1);// 把子弹加入向量
            ss.add(s);break;case 2:s = new Shot(x + 10, y + 30, 2);// 把子弹加入向量
            ss.add(s);break;case 3:s = new Shot(x, y + 10, 3);// 把子弹加入向量
            ss.add(s);break;}// 启动子弹线程(创建线程,赶紧传参,我在这里吃了大亏!)Thread t = new Thread(s);t.start();}public void moveUp() {y -= speed;}public void moveRight() {x += speed;}public void moveDown() {y += speed;}public void moveLeft() {x -= speed;}
}

实现图片:

相关素材:

1.爆炸效果的图片(3张)

2.游戏声音素材

这个自己下载一个好啦(我的是上面命名为111.wav的文件,这里不支持上传)

转载于:https://www.cnblogs.com/1693977889zz/p/8445905.html

Java坦克大战(四)相关推荐

  1. Java坦克大战 (四) 之子弹的产生

    本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...

  2. java 坦克大战_java课程设计之坦克大战

    本文实例为大家分享了java坦克大战的具体代码,供大家参考,具体内容如下 环境要求: 操作系统:Windows 10 JAVA虚拟机:JDK1.8以上 开发环境:Eclipse(4.5以上) 功能提示 ...

  3. java坦克大战课设报告_java课程设计之坦克大战

    本文实例为大家分享了java坦克大战的具体代码,供大家参考,具体内容如下 环境要求: 操作系统:Windows 10 JAVA虚拟机:JDK1.8以上 开发环境:Eclipse(4.5以上) 功能提示 ...

  4. java坦克大战总体功能设计_Java坦克大战设计报告.doc

    Java坦克大战设计报告.doc <语言设计> 设计报告 信息工程学院专业班级:::指导老师:2011年7月22日 目录 目录2 题目一 坦克大战4 1.1题目简介4 1.2设计的内容.要 ...

  5. Java坦克大战游戏源码(java坦克大战)

    Java坦克大战游戏源码(java坦克大战) public Swingtest002() {// 设置标题setTitle("请登陆");// 绝对布局setLayout(null ...

  6. Java坦克大战,基于Swing编写很哇塞的小游戏,可以做课程设计毕业设计

    Java坦克大战,基于Swing编写很哇塞的小游戏,可以做课程设计毕业设计 有图有真相 操作方法:ASDW控制移动,鼠标控制炮筒旋转,鼠标左键开枪,空格发射炮弹, 开发思路是标准的游戏开发思路,单线程 ...

  7. java炮弹_Java坦克大战 (四) 之子弹的产生

    在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学完J2SE的小伙伴们一点启示! 坦克大战V0.4实现功能: 1.写一个Missile类,产生一个可运动的子 ...

  8. [ java ] 坦克大战 5.0 ~ 最终完整版

    坦克大战5.0 新增功能内容:(加入IO流内容) 防止敌坦克间重叠 击杀数显示 保存上局游戏进度–>两种开局方式 加入开局音乐 修复记录文件丢失后的异常 5.0版本为最终版 提示:爆炸图片需自行 ...

  9. java坦克大战登录界面设计_基于JAVA的坦克大战设计和实现-代码.doc

    JISHOU UNIVERSITY 本科生毕业设计 题 目:基于JAVA的坦克大战设计与实现作 者:学 号:所属学院:专业年级:指导教师:职 称:完成时间:2012年5月7日 吉首大学 基于JAVA的 ...

最新文章

  1. 在Ubuntu 14.04 64bit上安装批量图片处理器XnConvert
  2. javascript var变量删除
  3. 【转】TCP协议中的三次握手和四次挥手(图解)
  4. OTA整包的制作流程(未完)
  5. Boost:以协程的方式实现重构echo服务器的实例
  6. Android app native代码性能分析
  7. 查找数组是否有重复元素
  8. Gargari and Permutations CodeForces - 463D(建图+记忆化搜索)
  9. MFC开发IM-自绘按钮控件,给按钮设置背景图片
  10. 【Linux】基于Openfile的multipath测试
  11. 一篇google developer 安全介绍的翻译
  12. Atitit 指令集(IA及指令集架构 1. 指令集(IA:InstructionSet)是指CPU指令系统所能识别(翻译)执行的全部指令的集合。 1 1.1. (1)运算指令 1 1.2. (2)
  13. java种子_MC速通各类种子(java版,更新至6.26)
  14. 怎么自己发表计算机学术论文,计算机学术论文写做与发表
  15. 卓凡信息技术考试系统服务器,卓凡信息技术考试系统
  16. WireShark抓取网站用户名和密码
  17. selenium 实战之 A级纳税人信息
  18. 【EXLIBRIS】随笔记 004
  19. 走近图灵奖大师David Patterson开挂的人生
  20. 学习笔记——VMware网络桥接的几个问题(有配置问题的值得一看)

热门文章

  1. QQ for Linux 复活,微信 for Linux 还远吗?
  2. 实现机器学习的循序渐进指南IX ——树回归
  3. 使用ASP.NET Web API构建Restful API
  4. RuoYi框架使用手册
  5. vue createApp(),mount(),生命周期钩子函数执行顺序
  6. sqlsever无法重新启动计算机,SQLServer 2008安装提示需要重启计算机,但是重启还是不通过解决方案...
  7. 中国重汽微服务管理_干货 | 微服务架构下 Spring Cloud OAuth2 通用权限管理系统
  8. ElasticSearch启动报错,报ERROR: [3] bootstrap checks failed
  9. HTML修改价格文字,HTML打折计算价格实现原理与脚本代码
  10. 移除数组第一个元素_3分钟短文 | PHP 数组删除元素,忘了foreach吧,有更优雅的方式...