坦克大戰(基於尚學堂版修改)

大概用了兩天半的課餘,一共四五個多小時的時間做的,一千行代碼的小遊戲。先實現了尚學堂版坦克大戰,一邊看PPT一邊自己寫,不會實現的地方看視頻,一點點做了來以後,然後根據自己的想法進行了修改:

1.      加強AI,優化了坦克撞牆不回頭的問題

2.      敵我使用兩種顏色子彈

3.      敵方坦克死光後,隨機生成十輛坦克,並避免卡牆。


代碼:

TankClient.java

import java.awt.*;
import java.util.*;
import java.awt.event.*;

public class TankClient extends Frame {
	Image offScreenImage = null;
	Tank tank = new Tank(600,325,this,Tank.Direction.STOP,true);
	LinkedList<Missile> missiles = new LinkedList<Missile>();
	LinkedList<Explode> explodes = new LinkedList<Explode>();
	LinkedList<Tank> tanks = new LinkedList<Tank>();
	LinkedList<Missile> eMissiles = new LinkedList<Missile>();
	Blood b = new Blood();
	Random r = new Random();							//添加隨機數,用於隨機生成坦克
	
	
	Wall w=new Wall(500, 200, 20, 250, this);
	
	public static final int WINDOW_HEIGHT = 600,WINDOW_WIDTH = 800;
	public static void main(String[] args) {
		new TankClient().launchFrame();
	}
	
	public void launchFrame(){
		for(int i=0;i<10;i++){
			tanks.add(new Tank(50, (50*i+120), this, Tank.Direction.D, false));
		}
		

		setBounds(600,300,WINDOW_WIDTH,WINDOW_HEIGHT);
		setVisible(true);
		this.setResizable(false);
		
		this.addKeyListener(new KeyMonitor());
		setBackground(Color.lightGray);
		addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e) 
			{
				setVisible(false);
				System.exit(0);
			}
		});
		
		new Thread(new rePaint()).start();

	}
	
	public void paint(Graphics g)
	{
		if(tanks.size()<=0){
			for(int i=0;i<10;i++){
				int newX,newY;
				Tank t = new Tank(newX=r.nextInt(500),newY=r.nextInt(600), this, Tank.Direction.D, false);		//用於隨機生成坦克

				while(new Rectangle(newX,newY,30,30).intersects( w.getRect())){								//與牆進行碰撞檢測
					t = new Tank(newX=r.nextInt(500),newY=r.nextInt(600), this, Tank.Direction.D, false);
				}
				
				tanks.add(t);
			}
		}
		Color c = g.getColor();
/*
		for(Missile m:missiles)    //用此種循環會出現Exception,故放棄
		{
			if(!m.getExist())
				missiles.remove(m);
			m.drawMissile(g);
			m.hitTank(eTank);
		}
*/	
		for(int i=0;i<missiles.size();i++){
			Missile m = missiles.get(i);
			m.hitTanks(tanks);
			m.hitTank(tank);
			m.drawMissile(g);
			m.hitWall(w);
		}
		
		for(int i=0;i<tanks.size();i++){
			Tank t = tanks.get(i);
			t.collidesWall(w);
			t.drawTank(g);
			t.collidesTanks(tanks);
		}
		tank.collidesWall(w);
		tank.collidesTanks(tanks);
		tank.eat();
		
		for(int i=0;i<explodes.size();i++)
		{
			Explode e = explodes.get(i);
			e.draw(g);
		}
		
		w.drawWall(g);
		b.draw(g);
		
		g.drawString("missiles count:"+missiles.size(), 30, 60);
		g.drawString("explodes count:"+explodes.size(), 30, 75);
		g.drawString("enemy tanks count:"+tanks.size(), 30, 90);
		g.drawString("tank life:"+tank.getLife(), 30, 105);
		tank.drawTank(g);
		
		
		g.setColor(c);
	}

	public void update(Graphics g){
		if(offScreenImage==null){
			offScreenImage = this.createImage(WINDOW_WIDTH, WINDOW_HEIGHT);
		}
		
		Graphics gOffScreen = offScreenImage.getGraphics();

		Color c = gOffScreen.getColor();
		gOffScreen.setColor(Color.lightGray);
		gOffScreen.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
		gOffScreen.setColor(c);
	
		paint(gOffScreen);
		g.drawImage(offScreenImage, 0, 0, null);
	} 

	private class rePaint implements Runnable{
		
		
		public void run(){
			while(true)
			{
				repaint();
				try {
					Thread.sleep(30);
				} catch (InterruptedException e) {
					e.printStackTrace();
			}
			}
		}
	}
	
	private class KeyMonitor extends KeyAdapter{
		public void keyPressed(KeyEvent e)
		{
			tank.keyPressed(e);

		}
		
		public void keyReleased(KeyEvent e)
		{
			tank.keyReleased(e);
		}
		
	}
}

Tank.java

import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class Tank {
	enum Direction {L,LU,U,UR,R,RD,D,LD,STOP};
	
	private static final int XSPEED = 5;
	private static final int YSPEED = 5;
	private static final int WIDTH = 30;
	private static final int HEIGHT = 30;
	
	private boolean good = true;
	private boolean live = true;
	private int life = 100;
	public int getLife() {
		return life;
	}

	public void setLife(int life) {
		this.life = life;
	}

	private int x,y;
	private int oldX,oldY;
	
	private static Random r = new Random();
	
	private boolean bL = false;
	private boolean bU = false;
	private boolean bR = false;
	private boolean bD = false;
	
	private boolean pL = false;
	private boolean pU = false;
	private boolean pR = false;
	private boolean pD = false;
	private Direction direc = Direction.STOP;
	private Direction ptDirec = Direction.D;
	private BloodBar bb = new BloodBar();
	
	private int step = r.nextInt(12)+3;
	TankClient tc;
	

	Tank(int x,int y, TankClient tc,Direction dir,Boolean good)
	{
		this.x = x;
		this.y = y;
		this.tc = tc;
		this.direc = dir;
		this.good = good;
		this.direc = dir;
		this.oldX = x;
		this.oldY = y;
		
		new Thread(new Runnable(){

			public void run() {
				
			}
			
		}).start();
	}

	public void drawTank(Graphics g){
		
		if(this.live==false)  {
			if(!good){
				tc.tanks.remove(this);
			}
			return;
		}
		Color c = g.getColor();
		
		if(good==true)
		g.setColor(Color.RED);
		else
		g.setColor(Color.BLUE);
		g.fillOval(x, y, 30, 30);
		
		g.setColor(Color.BLACK);
		bb.draw(g);
		
		switch(ptDirec){
		case D:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH/2, y+HEIGHT);
			break;
		case L:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x, y+HEIGHT/2);
			break;
		case LD:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x, y+HEIGHT);
			break;
		case LU:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x, y);
			break;
		case R:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH, y+HEIGHT/2);
			break;
		case RD:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH, y+HEIGHT);
			break;
		case U:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH/2, y);
			break;
		case UR:
			g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH, y);
			break;
		}
		g.setColor(c);

		move();
	}
	
	private synchronized void stay(){
		x = oldX;
		y = oldY;
		if(!this.good){
			switch(this.direc){						//坦克不會傻傻的頂着牆跑了
				case D:
					this.direc = Direction.U;
					break;
				case L:
					this.direc = Direction.R;
					break;
				case LD:
					this.direc = Direction.UR;
					break;
				case LU:
					this.direc = Direction.RD;
					break;
				case R:
					this.direc = Direction.L;
					break;
				case RD:
					this.direc = Direction.LU;
					break;
				case U:
					this.direc = Direction.D;
					break;
				case UR:
					this.direc = Direction.LD;
					break;
				default:
				step=r.nextInt(12)+3;					//優化:翻身撞牆後不會立即調整方向
		}
		}
	}
	
	private void move()
	{
		oldX = x;
		oldY = y;
		switch(direc){
		case D:
			y += YSPEED;
			break;
		case L:
			x -= XSPEED;
			break;
		case LD:
			x -= XSPEED;
			y += YSPEED;
			break;
		case LU:
			x -= XSPEED;
			y -= YSPEED;
			break;
		case R:
			x += XSPEED;
			break;
		case RD:
			x += XSPEED;
			y += YSPEED;
			break;
		case STOP:
			break;
		case U:
			y -= YSPEED;
			break;
		case UR:
			x += XSPEED;
			y -= YSPEED;
			break;
		}
		if(this.direc != Direction.STOP){
			ptDirec = direc;
		}
		
		while(x<0) x=0;
		while(y<30) y=30;
		while(x+Tank.WIDTH>TankClient.WINDOW_WIDTH ) x=TankClient.WINDOW_WIDTH-Tank.WIDTH;
		while(y+Tank.HEIGHT>TankClient.WINDOW_HEIGHT ) y=TankClient.WINDOW_HEIGHT-Tank.HEIGHT;
		
		if(!good){
			if(step==0){
				Direction[] dirs = Direction.values();
				int ranNum = r.nextInt(dirs.length);
				direc = dirs[ranNum];
				step=r.nextInt(12)+3;
			}
			step--;
			
			if(r.nextInt(40)>36){
				this.fire();
			}
			

			
		}
	}
	
	public void keyPressed(KeyEvent e)
	{
		int key = e.getKeyCode();
		switch(key){
		case KeyEvent.VK_DOWN:
			bD = true;
			pD = true;
			break;
		case KeyEvent.VK_LEFT:
			bL = true;
			pL = true;
			break;
		case KeyEvent.VK_UP:
			bU = true;
			pU = true;
			break;
		case KeyEvent.VK_RIGHT:
			bR = true;
			pR = true;
			break;

		}
		locate();
	}
	
	public void fire() {
		if(!live)	return;
		int x = this.x+this.WIDTH/2-Missile.WIDTH/2;
		int y = this.y+this.HEIGHT/2-Missile.HEIGHT/2;
		tc.missiles.add(new Missile(x,y,good,ptDirec,tc,this));		//修改構造函數
	}
	
	public void fire(Direction dir) {
		if(!live)	return;
		int x = this.x+this.WIDTH/2-Missile.WIDTH/2;
		int y = this.y+this.HEIGHT/2-Missile.HEIGHT/2;
		tc.missiles.add(new Missile(x,y,good,dir,tc,this));			//修改構造函數
	}
	
	public void superFire(){
		Direction[] dirs = Direction.values();
		for(int i=0;i<dirs.length-1;i++){
			fire(dirs[i]);
		}
	}

	public Direction getPtDirec() {
		return ptDirec;
	}

	public void setPtDirec(Direction ptDirec) {
		this.ptDirec = ptDirec;
	}

	public boolean isGood() {
		return good;
	}

	public void locate()
	{
		if(!bD && bL && !bU && !bR) direc = Direction.L;
		else if(!bD && bL && bU && !bR) direc = Direction.LU;
		else if(!bD && !bL && bU && !bR) direc = Direction.U;
		else if(!bD && !bL && bU && bR) direc = Direction.UR;
		else if(!bD && !bL && !bU && bR) direc = Direction.R;
		else if(bD && !bL && !bU && bR) direc = Direction.RD;
		else if(bD && !bL && !bU && !bR) direc = Direction.D;
		else if(bD && bL && !bU && !bR) direc = Direction.LD;
		else if(!bD && !bL && !bU && !bR) direc = Direction.STOP;
	
		
		/*
		if(!pD && bL && !pU && !pR) ptDirec = Direction.L;
		else if(!pD && pL && pU && !pR) ptDirec = Direction.LU;
		else if(!pD && !pL && pU && !pR) ptDirec = Direction.U;
		else if(!pD && !pL && pU && pR) ptDirec = Direction.UR;
		else if(!pD && !pL && !pU && pR) ptDirec = Direction.R;
		else if(pD && !pL && !pU && pR) ptDirec = Direction.RD;
		else if(pD && !pL && !pU && !pR) ptDirec = Direction.D;
		else if(pD && pL && !pU && !pR) ptDirec = Direction.LD;
	太麻煩!!!
		*/
	//	move();
	}

	public void keyReleased(KeyEvent e) {
		int key = e.getKeyCode();
		switch(key){
		case KeyEvent.VK_F2:{
			this.live = true;
			this.life = 100;
		}
		case KeyEvent.VK_DOWN:
			bD = false;
			pD = false;
			break;
		case KeyEvent.VK_LEFT:
			bL = false;
			pL = false;
			break;
		case KeyEvent.VK_UP:
			bU = false;
			pU = false;
			break;
		case KeyEvent.VK_RIGHT:
			bR = false;
			pR = false;
			break;
		case KeyEvent.VK_Z:
			this.fire();
			break;
		case KeyEvent.VK_X:
			superFire();
			break;
		}
		locate();
		
		
	}
	public boolean getLive()
	{
		return this.live;
	}
	
	public void setLive(boolean live)
	{
		this.live = live;
	}
	
	public Rectangle getRect()
	{
		return new Rectangle(x, y, WIDTH, HEIGHT);
	}
	
	public boolean collidesWall(Wall w){
		if(this.getRect().intersects(w.getRect())){
			stay();
			return true;
		}
		return false;
	}
	
	public boolean collidesTanks(java.util.List<Tank> tanks){
		for(int i=0;i<tanks.size();i++){
			Tank t = tanks.get(i);
			if(t!=this && this.live == true && t.getLive() == true &&this.getRect().intersects(t.getRect())){
				this.stay();
				t.stay();
				return true;
			}
		}
		return false;
	}
	
	public boolean eat(){
		if(this.live && tc.b.isLive() && tc.b.getRect().intersects(this.getRect())){
			this.life = 100;
			tc.b.setLive(false);
			return true;
		}
		return false;
	}
	
	private class BloodBar{
		protected void draw(Graphics g){
			Color c = g.getColor();
			
			int w = WIDTH*life/100;
			g.setColor(Color.red);
			g.drawRect(x, y-10, WIDTH, 5);
			g.fillRect(x, y-10, w, 5);
			
			g.setColor(c);
		}
	}
}

Missile.java

import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;

public class Missile {
	int x,y;
	TankClient tc;
	Tank.Direction direc;
	
	public static final int XSPEED = 12;
	public static final int YSPEED = 12;
	public static final int WIDTH = 10;
	public static final int HEIGHT = 10;
	
	private boolean exist = true;
	private boolean good;
	private Tank from;
	/*
	Missile(int x, int y,Tank.Direction direc){
		this.x = x;
		this.y = y;
		this.direc = direc;
	}
	
	Missile(int x, int y,Tank.Direction direc,TankClient tc){
		this.x = x;
		this.y = y;
		this.direc = direc;
		this.tc = tc;
	}
	*/
	Missile(int x, int y,boolean good,Tank.Direction direc,TankClient tc,Tank from){
		this.x = x;
		this.y = y;
		this.direc = direc;
		this.tc = tc;
		this.good = good;
		this.from = from;
	}
	
	public void drawMissile(Graphics g){
		if(this.exist==false){
			tc.missiles.remove(this);
			return;
		}
		Color c = g.getColor();
		
		if(!this.from.isGood()){
			g.setColor(Color.BLUE);
		}
		else
			g.setColor(Color.BLACK);
		g.fillOval(x, y, WIDTH, HEIGHT);

		g.setColor(c);
		move();
	}
	
	public void move(){
		switch(direc){
		case D:
			y += YSPEED;
			break;
		case L:
			x -= XSPEED;
			break;
		case LD:
			x -= XSPEED;
			y += YSPEED;
			break;
		case LU:
			x -= XSPEED;
			y -= YSPEED;
			break;
		case R:
			x += XSPEED;
			break;
		case RD:
			x += XSPEED;
			y += YSPEED;
			break;
		case U:
			y -= YSPEED;
			break;
		case UR:
			x += XSPEED;
			y -= YSPEED;
			break;
		}
		
		if(x <0 || y<0 || x>TankClient.WINDOW_WIDTH ||y>TankClient.WINDOW_HEIGHT)
			this.exist = false;
	}
	
	public Rectangle getRect()
	{
		return new Rectangle(x, y, WIDTH, HEIGHT);
	}
	
	public boolean getExist()
	{
		return this.exist;
	}
	
	public boolean hitTank(Tank t)
	{
			if(this.exist &&this.getRect().intersects(t.getRect()) && t.getLive() && this.good != t.isGood())	//碰撞檢測
			{
				if(t.isGood()){
					t.setLife(t.getLife()-10);
					if(t.getLife()<=0)
						t.setLive(false);
				}else{		
					t.setLife(t.getLife()-25);
					if(t.getLife()<=0)
						t.setLive(false);
				}
				this.exist = false;
				
				tc.explodes.add(new Explode(x,y,tc));
				return true;
			}
		
		return false;
	}
	
	public boolean hitTanks(LinkedList<Tank> tanks)
	{
		Tank t = null;
		for(int i=0;i<tc.tanks.size();i++){
			t = tanks.get(i);
			if(hitTank(t))
					{
				return true;
			}
		}
		return false;
	}
	
	public boolean hitWall(Wall w){
		if(this.exist == true && this.getRect().intersects(w.getRect())){
			this.exist = false;
		}
		return true;
	}
}

Wall.java

import java.awt.*;
/*
 * 坦克不能穿過
 * 子彈碰撞會消失
 */
public class Wall {
	private int x,y,width,height;
	TankClient tc;
	
	public Wall(int x,int y,int width,int height,TankClient tc){
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
		this.tc = tc;
	}
	
	public void drawWall(Graphics g)
	{
		Color c = g.getColor();
		g.fillRect(x, y, width, height);
		g.setColor(c);
	}
	
	public Rectangle getRect()
	{
		return new Rectangle(x,y,width,height);
	}
}

Explode.java

import java.awt.*;

public class Explode {
	private int x,y;
	private boolean live = true;
	private int[] diameter = {4 ,7 ,12 ,18 ,26 ,32 ,49 ,30 ,14 ,6}; 
	private int step = 0;
	private TankClient tc;
	
	public Explode(int x,int y,TankClient tc){
		this.x = x;
		this.y = y;
		this.tc = tc;
		
	}
	
	public void draw(Graphics g){
		if(live==false){
			tc.explodes.remove(this);
			return;
		}
		if(step==diameter.length){
			live = false;
			return;
		}
		Color c = g.getColor();
		g.setColor(Color.orange);
		g.fillOval(x, y, diameter[step], diameter[step]);
		g.setColor(c);
		step++;
	}
}

Blood.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

public class Blood {
	private int[][] loc = {
			{120,150},{130,170},{140,165},{150,135},{125,145},{123,147}};
	private static int width = 10;
	private static int height = 10;
	private int step = 0;
	private boolean live=true;
	
	public boolean isLive() {
		return live;
	}

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

	public void draw(Graphics g){
		if(!this.live)	return;
		Color c = g.getColor();
		
		g.setColor(Color.MAGENTA);
		g.fillRect(loc[step][0], loc[step][1], width, height);
		
		g.setColor(c);
		step++;
		if(step==loc.length)
			step=0;
	}
	
	public Rectangle getRect(){
		return new Rectangle(loc[step][0], loc[step][1], width, height);
	}
}


發佈了42 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章