纯Java实现坦克大战游戏,源码公开

前言

近日最做项目,很多网友在问题是否有游戏的代码分享,故总结了去年开发的一款小游戏坦克大战,源码公开,大家一起研究改进
 * 功能:坦克大战游戏
 * 1、画出我的坦克
 * 2、让我的坦克动起来
 * 3、让我的坦克按下空格(space)键发射子弹
 * 4、让我的坦克可以连发子弹(最多连发5颗子弹)
 * 5、打到敌人坦克,敌人坦克就消失
 * 6、加入坦克被击中爆炸的效果
 * 7、让敌人的坦克可以自由随机移动
 * 8、控制坦克在指定的MyPanel面板中移动,不可越界
 * 9、让敌人的坦克发射子弹
 * 10、当我的坦克被敌人子弹击中,我的坦克爆炸
 * 11、防止敌人坦克重叠运动
 * 12、可以分关--做一个开始的Panel,它是空的主要是提示关卡
 * 13、游戏可以暂停、继续--暂停时将子弹、坦克速度设为0,坦克方向不变
 * 14、可以记录玩家的成绩
 * 15、java如何操作声音文件

一、源码

package com.haiding.tank_7;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.*;
import javax.sound.sampled.*;
public class MyTank07 extends JFrame implements ActionListener{
	//定义组件
	MyPanel 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) {
		MyTank07 mt=new MyTank07();
	}
	//构造函数
	public MyTank07(){
		//创建菜单及菜单选项
		jmb=new JMenuBar();
		jm1=new JMenu("游戏(G)");
		//设置快捷方式
		jm1.setMnemonic('G');
		jmi1=new JMenuItem("开始新游戏(N)");
		jmi1.setMnemonic('N');
		//对jmi1相应
		jmi1.addActionListener(this);
		jmi1.setActionCommand("newgame");
		
		jmi2=new JMenuItem("退出游戏(E)");
		jmi2.setMnemonic('E');
		jmi2.addActionListener(this);
		jmi2.setActionCommand("exit");
		
		jmi3=new JMenuItem("存盘退出(S)");
		jmi3.setMnemonic('S');
		jmi3.addActionListener(this);
		jmi3.setActionCommand("save");
		
		jmi4=new JMenuItem("继续游戏(C)");
		jmi4.setMnemonic('C');
		jmi4.addActionListener(this);
		jmi4.setActionCommand("congame");
		
		jm1.add(jmi1);
		jm1.add(jmi2);
		jm1.add(jmi3);
		jm1.add(jmi4);
		jmb.add(jm1);
		this.setJMenuBar(jmb);
		
		//构建组件
		msp=new MyStartPanel();
		Thread t=new Thread(msp);
		t.start();
		this.add(msp);
		
		//设置JFrame窗体
		this.setTitle("坦克大战");//JFrame标题
		this.setSize(600, 500);//JFrame窗体大小
		this.setLocationRelativeTo(null);//在屏幕中心显示
		this.setVisible(true);//显示
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//退出并关闭JFrame
	}

	public void actionPerformed(ActionEvent e) {
		//对用户不同的点击,做出不同的处理
		if(e.getActionCommand().equals("newgame")){
			//创建战场面板
			mp=new MyPanel("newgame");
			//启动mp线程
			Thread ta=new Thread(mp);
			ta.start();
			//先删除旧的开始面板
			this.remove(msp);
			//加入组件
			this.add(mp);
			//监听
			this.addKeyListener(mp);
			//显示,刷新JFrame
			this.setVisible(true);
		}else if(e.getActionCommand().equals("exit")){
			//用户点击了退出菜单
			//保存用户游戏记录数据
			Recorder.keepRecording();
			System.exit(0);
		}else if(e.getActionCommand().equals("save")){
			//用户点击保存菜单
			//保存击毁敌人的数量和敌人的坐标
			Recorder.setEts(mp.ets);
			Recorder.keepRecAndEnemyTank();
			System.exit(0);
		}else if(e.getActionCommand().equals("congame")){
			//继续上次游戏
			//创建战场面板
			mp=new MyPanel("congame");
			
			//启动mp线程
			Thread ta=new Thread(mp);
			ta.start();
			//先删除旧的开始面板
			this.remove(msp);
			//加入组件
			this.add(mp);
			//监听
			this.addKeyListener(mp);
			//显示,刷新JFrame
			this.setVisible(true);
		}
	}
}
//开始面板--起提示作用
class MyStartPanel extends JPanel implements Runnable{
	int times=0;
	public void paint(Graphics g){
		super.paint(g);
		g.setColor(Color.black);
		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() {
		while(true){
			//休眠
			try {
				Thread.sleep(500);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			times++;
			//重画
			this.repaint();
		}
	}
}

//我的面板Panel
class MyPanel extends JPanel implements KeyListener,Runnable{//MyPanel继承Jpanel面板,创建KeyListener键盘接口和Runnable线程接口
	//定义一个我的坦克
	Hero hero=null;
	//定义声音播放
	AePlayWave apw=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;
		
	//构造函数
	public MyPanel(String flag){
		hero=new Hero(200, 270);//我的坦克初始位置
		//恢复游戏记录
		Recorder.getRecoring();
		if(flag.equals("newgame")){
			//播放开战声音
			apw=new AePlayWave("e:\\tankgame\\tankmusic.wav");
			apw.start();
			//初始化敌人的坦克
			for(int i=0;i<enSize;i++){
				//创建一辆敌人的坦克对象
				EnemyTank et=new EnemyTank((i+1)*50, 0);
				//初始敌人坦克颜色
				et.setColor(2);
				//初始敌人坦克的方向
				et.setDirect(1);
				
				//将MyPanel的敌人向量交给该敌人坦克
				et.setEts(ets);
				
				//启动敌人坦克进程
				Thread t=new Thread(et);
				t.start();
				
				//给敌人坦克添加一颗子弹
				Shot s=new Shot(et.x+10, et.y+30, 1);
				//把子弹加入给敌人
				et.ss.add(s);
				Thread t2=new Thread(s);
				t2.start();
				
				//加入敌人坦克
				ets.add(et);
			}
		}else if(flag.equals("congame")){
			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(2);
				//初始敌人坦克的方向
				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, 1);
				//把子弹加入给敌人
				et.ss.add(s);
				Thread t2=new Thread(s);
				t2.start();
				
				//加入敌人坦克
				ets.add(et);
			}
		}
		
		//初始化爆炸图片
		try {
			image1=ImageIO.read(new File("bomb1.gif"));
			image2=ImageIO.read(new File("bomb2.gif"));
			image3=ImageIO.read(new File("bomb3.gif"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//画出提示信息
	public void showInfo(Graphics g){
		//画出提示信息坦克(该坦克不参与战斗,只是用于显示提示信息)
		this.drawTank(80, 330, g, 1, 0);
		g.setColor(Color.BLACK);
		g.setFont(new Font("宋体",Font.BOLD,20));
		g.drawString(Recorder.getEnNum()+"", 110, 350);//显示敌人坦克数量
		
		this.drawTank(140, 330, g, 0, 0);
		g.setColor(Color.BLACK);
		g.setFont(new Font("宋体",Font.BOLD,20));
		g.drawString(Recorder.getMyLife()+"", 170, 350);//显示我的坦克数量
	
		//画出玩家的总成绩
		g.setColor(Color.black);
		g.setFont(new Font("宋体",Font.BOLD,20));
		g.drawString("您的总成绩", 420, 30);
		
		this.drawTank(420, 60, g, 1, 0);
		g.setColor(Color.black);
		g.setFont(new Font("宋体",Font.BOLD,20));
		g.drawString(Recorder.getAllEnNum()+"", 460, 80);
	}
	
	//重写paint函数
	public void paint(Graphics g){
		super.paint(g);//调用父类paint方法
		
		//画出提示信息
		this.showInfo(g);
		
		//设置Panel底色
		g.setColor(Color.black);
		g.fillRect(0, 0, 400, 300);//fillRect(0,0,X?,Y?)中X?/Y?为活动区域
		
		//画出自己的坦克
		if(hero.isLive==true){
			this.drawTank(hero.getX(), hero.getY(), g, 0, this.hero.direct);
		}
		
		//从ss向量中取出每一颗子弹并画出
		for(int i=0;i<this.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);
			}
			//判断子弹是否死亡
			if(myShot.isLive==false){
				//从向量ss中删除该子弹
				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>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, 1, et.getDirect());
				//再画出敌人坦克的子弹
				for(int j=0;j<et.ss.size();j++){
					//取出子弹
					Shot enemyShot=et.ss.get(j);
					if(enemyShot.isLive){
						g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false);
					}else{
						//如果敌人的坦克死亡了就从向量Vector中去掉
						et.ss.remove(enemyShot);
					}
				}
			}
		}
	}
	
	//判断我的子弹是否击中敌人的坦克
	public void hitEnemyTank(){
		//遍历Vector集合类
		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)){
							apw=new AePlayWave("e:\\tankgame\\tank_explosion.wav");
							apw.start();
							//调用reduceEnNum()减少敌人坦克统计数
							Recorder.reduceEnNum();
							//调用addEnNumRec()增加消灭敌人坦克统计数
							Recorder.addEnNumRec();
						}
					}
				}
			}
		}
	}
	
	//判断敌人的子弹是否击中我的坦克
	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 boolean hitTank(Shot s,Tank et){
		boolean b=false;
		//判断该敌人坦克的方向
		switch(et.direct){
		case 0://敌人坦克向上或向下
		case 1:
			if(s.x>et.x&&s.x<et.x+20&&s.y>et.y&&s.y<et.y+29){
				//击中方向为上或下的敌人坦克
				//子弹死亡
				s.isLive=false;
				//敌人坦克死亡
				et.isLive=false;
				b=true;
				//创建一颗炸弹
				Bomb bomb=new Bomb(et.x, et.y);
				//放入Vector向量中管理
				bombs.add(bomb);
			}
			break;
		case 2://敌人坦克向左或向右
		case 3:
			if(s.x>et.x&&s.x<et.x+29&&s.y>et.y&&s.y<et.y+20){
				//击中方向为左或右的敌人坦克
				//子弹死亡
				s.isLive=false;
				//敌人坦克死亡
				et.isLive=false;
				b=true;
				//创建一颗炸弹
				Bomb bomb=new Bomb(et.x, et.y);
				//放入Vector向量中管理
				bombs.add(bomb);
			}
			break;
		}
		return b;
	}
	
	//画出坦克的函数
	public void drawTank(int x,int y,Graphics g,int type,int direct){
		//判断是什么类型的坦克
		switch(type){
		case 0:
			g.setColor(Color.cyan);//我的坦克颜色
			break;
		case 1:
			g.setColor(Color.yellow);//敌人坦克颜色
			break;
		case 2:
			g.setColor(Color.red);
			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, 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+29);
			break;
		//向左走的坦克
		case 2:
			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;
		//向右走的坦克
		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+29, y+10);
			break;
		}
	}

	public void keyPressed(KeyEvent e) {//按下键事件a向左s向下d向右w向上
		if(e.getKeyCode()==KeyEvent.VK_W||e.getKeyCode()==KeyEvent.VK_UP){
			//向上
			this.hero.setDirect(0);
			this.hero.moveUp();
		}else if(e.getKeyCode()==KeyEvent.VK_S||e.getKeyCode()==KeyEvent.VK_DOWN){
			//设置我的坦克的方向,向下
			this.hero.setDirect(1);
			this.hero.moveDown();
		}else if(e.getKeyCode()==KeyEvent.VK_A||e.getKeyCode()==KeyEvent.VK_LEFT){
			//向左
			this.hero.setDirect(2);
			this.hero.moveLeft();
		}else if(e.getKeyCode()==KeyEvent.VK_D||e.getKeyCode()==KeyEvent.VK_RIGHT){
			//向右
			this.hero.setDirect(3);
			this.hero.moveRight();
		}
		
		//判断玩家是否按下空格键,不可接上面else if。不然不能同时按方向键和空格(space)键
		if(e.getKeyCode()==KeyEvent.VK_SPACE){
			apw=new AePlayWave("e:\\tankgame\\tank_Shelling_sound.wav");
			apw.start();
			//控制子弹连发
			if(this.hero.ss.size()<=4){
				//按下空格后开火
				this.hero.shotEnemy();
			}
		}
		
		//调用repaint()函数,来重绘界面
		this.repaint();
	}

	public void keyReleased(KeyEvent e) {//弹起键事件
		
	}
	
	public void keyTyped(KeyEvent e) {//按键输出值
		
	}

	//重写run函数
	public void run() {
		while(true){
			try {
				Thread.sleep(100);//休息100毫秒后重绘MyPanel面板
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			this.hitEnemyTank();
			//判断敌人的子弹是否击中我的坦克
			this.hitMe();

			//重绘MyPanel面板
			this.repaint();
		}
	}
}

二、成员类

package com.haiding.tank_7;

import java.util.Vector;
import java.io.*;
import javax.sound.sampled.*;

//播放声音的类
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[2048];

		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,y,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;
	//从文件中恢复记录点
	private 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 static Vector<EnemyTank> ets=new Vector<EnemyTank>();
	
	//完成读取任务点任务
	public static Vector<Node> getNodesAndEnNums(){
		try {
			fr=new FileReader("e:\\tankgame\\tanksave.txt");
			br=new BufferedReader(fr);
			String n="";
			//先读一行
			n=br.readLine();
			allEnNum=Integer.parseInt(n);		
			while((n=br.readLine())!=null){
				String []Recovery=n.split(" ");//split方法可以按一行字符中有多少个空间来返回数组
				Node node=new Node(Integer.parseInt(Recovery[0]),Integer.parseInt(Recovery[1]),Integer.parseInt(Recovery[2]));
				nodes.add(node);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				br.close();
				fr.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
		return nodes;
	}
	
	//保存击毁敌人的数量和敌人坦克坐标、方向
	public static void keepRecAndEnemyTank(){
		try {
			//创建
			fw=new FileWriter("e:\\tankgame\\tanksave.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;//得到坐标x,y和方向direct
					//写入到文件
					bw.write(recode+"\r\n");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//关闭流,先开后关,后开先关
			try {
				bw.close();
				fw.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	//从文件中读取记录
	public static void getRecoring(){
		try {
			fr=new FileReader("e:\\tankgame\\tanksave.txt");
			br=new BufferedReader(fr);
			String n=br.readLine();
			allEnNum=Integer.parseInt(n);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				br.close();
				fr.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}
	//把玩家击毁敌人坦克数量保存到文件中
	public static void keepRecording(){
		try {
			//创建
			fw=new FileWriter("e:\\tankgame\\tanksave.txt");
			bw=new BufferedWriter(fw);
			bw.write(allEnNum+"\r\n");
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//关闭流,先开后关,后开先关
			try {
				bw.close();
				fw.close();
			} catch (Exception e) {
				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 static void setMyLife(int myLife) {
		Recorder.myLife = myLife;
	}
	
	public static Vector<EnemyTank> getEts() {
		return ets;
	}

	public static void setEts(Vector<EnemyTank> ets) {
		Recorder.ets = ets;
	}
	
	//敌人坦克死亡就减少坦克数
	public static void reduceEnNum(){
		enNum--;
	}
	//当消灭敌人的时候
	public static void addEnNumRec(){
		allEnNum++;
	}
}

//炸弹类
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,y,direct,speed=3;//初始子弹x,y坐标,direct子弹方向,speed子弹速度

	//子弹是否还活着
	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);//让子弹休息50毫秒,防止快速消费内存
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			switch(direct){
				case 0://向上
					y-=speed;
					break;
				case 1://向下
					y+=speed;
					break;
				case 2://向 左
					x-=speed;
					break;
				case 3://向右
					x+=speed;
					break;
			}
			//子弹何时死亡
			//判断该子弹是否碰到MyPanel面板的边缘
			if(x<0||x>400||y<0||y>300){
				this.isLive=false;
				break;
			}
		}
	}
}

//定义坦克类
class Tank{
	//表示坦克的X横坐标Y纵坐标
	int x=0,y=0;
	//direct坦克方向,0向上、1向下、2向左、3向右
	int direct=0;
	//坦克的速度
	int speed=1;
	//坦克颜色
	int color;
	
	boolean isLive=true;

	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 move=30;//敌人坦克移动步长(区域)
	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> tank){
		this.ets=tank;
	}
	
	//判断敌人坦克是否重叠
	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==1){
						//判断敌人当前坦克左轮与同伴坦克(向上或向下)的位置比较
						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==2||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==1){
						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==2||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 2://敌人当前坦克向左
			for(int i=0;i<ets.size();i++){
				EnemyTank et=ets.get(i);
				if(et!=this){
					if(et.direct==0||et.direct==1){
						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==2||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;
		case 3://敌人当前坦克向右
			for(int i=0;i<ets.size();i++){
				EnemyTank et=ets.get(i);
				if(et!=this){
					if(et.direct==0||et.direct==1){
						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==2||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;
		}
		return b;
	}

	//重写run()函数
	public void run() {
		while(true){
			switch(this.direct){
			case 0://坦克正在向上移动
				for(int i=0;i<move;i++){
					if(y>0&&!this.isTouchOtherEnemy()){//判断敌人坦克向上走不会越界
						y-=speed;
					}
					try {
						Thread.sleep(50);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				break;
			case 1://向下移动
				for(int i=0;i<move;i++){
					if(y<400&&!this.isTouchOtherEnemy()){//判断敌人坦克向下走不会越界
						y+=speed;
					}
					try {
						Thread.sleep(50);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				break;
			case 2://向左移动
				for(int i=0;i<move;i++){
					if(x>0&&!this.isTouchOtherEnemy()){//判断敌人坦克向左走不会越界
						x-=speed;
					}
					try {
						Thread.sleep(50);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				break;
			case 3://向右移动
				for(int i=0;i<move;i++){
					if(x<300&&!this.isTouchOtherEnemy()){//判断敌人坦克向右走不会越界
						x+=speed;
					}
					try {
						Thread.sleep(50);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				break;
			}
			
			this.times++;
			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+10, y+29, 1);
							ss.add(s);
							break;
						case 2:
							s=new Shot(x, y+10, 2);
							ss.add(s);
							break;
						case 3:
							s=new Shot(x+29, 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>();//Vector线程安全的集合类
	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+10, y+29, 1);
			ss.add(s);
			break;
		case 2://向左
			s=new Shot(x, y+10, 2);
			ss.add(s);
			break;
		case 3://向右
			s=new Shot(x+29, 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;
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_41645135/article/details/121744182
今日推荐