JAVA坦克大战游戏v3
JAVA坦克大战游戏v3
素材
bomb_3.gif
bomb_2.gif
bomb_1.gif
项目结构
游戏演示
MyTankGame3.java
/*** 功能:坦克游戏的5.0[]* 1.画出坦克.* 2.我的坦克可以上下左右移动* 3.可以发射子弹,子弹连发(最多5)* 4.当我的坦克击中敌人坦克时,敌人就消失(爆炸的效果)* 5.我被击中后,显示爆炸效果* 6.防止敌人坦克重叠运动(*)* 6.1决定把判断是否碰撞的函数写到EnemyTank类* 7.可以分关(*)* 7.1做一个开始的Panle,它是一个空的* 7.2闪烁效果* 8.可以在玩游戏的时候暂停和继续(*)* 8.1当用户点击暂停时,子弹的速度和坦克速度设为0,并让坦克的方向不要变化* 9.可以记录玩家的成绩(*)* 9.1用文件流.* 9.2单写一个记录类,完成对玩家记录* 9.3先完成保存共击毁了多少辆敌人坦克的功能.* 9.4存盘退出游戏,可以记录当时的敌人坦克坐标,并可以恢复* 10.java如何操作声音文件(*)* 10.1对声音文件的操作*/
package org.example;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
public class MyTankGame3 extends JFrame implements ActionListener {MyPanel mp=null; //定义一个游戏面板MyStartPanel msp=null; //定义一个开始面板JMenuBar jmb=null; //菜单条JMenu jm1=null; //菜单JMenuItem jmil=null; //菜单选项1 开始新游戏JMenuItem jmi2=null; //菜单选项2 退出游戏JMenuItem jmi3=null; //菜单选项3 存盘退出游戏JMenuItem jmi4=null; //菜单选项4 继续上局游戏//主函数public static void main(String[] args) {// TODO Auto-generated method stub//定义一个MyTankGame3 的对象mtg并创建它MyTankGame3 mtg=new MyTankGame3();}//未完//构造函数public MyTankGame3(){//创建菜单及菜单选项jmb=new JMenuBar();jm1 =new JMenu("游戏(G)");//设置快捷方式jm1.setMnemonic('G');jmil =new JMenuItem("开始新游戏(N)");jmi2 =new JMenuItem("退出游戏(E)");jmi3 =new JMenuItem("存盘退出游戏(C)");jmi4 =new JMenuItem("继续上局游戏(S)");//注册监听jmi4.addActionListener(this);jmi4.setActionCommand("conGame");//注册监听jmi3.addActionListener(this);jmi3.setActionCommand("saveExit");jmi2.addActionListener(this);jmi2.setActionCommand("exit");jmi2.setMnemonic('E');//对jmil相应jmil.addActionListener(this);jmil.setActionCommand("newgame");jm1.add(jmil);jm1.add(jmi2);jm1.add(jmi3);jm1.add(jmi4);jmb.add(jm1);msp=new MyStartPanel();Thread t=new Thread(msp);t.start();this.setJMenuBar(jmb);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.add(msp);this.setSize(600, 500);this.setVisible(true);}//未完public void actionPerformed(ActionEvent arg0) {// TODO Auto-generated method stub//对用户不同的点击作出不同的处理if(arg0.getActionCommand().equals("newgame")){mp=new MyPanel("newGame");//创建战场面板Thread t=new Thread(mp);//启动mp线程t.start();this.remove(msp); //先删除旧的开始面板this.add(mp);this.addKeyListener(mp);//注册监听this.setVisible(true); //显示,刷新JFrame}else if(arg0.getActionCommand().equals("exit")){//用户点击了退出系统的菜单//保存击毁敌人数量.Recorder.keepRecording();System.exit(0);}//对存盘退出左处理else if(arg0.getActionCommand().equals("saveExit")){System.out.println("111");System.out.println("mp.ets.size="+mp.ets.size());//工作Recorder rd=new Recorder();rd.setEts(mp.ets);//保存击毁敌人的数量和敌人的坐标rd.keepRecAndEnemyTank();//退出System.exit(0);}else if(arg0.getActionCommand().equals("conGame")){//创建战场面板mp=new MyPanel("con");//启动mp线程Thread t=new Thread(mp);t.start();//先删除旧的开始面板this.remove(msp);this.add(mp);//注册监听this.addKeyListener(mp);//显示,刷新JFramethis.setVisible(true);}} //MyTankGame3()构造函数完
}//class MyTankGame3完
//class MyStartPanel 打开游戏的第一个画面,就是一个提示作用
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", 150, 150);}}public void run() {// TODO Auto-generated method stubwhile(true){//休眠try{Thread.sleep(100);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}times++;this.repaint();//重画}}
}//class MyStartPanel完
//class MyPanel,我的面板,游戏就在这个面板上运行
class MyPanel extends JPanel implements KeyListener,Runnable {//定义一个我的坦克Hero hero=null;//定义敌人的坦克组Vector<EnemyTank> ets=new Vector<EnemyTank>();Vector<Node> nodes=new Vector<Node>();//定义炸弹集合Vector<Bomb> bombs=new Vector<Bomb>();int enSize=3;//定义三张图片,三张图片才能组成一颗炸弹Image image1=null;Image image2=null;Image image3=null;
//class MyPanel未完//MyPanel()构造函数public MyPanel(String flag){//恢复记录Recorder.getRecoring();hero=new Hero(100,100);if(flag.equals("newGame"))//如果玩家点击的是开始新游戏{//初始化敌人的坦克for(int i=0;i<enSize;i++){//创建一辆敌人的坦克对象EnemyTank et=new EnemyTank((i+1)*50,0);et.setColor(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);}}//判断完毕,还有下一个判断//MyPanel()构造函数未完//玩游戏只有两种情况,要么新游戏,要么接着玩,保存和退出不在这个地方做判断else{System.out.println("接着玩");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);}}//判断完毕//创建图片try {image1=ImageIO.read(new File("images/O.png"));image2=ImageIO.read(new File("images/S.png"));image3=ImageIO.read(new File("images/T.png"));} catch (Exception e) {e.printStackTrace();// TODO: handle exception}//播放开战声音AePlayWave apw=new AePlayWave("out/ring05.wav");apw.start();}//MyPanel()构造函数完//showInfo(Graphics g)函数画出提示信息public void showInfo(Graphics g){//画出提示信息坦克(该坦克不参与战斗)this.drawTank(80,330, g, 0, 0);g.setColor(Color.black);g.drawString(Recorder.getEnNum()+"", 110, 350);this.drawTank(130, 330, g, 0, 1);g.setColor(Color.black);g.drawString(Recorder.getMyLife()+"", 165, 350);//画出玩家的总成绩g.setColor(Color.black);Font f=new Font("宋体",Font.BOLD,20);g.setFont(f);g.drawString("您的总成绩", 420, 30);this.drawTank(420, 60, g, 0, 0);g.setColor(Color.black);g.drawString(Recorder.getAllEnNum()+"", 460, 80);}//public paint(Graphics g)函数,整个游戏的前台public void paint(Graphics g){super.paint(g);g.fillRect(0, 0, 400, 300);//画出提示信息this.showInfo(g);//画出自己的坦克if(hero.isLive){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.drawOval(myShot.x, myShot.y, 50, 50);g.draw3DRect(myShot.x, myShot.y, 1, 1,false);}if(myShot.isLive==false){//从ss中删除掉该子弹hero.ss.remove(myShot);}}//画出炸弹for(int i=0;i<bombs.size();i++){System.out.println("bombs.size()="+bombs.size());//取出炸弹Bomb b=bombs.get(i);if(b.life>6){g.drawImage(image1, b.x, b.y, 30, 30, this);}else if(b.life>3){g.drawImage(image2, b.x, b.y, 30, 30, this);}else{g.drawImage(image3, b.x, b.y, 30, 30, this);}//让b的生命值减小b.lifeDown();//如果炸弹生命值为0,就把该炸弹重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);//再画出敌人的子弹//System.out.println("坦克子弹有:"+et.ss.size());for(int j=0;j<et.ss.size();j++){//取出子弹Shot enemyShot=et.ss.get(j);if(enemyShot.isLive){//System.out.println("第 "+i+"坦克的 "+j+"颗子弹x="+enemyShot.x);g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1,false);}else{//如果敌人的坦克死亡就从Vector去掉et.ss.remove(enemyShot);}}}}}//paint(Graphics g)函数完
//class MyPanel未完//public void hitMe()函数敌人的坦克是否击中我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();}}}}}}//写一个函数专门判断子弹是否击中敌人坦克public boolean hitTank(Shot s,Tank 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);//放入Vectorbombs.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);//放入Vectorbombs.add(b);}}return b2;}//画出坦克的函数(扩展)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;}//判断方向switch(direct){//向上case 0://画出我的坦克(到时再封装成一个函数)//1.画出左边的矩形g.fill3DRect(x, y, 5, 30,false);//2.画出右边矩形g.fill3DRect(x+15,y , 5, 30,false);//3.画出中间矩形g.fill3DRect(x+5,y+5 , 10, 20,false);//4.画出圆形g.fillOval(x+5, y+10, 10, 10);//5.画出线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://向下//画出我的坦克(到时再封装成一个函数)//1.画出左边的矩形g.fill3DRect(x, y, 5, 30,false);//2.画出右边矩形g.fill3DRect(x+15,y , 5, 30,false);//3.画出中间矩形g.fill3DRect(x+5,y+5 , 10, 20,false);//4.画出圆形g.fillOval(x+5, y+10, 10, 10);//5.画出线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;}}//键按下处理 a 表示向左 s 表示 下 w 表示向上 d表示右public void keyPressed(KeyEvent arg0) {// TODO Auto-generated method stubif(arg0.getKeyCode()==KeyEvent.VK_W){//设置我的坦克的方向this.hero.setDirect(0);this.hero.moveUp();}else if(arg0.getKeyCode()==KeyEvent.VK_D){//向右this.hero.setDirect(1);this.hero.moveRight();}else if(arg0.getKeyCode()==KeyEvent.VK_S){//向下this.hero.setDirect(2);this.hero.moveDown();}else if(arg0.getKeyCode()==KeyEvent.VK_A){//向左this.hero.setDirect(3);this.hero.moveLeft();}if(arg0.getKeyCode()==KeyEvent.VK_J){//判断玩家是否按下j//开火//System.out.println("this.hero.ss.size()="+this.hero.ss.size());if(this.hero.ss.size()<=4){this.hero.shotEnemy();}}//必须重新绘制Panelthis.repaint();}public void keyReleased(KeyEvent arg0) {// TODO Auto-generated method stub}public void keyTyped(KeyEvent arg0) {// TODO Auto-generated method stub}//class MyPanel的线程函数public void run() {// TODO Auto-generated method stub//每隔100毫秒去重绘while(true){try {Thread.sleep(100);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}this.hitEnemyTank();//函数,判断敌人的子弹是否击中我this.hitMe();//重绘this.repaint();}}
}//class MyPanel完
Members.java
package org.example;import javax.sound.sampled.*;
import java.io.*;
import java.util.Vector;
public class Members{}//播放声音的类
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 AePlayWave extends Thread完
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()函数public Vector<Node> getNodesAndEnNums(){try {fr=new FileReader("d:\\myRecording.txt");br=new BufferedReader(fr);String n="";//先读取第一行n=br.readLine();allEnNum=Integer.parseInt(n);while((n=br.readLine())!=null){String []xyz=n.split(" ");Node node=new Node(Integer.parseInt(xyz[0]),Integer.parseInt(xyz[1]),Integer.parseInt(xyz[2]));nodes.add(node);}} catch (Exception e) {e.printStackTrace();// TODO: handle exception}finally{try {//后打开则先关闭br.close();fr.close();} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}return nodes;}//保存击毁敌人的数量和敌人坦克坐标,方向public void keepRecAndEnemyTank(){try {//创建fw=new FileWriter("d:\\myRecording.txt");bw=new BufferedWriter(fw);bw.write(allEnNum+"\r\n");System.out.println("size="+ets.size());//保存当前活的敌人坦克的坐标和方向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 (Exception e) {e.printStackTrace();// TODO: handle exception}finally{//关闭流try {//后开先关闭bw.close();fw.close();} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}//从文件中读取,记录public static void getRecoring(){try {fr=new FileReader("d:\\myRecording.txt");br=new BufferedReader(fr);String n=br.readLine();allEnNum=Integer.parseInt(n);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}finally{try {//后打开则先关闭br.close();fr.close();} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}//把玩家击毁敌人坦克数量保存到文件中public static void keepRecording(){try {//创建fw=new FileWriter("d:\\myRecording.txt");bw=new BufferedWriter(fw);bw.write(allEnNum+"\r\n");} catch (Exception e) {e.printStackTrace();// TODO: handle exception}finally{//关闭流try {//后开先关闭bw.close();fw.close();} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}public static int getEnNum() {return enNum;}public static void setEnNum(int enNum) {Recorder.enNum = enNum;}public static int getMyLife() {return myLife;}public static void setMyLife(int myLife) {Recorder.myLife = myLife;}//减少敌人数public static void reduceEnNum(){enNum--;}//消灭敌人public static void addEnNumRec(){allEnNum++;}public static int getAllEnNum() {return allEnNum;}public static void setAllEnNum(int allEnNum) {Recorder.allEnNum = allEnNum;}public Vector<EnemyTank> getEts() {return ets;}public void setEts(Vector<EnemyTank> ets1) {this.ets = ets1;System.out.println("ok");}
}
//炸弹类
class Bomb{//定义炸弹的坐标int x,y;//炸弹的生命int life=9;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;int speed=1;//是否还活着boolean isLive=true;public Shot(int x,int y,int direct){this.x=x;this.y=y;this.direct=direct;}public void run() {while(true){try {Thread.sleep(50);} catch (Exception e) {// TODO: handle exception}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 Tank {//表示坦克的横坐标int x=0;//坦克纵坐标int y=0;//坦克方向//0表示上 1表示 右 2表示下 3表示左int direct=0;int color;boolean isLive=true;//坦克的速度int speed=3;public Tank(int x,int y){this.x=x;this.y=y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getDirect() {return direct;}public void setDirect(int direct) {this.direct = direct;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}public int getColor() {return color;}public void setColor(int color) {this.color = color;}
}
//敌人的坦克,把敌人做成线程类
class EnemyTank extends Tank 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);}//得到MyPanel的敌人坦克向量public void setEts(Vector<EnemyTank> vv){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==3||et.direct==1){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==3||et.direct==1){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==3||et.direct==1){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==3||et.direct==1){//上一点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;}public void run() {// TODO Auto-generated method stubwhile(true){switch(this.direct){case 0://说明坦克正在向上for(int i=0;i<30;i++){if(y>0&&!this.isTouchOtherEnemy()){y-=speed;}try {Thread.sleep(50);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}break;case 1://向右for(int i=0;i<30;i++){//保证坦克不出边界if(x<400&&!this.isTouchOtherEnemy()){x+=speed;}try {Thread.sleep(50);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}break;case 2://向下for(int i=0;i<30;i++){if(y<300&&!this.isTouchOtherEnemy()){y+=speed;}try {Thread.sleep(50);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}break;case 3://向左for(int i=0;i<30;i++){if(x>0&&!this.isTouchOtherEnemy()){x-=speed;}try {Thread.sleep(50);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}break;}this.times++;if(times%2==0){if(isLive){if(ss.size()<5){//System.out.println("et.ss.size()<5="+et.ss.size());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){//让坦克死亡后,退出线程.break;}}}
}
//我的坦克
class Hero extends Tank {//子弹//Shot s=null;Vector<Shot> ss=new Vector<Shot>();Shot s=null;public Hero(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;}
}
相关文章:

JAVA坦克大战游戏v3
JAVA坦克大战游戏v3 素材 bomb_3.gif bomb_2.gif bomb_1.gif 项目结构 游戏演示 MyTankGame3.java /*** 功能:坦克游戏的5.0[]* 1.画出坦克.* 2.我的坦克可以上下左右移动* 3.可以发射子弹,子弹连发(最多5)* 4.当我的坦克击中敌人坦克时,敌人就消失(爆炸的效…...

使用acme,自动续签免费的SSL,无忧http升级https
使用acme自动续签免费的SSL 安装acme.sh颁发域名将证书安装到nginx下配置nginx的ssl自动续签 这里只进行最简单的操作 安装acme.sh 进入你的用户目录,如果你使用root登陆,那么你的用户目录就是 /root/ curl https://get.acme.sh | sh -s emailmyexam…...

Uniapp笔记(五)uniapp语法4
本章目标 授权登录【难点、重点】 条件编译【理解】 小程序分包【理解】 一、授权登录 我的模块其实是两个组件,一个是登录组件,一个是用户信息组件,根据用户的登录状态判断是否要显示那个组件 1、登录的基本布局 <template><…...
编写一个yolov5的模型检测,只要运行后,就不结束,只要有文件放入到文件夹中,就去执行读取
编写一个yolov5的模型检测,只要运行后,就不结束,只要有文件放入到文件夹中,就去执行读取 import os import cv2 import torch from torchvision import transforms from PIL import Image from yolo.model import YOLO…...

vscode调试PHP代码
目录 准备工作ssh的连接以及配置调试 准备工作 1.首先你需要下载一个vscode 2.下载模块 你需要在VScode中去下载我们所需的两个模块PHP Debug以及remote -ssh 3.安装对应版本的xdebug 需要在xdebug的官方去进行分析,选择适合你自己版本的xdebug 去往官方&#x…...

js reverse实现数据的倒序
2023.8.25今天我学习了如何在数组顺序进行倒序排列,如: 原数组为: 我们只需要对数组使用reverse()方法 let demo [{id: 1, name: 一号},{id: 2, name: 二号},{id: 3, name: 三号},]demo.reverse()console.log(demo) 扩展: 当我…...

日常踩坑记录
本篇文章主要介绍一下最近的开发中用到的些小问题。问题不大,但有些小细节,记录一下,有遇到的朋友可以看一下,有更好的解决方法欢迎分享。 浏览器记住密码自动填充表单 这个问题我在火狐浏览器遇到了。我登录系统时选择了浏览器…...

threejs特殊几何体(一:文字几何体对象)
threejs中文字几何体通过newTextGeometry()生成,它被单独作为一个类存在于threejs中const txtGeo new TextGeometry("threejs", { ...opts, font: font }); 我们先看效果: <template><div></div> &…...
链表的实现
本程序List链表用两种方式实现,一种是双向链表,一种是双向循环链表。循环双向链表和双向链表,它们的编码差别很小;但是循环链表在插入效率上胜出很多,同时查询时候更灵活。综合考虑,循环链表是首选。 另外…...
c++ std::mutex与std::condition_variable
1. std::mutex lock()加锁; try_lock()尝试加锁; unlock()解锁; std::mutex m_mutex; m_mutex.lock(); ... m_mutex.unlock(); 2. std::lock_guard 类模板;等同自动锁,直接取代lock()和unlock(); 构造时加锁,析构时解锁; std::mutex m_mutex; {std::lock_guard<std:…...

Aspose.Tasks for .NET V23Crack
Aspose.Tasks for .NET V23Crack 改进了大型项目的内存占用。 添加了API,允许您在应用程序无法访问系统字体文件夹时指定用户的字体文件夹。 Aspose.Tasksfor.NET是处理MicrosoftProject文件的可靠的项目管理API。API支持在不依赖Microsoft Project的情况下读取、写…...

vue过渡及动画
文章目录 前言类名使用自己定义动画样式多个元素过渡使用第三方库 前言 对于vue中的过渡与动画,官网上是这样概述的: Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。包括以下工具: 在 CSS 过渡和动画中自动…...

Linux环境下SVN服务器的搭建与公网访问:使用cpolar端口映射的实现方法
文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…...
【ubuntu】 DNS 设置工具 resolvectl
什么是 resolvectl “resolvectl” 是一个用于管理系统 DNS 解析配置的命令行工具。它是 systemd-resolved 服务的一部分,该服务是在许多基于 Systemd 的 Linux 发行版中用于管理网络配置和 DNS 解析的系统服务。 通过 resolvectl 命令,可以查看当前系…...

Keepalived+Lvs(dr)调度器主备配置小实验
目录 前言 一、实验拓扑图 二、配置LVS(dr)模式 三、配置调配器热备 四、测试 总结 前言 Keepalived和LVS(Linux Virtual Server)是两个常用的开源软件,通常结合使用以提供高可用性和负载均衡的解决方案。 Keepalive…...

第四讲Java基本语法——数组结构(多维数组)
前言 前面几讲,我们讲了Java基本语法,初学者也能够有一定的入门。本讲,我们也是继续来讲解一下Java另一个基础语法——数组,其实在前面讲解数据类型的时候,我们也有提到数组是引用类型,那今天我们就来分析一下什么是数组,怎么用数组呢? 一、数组是什么 数组是…...
【题解】JZOJ6578 / 洛谷P5201[USACO2019Jan]Shortcut G
洛谷 P5201 [USACO19JAN] Shortcut G 题意 在一个带权无向连通图上,每个点有 a i a_i ai 只奶牛,奶牛会走最短路径到 1 1 1,如果有多条路径,选择字典序最小的,定义移动总时间为所有奶牛走到 1 1 1 的时间之和。…...

npm install sentry-cli失败的问题
1. 目前报错 2. 终端运行 npm set ENTRYCLI_CDNURLhttps://cdn.npm.taobao.org/dist/sentry-cli npm set sentrycli_cdnurlhttps://cdn.npm.taobao.org/dist/sentry-cli3. 再安装 npx sentry/wizardlatest -i nextjs即可成功...
Node opensslErrorStack 错误解决方法记录
从Git仓库中下载了一个老项目,使用npm install 安装后没有问题,当我使用npm run dev 的时候遇到了 OpenSSL 相关错误,例如 opensslErrorStack: [error:03000086:digital envelope routines::initialization error] 网上找了一下相关信息&am…...

你知道什么是Grandmillennial风格吗,进来看看吧
如果你既欣赏祖母的印花棉布扶手椅和大胆的图案,又喜欢千禧一代朋友现代家居中的开放空间和时尚家具,那么 "千禧一代 “风格就是为你量身打造的。它借鉴了几十年来的流行趋势,形成了一种独特的、带有现代风格的老式设计。 在典型的 &quo…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...