Java实现坦克大战(1990有木有勾起童年回忆)

笔者最近一个星期又抽时间学习了一点点Java多线程编程,结合swing绘图做了一个特别简单版的坦克大战游戏。

功能说明:

1.仅仅有一关;英雄坦克(自己)只有一条命--不过可以很好的扩展,只要把MyPanel中的SuperTank做成跟敌人坦克一样的Vector即可;

2.右侧的调速面板仅可以调整我军坦克速度;子弹速度目前不可面板自动调整;

3.敌军总共20辆坦克,同时显示的有3辆;击毁一辆会在左上角自动增加一辆,直到上限20辆;

4.目前敌军坦克的移动完全是随机的,没有加入敌军向目标攻击的概率函数控制(后续优化);

 

代码说明:

1.我本机是编写了三个*.java文件,当然拷贝后,完全可以直接在一个文件中粘贴并编译;

 

游戏截图:

 

/**
 * 坦克大战
 * 1.Created by Light on 2014-8-1  画坦克
 * 2.Modified by Light on 2014-8-1 让坦克按照键盘的方向键实现移动
 * 3.Modified by Light on 2014-8-1 让坦克发子弹,并且让子弹飞
 * 4.Modified by Light on 2014-8-4 让敌人坦克自由行动,让子弹打到坦克时,坦克和子弹都消失,让坦克少于三个时自动增加
 * 5.Modified by Light on 2014-8-4 优化敌军坦克行动代码和让敌军坦克发射子弹
 * 6.Modified by Light on 2014-8-5 让敌军的坦克发射子弹也能击毁英雄坦克
 */
package com.firstversion;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


import javax.swing.*;
public class TankGame extends JFrame implements ActionListener{

	/**
	 * 不知道这是干什么用的,后续补充
	 */
	private static final long serialVersionUID = 1L;
	MyPanel mp ;
	oprationPanel mep;
	JSplitPane jsplit;
	JButton friend, enemy,speedUp,speedDown;
	JLabel speedArea;
	//主函数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new TankGame();
	}
	//坦克游戏的构造函数
	public TankGame()
	{
		mp = new MyPanel();
		
		mep = new oprationPanel();
		jsplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		//暂时把分隔窗口收起功能注释掉,免的窗口发生变化导致坦克开出边界
		//jsplit.setOneTouchExpandable(true);
		
		friend = new JButton("友军");
		friend.addActionListener(mp);
		friend.setActionCommand("friend");
		friend.addKeyListener(mp);
		//http://blog.csdn.net/hn1232/article/details/4224863
		//因在另外一个Panel上添加button导致键盘监听失效,参考上面的博文将每个Button都加了键盘监听,功能恢复了,但是现在不明白原理
		enemy = new JButton("敌军");
		enemy.addActionListener(mp);
		enemy.setActionCommand("enemy");
		enemy.addKeyListener(mp);
		
		speedUp = new JButton("加速");
		speedUp.addActionListener(this);
		speedUp.addActionListener(mp);
		speedUp.setActionCommand("speedUp");
		speedUp.addKeyListener(mp);
		
		speedDown = new JButton("减速");
		speedDown.addActionListener(this);
		speedDown.addActionListener(mp);
		speedDown.setActionCommand("speedDown");
		speedDown.addKeyListener(mp);
		
		speedArea = new JLabel(String.valueOf(mp.st.getSpeed()));
		
		
		//Layout
		mep.add(friend);
		mep.add(enemy);
		mep.add(speedUp);
		mep.add(speedDown);
		mep.add(speedArea);
		
		jsplit.setLeftComponent(mp);
		jsplit.setRightComponent(mep);
		this.add(jsplit);
		
		//Listener set
		this.addKeyListener(mp);
		
		//启动MyPanel
		Thread t = new Thread(mp);
		t.start();
		
		//设置JFrame
		this.setSize(600, 450);
		this.setResizable(false);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLocation(350, 180);
		this.setVisible(true);
		jsplit.setDividerLocation(0.88);
		

	}
	
	//写一个方法用于刷新speedArea
	public void refreshSpeed()
	{
		speedArea.setText(String.valueOf(this.mp.st.getSpeed()));
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		this.refreshSpeed();	
		this.repaint();
	}

}


package com.firstversion;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.*;
import javax.swing.JPanel;
import java.lang.Thread;


//个人Panel,用于重写paint方便自定义
class MyPanel extends JPanel implements KeyListener,ActionListener,Runnable
{
	/**
	 * 暂时不清楚这个是干什么用的
	 */
	private static final long serialVersionUID = 1L;
	//英雄坦克
	SuperTank st = null;	
	//敌军坦克,使用Vector来装敌军坦克群
	int enemyNum = 3;
	Vector<EnemyTank> enemyTanks = null;
	//个人Panel构造方法
	
	public MyPanel()
	{
		//初始化英雄坦克-->位置在底层中央,方向朝上
		st = new SuperTank(250,350);
		//初始化敌人坦克,并为每个坦克启动一个线程-->在上层,方向朝下
		enemyTanks = new Vector<EnemyTank>();
		for(int i=0;i<enemyNum;i++)
		{
			//初始化敌军坦克
			EnemyTank et = new EnemyTank(i*100,0);
			//初始化敌军坦克的类型和方向
			et.setDirection(3);
			et.setTankType(1);
			//将敌军坦克装载Vector中管理
			enemyTanks.addElement(et);
			//System.out.println("装了"+(i+1)+"个");
			//System.out.println("总共"+(enemyTanks.size())+"个");
			Thread t = new Thread(this.enemyTanks.get(i));
			t.start();
		}
				
	}
	
	//重写paint方法
	public void paint(Graphics g)
	{
		super.paint(g);
		//设置一下背景颜色
		g.fillRect(0, 0, 600, 450);
		//画英雄坦克
		if(this.st.isLive())
		{
			this.createTank(this.st.getX(),this.st.getY(),g,this.st.getTankType(),this.st.getDirection());
		}
		
		//画英雄坦克子弹,要先判断子弹是否存在(子弹集是否为空)并且是否存活
		if(!(this.st.bulletVector.isEmpty()))//子弹集不为空
		{
			for(int i=0;i<this.st.bulletVector.size();i++)//遍历子弹集
			{
				Bullet b = this.st.bulletVector.get(i);
				if(b.isLive())//子弹为存活状态
				{
					//画子弹,x和y是取得子弹当前的最新坐标参照点
					g.fillOval(b.getX(), b.getY(), 4, 4);
				}
			}
		}
			
		//画敌军坦克 for
		for(int i=0;i<enemyTanks.size();i++)
		{
			//System.out.println("画了"+(i+1)+"个");
			//System.out.println("总共"+(enemyTanks.size())+"个");
			EnemyTank et = this.enemyTanks.get(i);
			if(et.isLive())
			{
				this.createTank(et.getX(),et.getY(),g,et.getTankType(),et.getDirection());
			}
			//System.out.println("画了"+(i+1)+"个");
			//画敌军坦克子弹
			for(int j=0;j<et.bulletVector.size();j++)
			{
				Bullet b = et.bulletVector.get(j);
				if(b.isLive())
				{
					//画子弹,x和y是取得子弹当前的最新坐标参照点
					g.fillOval(b.getX(), b.getY(), 4, 4);
				}
			}
		}
		
	}
	
	//专门写一个方法来创建坦克-->参数:初始横坐标/初始纵坐标/画笔/坦克类型/坦克方向	
	public void createTank(int x,int y,Graphics g,int tankType, int direction)
	{
		//先根据tankType判断坦克类型
		switch(tankType)
		{//0-->自己; 1--> 敌军
		case 0: g.setColor(Color.YELLOW); break; //暂时使用颜色来标识tankType
		case 1: g.setColor(Color.CYAN); break;
		}
		//接着根据direction判断坦克朝向,因为坦克朝不同的方向画法可能不一样,比如炮筒的画法和旗帜的画法肯定不一样
		switch(direction)
		{//0-->right; 1-->left; 2-->up; 3-->down;
		case 0: //认为是朝右
			//画两条履带
			g.fill3DRect(x, y, 60, 10, false);
			g.fill3DRect(x, y+30, 60, 10, false);
			//画坦克体
			g.fill3DRect(x+10, y+10, 30, 20, false);
			//画盖子
			g.fillOval(x+18, y+13, 14, 14);
			//画炮筒+炮筒头(略粗一点点)
			g.drawLine(x+25, y+20, x+60, y+20);
			g.drawLine(x+55, y+19, x+60, y+19);
			g.drawLine(x+55, y+21, x+60, y+21);
			break;
		case 1://朝左-->由朝右掉头
			//画两条履带
			g.fill3DRect(x, y, 60, 10, false);
			g.fill3DRect(x, y+30, 60, 10, false);
			//画坦克体
			g.fill3DRect(x+20, y+10, 30, 20, false);
			//画盖子
			g.fillOval(x+28, y+13, 14, 14);
			//画炮筒+炮筒头(略粗一点点)
			g.drawLine(x+35, y+20, x, y+20);
			g.drawLine(x+5, y+19, x, y+19);
			g.drawLine(x+5, y+21, x, y+21);
			break;
		case 2://朝上-->由朝右转头
			//画两条履带
			g.fill3DRect(x, y, 10, 60, false);
			g.fill3DRect(x+30, y, 10, 60, false);
			//画坦克体
			g.fill3DRect(x+10, y+20, 20, 30, false);
			//画盖子
			g.fillOval(x+13, y+28, 14, 14);
			//画炮筒+炮筒头(略粗一点点)
			g.drawLine(x+20, y, x+20, y+35);
			g.drawLine(x+19, y, x+19, y+5);
			g.drawLine(x+21, y, x+21, y+5);
			break;
		case 3://朝下-->由朝上掉头
			//画两条履带
			g.fill3DRect(x, y, 10, 60, false);
			g.fill3DRect(x+30, y, 10, 60, false);
			//画坦克体
			g.fill3DRect(x+10, y+10, 20, 30, false);
			//画盖子
			g.fillOval(x+13, y+18, 14, 14);
			//画炮筒+炮筒头(略粗一点点)
			g.drawLine(x+20, y+10, x+20, y+60);
			g.drawLine(x+19, y+55, x+19, y+60);
			g.drawLine(x+21, y+55, x+21, y+60);
			break;
		}
		
	}
	
	//写一个方法或者当前Panel中存活的敌军坦克数
	public int getAliveTanks()
	{
		int aliveTankNum = 0;
		for(int i=0;i<this.enemyTanks.size();i++)
		{
			EnemyTank et = this.enemyTanks.get(i);
			if(et.isLive())
			{
				aliveTankNum++;
			}
		}
		return aliveTankNum ;
	}

	//写一个方法判断面板中的子弹是否与坦克遭遇,遭遇则将坦克置为isLive = false
	public void gotTarget(Bullet b,EnemyTank et)
	{
		//一定要判断子弹和坦克是否存活,不然会碰到幽灵坦克和幽灵子弹
		if(b.isLive() && et.isLive())
		{
			//需要根据坦克的方向来判断
			switch(et.getDirection())
			{
			case 0:
			case 1: 
				if(b.getX()>et.getX() && b.getX() < et.getX()+56 && b.getY()>et.getY() && b.getY()<et.getY()+36)
				{
					b.setLive(false);//将子弹置为死亡
					et.setLive(false);//将坦克置为死亡
				}
				break;
			case 2:
			case 3: 
				if(b.getX()>et.getX() && b.getX()<et.getX()+36 && b.getY()>et.getY() && b.getY()<et.getY()+56)
				{
					b.setLive(false);//将子弹置为死亡
					et.setLive(false);//将坦克置为死亡
				}
				break;			
			}
		
		}
	}

	//写一个方法判断英雄坦克死亡
	public void isSuperDead(Bullet b,SuperTank st)
	{
		//先判断敌军子弹是否存活
		if(b.isLive() && st.isLive())
		{
			//需要根据坦克的方向来判断
			switch(st.getDirection())
			{
			case 0:
			case 1: 
				if(b.getX()>st.getX() && b.getX() < st.getX()+56 && b.getY()>st.getY() && b.getY()<st.getY()+36)
				{
					b.setLive(false);//将子弹置为死亡
					st.setLive(false);//将坦克置为死亡
				}
				break;
			case 2:
			case 3: 
				if(b.getX()>st.getX() && b.getX()<st.getX()+36 && b.getY()>st.getY() && b.getY()<st.getY()+56)
				{
					b.setLive(false);//将子弹置为死亡
					st.setLive(false);//将坦克置为死亡
				}
				break;			
			}
		}
	}
	//写一个方法加入坦克

	public void addEnemyTank()
	{
		EnemyTank et = new EnemyTank(0,0);
		et.setDirection(3);
		et.setTankType(1);
		//一定记得把坦克加入到Vector中,不然尼玛取不到,也画不出来
		this.enemyTanks.add(et);
		Thread t = new Thread(et);
		t.start();
	}
	
	@Override //重写监听方法
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getActionCommand().equals("friend"))
		{
			this.st.setTankType(0);
		}else if(e.getActionCommand().equals("enemy"))
		{
			this.st.setTankType(1);
		}else if(e.getActionCommand().equals("speedUp"))
		{
			this.st.setSpeed(this.st.getSpeed()+1);
			
		}else if(e.getActionCommand().equals("speedDown"))
		{
			if((this.st.getSpeed()-1)>0)
			{
				this.st.setSpeed(this.st.getSpeed()-1);
			}else{
				this.st.setSpeed(1);
			}
			
		}else{
			System.out.println("真神奇,你竟然能让程序跑到这个逻辑来!");
		}
		this.repaint();
	}

	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub
		if(e.getKeyCode()==KeyEvent.VK_S)
		{
			this.st.setDirection(3);//控制方向
			this.st.move(this.st.getDirection());
		}else if(e.getKeyCode()==KeyEvent.VK_W)
		{
			this.st.setDirection(2);
			this.st.move(this.st.getDirection());
		}else if(e.getKeyCode()==KeyEvent.VK_A)
		{
			this.st.setDirection(1);
			this.st.move(this.st.getDirection());
		}else if(e.getKeyCode()==KeyEvent.VK_D)
		{
			this.st.setDirection(0);
			this.st.move(this.st.getDirection());
		}
		//判断发射子弹
		if(e.getKeyCode()==KeyEvent.VK_J)
		{
			this.st.fair();
		}
		
		this.repaint();
	}

	@Override//释放键盘
	public void keyReleased(KeyEvent ke) {
		// TODO Auto-generated method stub
		
	}

	@Override//打印字符
	public void keyTyped(KeyEvent ke) {
		// TODO Auto-generated method stub
		
	}

	
	@Override
	public void run() {
		// 重写run()方法,刷新整个MyPanel
		while(true)
		{
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//System.out.println("刷新了一次!");//测试使用
			//判断子弹是否击中敌军坦克
			for(int i=0;i<this.st.bulletVector.size();i++)
			{
				Bullet b = this.st.bulletVector.get(i);
				for(int j=0;j<this.enemyTanks.size();j++)
				{
					EnemyTank et = this.enemyTanks.get(j);
					this.gotTarget(b, et);
				}
			}
			//判断英雄坦克是否死亡-->对每辆坦克的每颗子弹进行判断
			for(int i=0;i<this.enemyTanks.size();i++)
			{
				if(this.enemyTanks.get(i).isLive())
				{
					EnemyTank et = this.enemyTanks.get(i);
					for(int j=0;j<et.bulletVector.size();j++)
					{
						if(et.bulletVector.get(j).isLive())
						{
							Bullet b = et.bulletVector.get(j);
							this.isSuperDead(b, this.st);
						}
					}
				}
			}
			//判断敌军坦克是否需要增加,少于三个存活的坦克则增加到三个,总数达到20个则不再增加
			if(this.getAliveTanks()<3 && this.enemyTanks.size()<20)
			{
				this.addEnemyTank();
			}
			//敌军射击
			for(int j=0;j<this.enemyTanks.size();j++)
			{
				if(this.enemyTanks.get(j).isLive())
				{
					this.enemyTanks.get(j).fair();
				}
			}
			
			//重新调用repaint()
			this.repaint();					
		}		
	}	
}




//操作面板类
class oprationPanel extends JPanel
{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public oprationPanel()
	{
		
	}
	
}


package com.firstversion;

import java.util.*;

class Tank
{
	private int x=100;//坦克初始位置的横坐标
	private int y=100;//坦克初始位置的纵坐标
	private int direction=2; //坦克的朝向
	private int speed=4;//坦克的速度
	private int tankType=0;//坦克类型
	private boolean isLive = true ;//坦克默认存活

	Vector<Bullet> bulletVector = null;//使用Vector是为了使每个打出去的子弹都是一个线程,同时每个坦克可以打出多个子弹
	//成员属性访问和设置方法群
	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 getDirection() {
		return direction;
	}
	public void setDirection(int direction) {
		this.direction = direction;
	}
	public int getSpeed() {
		return speed;
	}
	public void setSpeed(int speed) {
		this.speed = speed;
	}
	public int getTankType() {
		return tankType;
	}
	public void setTankType(int tankType) {
		this.tankType = tankType;
	}
	public boolean isLive() {
		return isLive;
	}
	public void setLive(boolean isLive) {
		this.isLive = isLive;
	}


	
	//坦克构造函数,很重要,对于需要在其他位置调用的成员属性,在此都需要初始化,不然会报空指针
	public Tank(int x, int y)
	{
		this.x=x;
		this.y=y;
		//这句话初始化Vector一定要有的,不然会在MyPanel中调用出现空指针错误
		bulletVector = new Vector<Bullet>();
		
	}
	//坦克移动的能力方法,以方向为入参
	public void move(int direction)
	{//0-->right; 1-->left; 2-->up; 3-->down;
		switch(direction)
		{
		case 0: if(x+speed<455) x+=speed; break;
		case 1: if(x-speed>0) x-=speed; break;
		case 2: if(y-speed>0) y-=speed; break;
		case 3: if(y+speed<362) y+=speed; break;
		default: break;
		}
		//System.out.println("跑了一次!");
	}

	//判断当前坦克存活子弹数
	public int getAliveBullets()
	{
		int aliveBulletNum =0 ;
		for(int i=0;i<this.bulletVector.size();i++)
		{
			Bullet b = this.bulletVector.get(i);
			if(b.isLive())
			{
				aliveBulletNum++;
			}
		}
		return aliveBulletNum;
	}
}

class SuperTank extends Tank
{
	
	public SuperTank(int x,int y)
	{
		super(x,y);//使用父类的能够匹配(参数个数与类型完全一致)的构造函数
	}
	//fair
	public void fair()
	{//每次开火就产生一个子弹,也就是子弹类的实例对象,加入到bulletVector中的最后一位,再从最后一个取取出来启动线程
		if(this.getAliveBullets()<3)
		{
			switch(this.getDirection())
			{
			case 0: bulletVector.addElement(new Bullet(this.getX()+60,this.getY()+18,this.getDirection())); break;
			case 1: bulletVector.addElement(new Bullet(this.getX()-4,this.getY()+18,this.getDirection())); break;
			case 2: bulletVector.addElement(new Bullet(this.getX()+18,this.getY()-4,this.getDirection())); break;
			case 3: bulletVector.addElement(new Bullet(this.getX()+18,this.getY()+60,this.getDirection()));break;
			}
			//在每次发射动作之后,就要启动这个线程
			Thread t = new Thread(bulletVector.lastElement());
			t.start();
		}

	}
}


//敌军坦克类,因为敌军坦克需要自己走动,所以实现Runnable接口,另每一个敌军坦克对象作为一个线程
class EnemyTank extends Tank implements Runnable
{
	private boolean isMoving = false ;
	private int fairController = 25 ;

	public int getFairController() {
		return fairController;
	}
	public void setFairController(int fairController) {
		this.fairController = fairController;
	}

	public boolean isMoving() {
		return isMoving;
	}
	public void setMoving(boolean isMoving) {
		this.isMoving = isMoving;
	}
	public EnemyTank(int x, int y) {
		super(x, y);
	}
	//fair automatically -- fair controller
	//fair
	public void fair()
	{//每次开火就产生一个子弹,也就是子弹类的实例对象,加入到bulletVector中的最后一位,再从最后一个取取出来启动线程
		if(this.fairController>0)
		{
			this.fairController--;
			//System.out.println("不发射子弹");
		}else
		{
			//System.out.println("发射子弹");
			switch(this.getDirection())
			{
			case 0: bulletVector.addElement(new Bullet(this.getX()+60,this.getY()+18,this.getDirection())); break;
			case 1: bulletVector.addElement(new Bullet(this.getX()-4,this.getY()+18,this.getDirection())); break;
			case 2: bulletVector.addElement(new Bullet(this.getX()+18,this.getY()-4,this.getDirection())); break;
			case 3: bulletVector.addElement(new Bullet(this.getX()+18,this.getY()+60,this.getDirection()));break;
			}
			//在每次发射动作之后,就要启动这个线程
			Thread t = new Thread(bulletVector.lastElement());
			t.start();
			this.setFairController(25);
		}
		
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		int i =500;
		int j =3;
		while(true)
		{
			//休眠
			try {
				Thread.sleep(i);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//随机秒	
			i = (int)(Math.random()*5000);
			//开始计时毫秒级时间
			Date d = new Date();
			long longtime = d.getTime();
			//测试打印代码
			//System.out.println(longtime);
			//System.out.println(longtime+i);
			//System.out.println((new Date()).getTime());
			
			//随机方向
			j = ((int)(Math.random()*100))%4;
			//一定要按照随机的方向给敌军坦克设置方向,不能只定义移动方向,不然你会看到坦克横着开
			this.setDirection(j);
			//休眠结束时,将坦克置为移动状态
			this.setMoving(true);
			//在随机数期间保持运动
			while(true)
			{
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				Date d2 = new Date();
				//System.out.println("d2:"+d2.getTime());
				if(longtime+i>d2.getTime())
				{
					//调用移动方法
					this.move(j);
				}else{
					//停止时发射一个子弹
					this.fair();
					break;
				}
			}
			
			//退出循环时,将坦克置为静止
			this.setMoving(false);
			//在坦克静止时,每隔2~3s发射一颗子弹
			//判断线程退出
			if(this.isLive()==false)
			{
				break;
			}
		}
	}
}



//子弹类,作为线程处理
class Bullet implements Runnable
{
	private int x;
	private int y;
	private int speed = 5;//妈的这个地方坑死老子了,打了子弹就是不走,最后找到初始速度尼玛默认为0了
	private int direction;
	private boolean isLive = true;//默认子弹是激活的
	
	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 getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public int getDirection() {
		return direction;
	}

	public void setDirection(int direction) {
		this.direction = direction;
	}

	public boolean isLive() {
		return isLive;
	}

	public void setLive(boolean isLive) {
		this.isLive = isLive;
	}

	//Bullet构造方法
	public Bullet(int x, int y, int direction)
	{
		this.x=x;
		this.y=y;
		this.direction=direction;
	}
	
	@Override//重写run()方法
	public void run(){
		//在fair()的方法中,会调用start(),进而似的run()得以执行,所以在run()中需要包含当前子弹线程结束的逻辑判断
		//需要进行当前子弹的方向的判断
		while(true)
		{
			try {
				Thread.sleep(100);//每100毫秒变化一次初始位置,这样在MyPanel中进行repaint()就可以实现让子弹飞了
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			switch(this.direction)
			{
			case 0: x+=this.speed; break;
			case 1: x-=this.speed; break;
			case 2: y-=this.speed; break;
			case 3: y+=this.speed; break;
			}
			
			//System.out.println("子弹坐标:["+this.x+","+this.y+"]");//测试使用
			//判断子弹到边界自动退出线程
			if(x<0||y<0||x>600||y>450)
			{
				this.setLive(false);//将子弹状态置为非激活,作为后面在画子弹时需要判断的条件
				break;
				//这里不知道怎么在退出线程时,清除Vector中已经消亡的子弹;初步考虑应该在外部按照时间和子弹状态来清除子弹
			}else if(this.isLive==false){
				break;
			}
				
		}

	}
	
}


 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前言: 作者系四川大学计算机科学系毕业,但是毕业后十几年都没有编过程序,干的工作有抄水电表,网管,销售工作,最近发现人渐渐老去,有心愿未了,于是最近跟着网络视频教学,学习了一下VC++和面向对象编程,就自已小时候最爱玩的坦克大战为练习,来熟悉和巩固对VC++的学习。 本作特点: 1. 可能是世界上最接近“坦克大战”原作的VC程序. 几乎99%相似模拟度。 2. 本作还特别包括“坦克90”加强版。 3. 即时存档,读档功能。 4. 即时回退,时光倒流功能。 5. 播放战斗录相功能。 6. 智能躲避敌方攻击的功能。(在演示状态) 7. 敌方坦克智能躲避工方攻击的功能。(在TANKE90模式) 8. 对Win7兼容性不好, 运行会变慢 9. 本作是精确到象素级的模拟原作了. 如何编译: 1. 运行VC6. 2. 用打开工作空间的方式, 打开Tank.dsw 3. 如编译出现Diretx方面的错,请下载directx8程序包http://115.com/file/clqzomlm#dx81sdk.zip 加入到你的VC6里面, 如何安装请查网上. 4. 根目录下有Tank.exe已经编译好的了, 你可以试一试, 360可能会误报, 但保证没有病毒. 不信你自已编译好后, 也可能会误报 后记: 本次放出的是DirectX版本, 如有其它问题请联系作者. 作者邮箱: [email protected] 另外,还有一个CFrame版本,和一个WIN32版本,这两个版本效率不高,但兼容性好,有需要的联系。
========================================================== 局域网坦克大战V1.0使用说明 版权所有 (c)2011, 卓跃计算机职业培训学校。 作者 :余松鹰 ---------------------------------------------------------- 1.请确保游戏客户端(TankGame_Client.jar)的同级目录下存在img图片资源文件夹和sounds声音文件夹。 2.请确保游戏服务器端(TankGame_Server.jar)的同级目录下存在map文件夹且文件夹内至少存在一个以上的 XX.MAP文件,并且还存在游戏服务器配置文件ServerData.xml文件和用户信息文件Data.xml。 3.使用游戏地图编辑器(TankGame_MapEditer.jar)必须存在img地图编辑器图片资源文件 4.游戏开始顺序 1).打开游戏服务器端(TankGame_Server.jar)服务器端显示“服务器启动成功”。 2).打开客户端(TankGame_Client.jar)输入用户名和密码,若为新用户可注册后登录。(系统管理 员用户名admin,密码admin)。 3).点击连接服务器,控制玩家P1的用户可以选择地图,选择地图完后点击准备按钮,准备开始游 戏。 4).第二位用户登录完服务器,并按下了准备就开始游戏。 5.地图编辑器的编辑地图 1).打开地图编辑器,按照帮助菜单内的说明完成地图编辑后,保存地图将在地图编辑器的同级 目录产生一个.MAP文件,该文件既为用户编辑产生的地图。 2).将该地图放到服务器端(TankGame_Server.jar)的map文件内重启服务器端即可使用地图进行 游戏。 6.服务器端在关闭时,将在服务器端的同级目录下生产服务器日志(ServerLog.txt),该日志记录服务器 启动和关闭的时间,以及用户的登录和退出。 7.用户可在服务器配置文件(ServerData.xml)中修改服务器端口号

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值