JAVA坦克大战游戏v3

news2024/10/4 21:16:06

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);
			//显示,刷新JFrame
			this.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 stub
		while(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;
				//创建一颗炸弹,放入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);
			}
		}
		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 stub
		if(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();
			}
		}
		//必须重新绘制Panel
		this.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 stub
		while(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;
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/928926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉查找树、平衡二叉树、红黑树到底怎么插入调整?不用旋转快速实现

目录 时间复杂度二叉查找树二叉查找树的插入二叉查找树的删除 平衡二叉树平衡二叉树的插入平衡二叉树的删除 红黑树红黑树的插入红黑树的删除 时间复杂度 首先二叉查找树、平衡二叉树、红黑树的时间复杂度如下所示&#xff1a; 红黑树和二叉查找树的时间复杂度是一样的&#x…

电测知识分享——雷达行业必读热点!脉冲和跳频脉冲信号的生成与解调教程来了

按照信号分类&#xff0c;雷达通常有两种基本类型&#xff1a;连续波(CW)雷达和脉冲雷达。 连续波雷达多为小型的简易雷达。在应用中有单载频连续被和调制连续波两大类。单载频连续被雷达只能测速不能测距&#xff0c;广泛用于各种测速系统&#xff0c;比如交警的测速雷达。调…

自研软件太贵、购买成品软件太死板?不怕,我这有高招

传统IT自研软件开发&#xff0c;通过编程去写代码&#xff0c;还有数据库、API、第三方基础架构等。从而造成开发周期长、难度大&#xff0c;技术人员不易于开发维护&#xff0c;因此价格及时间成本也是相对较高。后期出现了可以直接应用的成品软件&#xff0c;以及现在火热的低…

GAN原理 代码解读

模型架构 代码 数据准备 import os import time import matplotlib.pyplot as plt import numpy as np import torchvision.transforms as transforms from torch.utils.data import DataLoader from torchvision import datasets import torch.nn as nn import torch# 创建文…

docker compose iceberg 快速体验

https://iceberg.apache.org/spark-quickstart/#docker-compose port&#xff1a;8888

回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测

回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现GA-APSO-IBP改进遗传-粒子群算法优化双层BP神经网络多输入单输出回归预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现GA-…

DPU在东数西算背景下如何赋能下一代算力基础设施 中科驭数在未来网络发展大会论道

以ChatGPT为代表的人工智能大模型的快速发展&#xff0c;对网络信息技术创新发展提出了新的挑战&#xff0c;我国东数西算重大工程也在加速布局。以确定性网络、算力网络为代表的未来网络核心技术&#xff0c;正成为决定未来经济和产业发展的关键。 8月23日&#xff0c;第七届…

学生分班查询系统的创建与使用指南

开学季&#xff0c;负责分班工作的老师们又面临一个难题&#xff1a;如何公布分班结果&#xff1f;将结果放在学校官网上可能会让很多无关人员看到&#xff0c;而不放则会导致家长们纷纷打电话来询问。那么&#xff0c;有没有一种方法可以让家长们自行查看分班结果呢&#xff1…

【SLAM】光流 - LK光流 - 金字塔分层LK光流

在SLAM的视觉里程计中&#xff0c;比较常用的就是特征点法和直接法。而直接法中&#xff0c;光流则是其中的重点内容&#xff0c;比如LSD-SLAM中就使用到了光流的方法。本文将会就光流的理论原理、公式推导进行详细的剖析&#xff0c;以帮助读者深刻地理解。 光流算法 光流是关…

每日一练 | 华为认证真题练习Day103

1、网络设备发送的IPv6报文时&#xff0c;会首先将报文长度和NTU值进行对比&#xff0c;如果大于MTU值&#xff0c;则直接丢弃。 A. 对 B. 错 2、路由器接口输出信息如下&#xff0c;则此接口可以接收哪些组播地址的数据&#xff1f; &#xff08;多选&#xff09; A. FF02::…

中国储能行业研究报告,光伏和风电领域装机量迅速增长

随着科学技术的进步&#xff0c;储能工业对我们的生活产生了深远的影响。电池技术的突破使得手机使用寿命更长&#xff0c;家庭储能系统使得能源管理更加智能和高效。人们通过对于储能的需求进行不断发展增长&#xff0c;将目光投向更环保可持续的解决问题方案。这个行业的发展…

计算机丢失msvcp140.dll是什么意思,要怎么处理呢?

今天&#xff0c;我将和大家探讨一个关于计算机的问题——“计算机丢失msvcp140.dll是什么意思&#xff0c;要怎么处理呢&#xff1f;”这个问题可能会在很多使用计算机的朋友中遇到。希望通过今天的演讲&#xff0c;能够帮助大家解决这个困扰。 首先&#xff0c;我们来了解一…

DevOps中的持续测试优势和工具

持续测试 DevOps中的持续测试是一种软件测试类型&#xff0c;它涉及在软件开发生命周期的每个阶段测试软件。持续测试的目标是通过早期测试和经常测试来评估持续交付过程的每一步的软件质量。 DevOps中的持续测试流程涉及开发人员、DevOps、QA和操作系统等利益相关者。 持续…

CC++ 常用技巧

C 中的C C 是面向过程的是把整个大程序分为一个个的子函数&#xff1b;C 是面向对象的是把整个程序划分为一个个的类。C 是完全兼容C 的&#xff0c;C 是C 的子集&#xff0c;C 是C 的超集。C 又对C 做了很多补充和提升&#xff0c;因此使用C 会比使用纯C 更方便。混用C和C&am…

《软件开发的201个原则》阅读笔记 120-161条

目录 使用有效的测试完成度标准 原则122 达成有效的测试覆盖 原则123 不要在单元测试之前集成 原则 124 测量你的软件 原则125 分析错误的原因 对错不对人 原则127 好的管理比好的技术更重要 使用恰当的方法 原则 129 不要相信你读到的一切 原则130 理解客户的优先级 原…

千人千面的分析?SpeedBI数据可视化工具也很擅长

SpeedBI数据可视化工具可以实现千人千面的分析&#xff0c;通过个性化的数据展示和交互式分析功能&#xff0c;让每个人都可以根据自己的需求和业务背景进行数据分析和可视化。 SpeedBI数据可视化工具支持多维自助分析&#xff0c;可以帮助用户深入探索和分析数据。以下是Spee…

超店有数最新报告!美国TikTok小店全新洗牌?搏一把的机会到了

据传&#xff0c;TikTok美国市场的半闭环模式将于8月底关闭&#xff0c;其将在美国全力发展全闭环。也就是说&#xff0c;想要继续在TikTok美区卖货&#xff0c;必须开通TikTok小店&#xff0c;官方不给放外链了。 如果消息属实&#xff0c;全闭环模式开启&#xff0c;美国Tik…

抖音电商,从消费者体验中做增量

夜晚总是最容易emo&#xff0c;也最容易冲动的时候。 王雪临睡前刷着抖音&#xff0c;看到一家化妆品品牌在直播&#xff0c;刚好最近她想买抗老精华&#xff0c;点进去听主播小姐姐介绍一番后下了单。第二天早上起来犹豫要不要退货&#xff0c;再货比三家时&#xff0c;手机收…

stm32之DHT11

今天&#xff0c;记录一下DHT11&#xff0c;涉及到了单总线协议&#xff0c;所以先花点时间谈论一下单总线协议&#xff08;DS18B20也是用的单总线&#xff09;。 单总线协议 单总线技术的通信协议 可能这时序图就是个例子&#xff0c;ds18b20的时序图与DHT11的时序图也是不一…

服务器中了mkp勒索病毒该怎么办?勒索病毒解密,数据恢复

mkp勒索病毒算的上是一种比较常见的勒索病毒类型了。它的感染数量上也常年排在前几名的位置。所以接下来就由云天数据恢复中心的技术工程师来对mkp勒索病毒做一个分析&#xff0c;以及中招以后应该怎么办。 一&#xff0c;中了mkp勒索病毒的表现 桌面以及多个文件夹当中都有一封…