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);}@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坦克大战(四)相关推荐
- Java坦克大战 (四) 之子弹的产生
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
- java 坦克大战_java课程设计之坦克大战
本文实例为大家分享了java坦克大战的具体代码,供大家参考,具体内容如下 环境要求: 操作系统:Windows 10 JAVA虚拟机:JDK1.8以上 开发环境:Eclipse(4.5以上) 功能提示 ...
- java坦克大战课设报告_java课程设计之坦克大战
本文实例为大家分享了java坦克大战的具体代码,供大家参考,具体内容如下 环境要求: 操作系统:Windows 10 JAVA虚拟机:JDK1.8以上 开发环境:Eclipse(4.5以上) 功能提示 ...
- java坦克大战总体功能设计_Java坦克大战设计报告.doc
Java坦克大战设计报告.doc <语言设计> 设计报告 信息工程学院专业班级:::指导老师:2011年7月22日 目录 目录2 题目一 坦克大战4 1.1题目简介4 1.2设计的内容.要 ...
- Java坦克大战游戏源码(java坦克大战)
Java坦克大战游戏源码(java坦克大战) public Swingtest002() {// 设置标题setTitle("请登陆");// 绝对布局setLayout(null ...
- Java坦克大战,基于Swing编写很哇塞的小游戏,可以做课程设计毕业设计
Java坦克大战,基于Swing编写很哇塞的小游戏,可以做课程设计毕业设计 有图有真相 操作方法:ASDW控制移动,鼠标控制炮筒旋转,鼠标左键开枪,空格发射炮弹, 开发思路是标准的游戏开发思路,单线程 ...
- java炮弹_Java坦克大战 (四) 之子弹的产生
在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学完J2SE的小伙伴们一点启示! 坦克大战V0.4实现功能: 1.写一个Missile类,产生一个可运动的子 ...
- [ java ] 坦克大战 5.0 ~ 最终完整版
坦克大战5.0 新增功能内容:(加入IO流内容) 防止敌坦克间重叠 击杀数显示 保存上局游戏进度–>两种开局方式 加入开局音乐 修复记录文件丢失后的异常 5.0版本为最终版 提示:爆炸图片需自行 ...
- java坦克大战登录界面设计_基于JAVA的坦克大战设计和实现-代码.doc
JISHOU UNIVERSITY 本科生毕业设计 题 目:基于JAVA的坦克大战设计与实现作 者:学 号:所属学院:专业年级:指导教师:职 称:完成时间:2012年5月7日 吉首大学 基于JAVA的 ...
最新文章
- 在Ubuntu 14.04 64bit上安装批量图片处理器XnConvert
- javascript var变量删除
- 【转】TCP协议中的三次握手和四次挥手(图解)
- OTA整包的制作流程(未完)
- Boost:以协程的方式实现重构echo服务器的实例
- Android app native代码性能分析
- 查找数组是否有重复元素
- Gargari and Permutations CodeForces - 463D(建图+记忆化搜索)
- MFC开发IM-自绘按钮控件,给按钮设置背景图片
- 【Linux】基于Openfile的multipath测试
- 一篇google developer 安全介绍的翻译
- Atitit 指令集(IA及指令集架构 1. 指令集(IA:InstructionSet)是指CPU指令系统所能识别(翻译)执行的全部指令的集合。	1 1.1. (1)运算指令	1 1.2. (2)
- java种子_MC速通各类种子(java版,更新至6.26)
- 怎么自己发表计算机学术论文,计算机学术论文写做与发表
- 卓凡信息技术考试系统服务器,卓凡信息技术考试系统
- WireShark抓取网站用户名和密码
- selenium 实战之 A级纳税人信息
- 【EXLIBRIS】随笔记 004
- 走近图灵奖大师David Patterson开挂的人生
- 学习笔记——VMware网络桥接的几个问题(有配置问题的值得一看)
热门文章
- QQ for Linux 复活,微信 for Linux 还远吗?
- 实现机器学习的循序渐进指南IX ——树回归
- 使用ASP.NET Web API构建Restful API
- RuoYi框架使用手册
- vue createApp(),mount(),生命周期钩子函数执行顺序
- sqlsever无法重新启动计算机,SQLServer 2008安装提示需要重启计算机,但是重启还是不通过解决方案...
- 中国重汽微服务管理_干货 | 微服务架构下 Spring Cloud OAuth2 通用权限管理系统
- ElasticSearch启动报错,报ERROR: [3] bootstrap checks failed
- HTML修改价格文字,HTML打折计算价格实现原理与脚本代码
- 移除数组第一个元素_3分钟短文 | PHP 数组删除元素,忘了foreach吧,有更优雅的方式...