Java——坦克大战(3)

本次实现:

  • 让敌方坦克能向随机方向移动
  • 敌我双方均能发射子弹且能击毁目标
  • 实现击中目标后产生爆炸效果
  • 优化相关细节及参数,将部分功能封装成一个(函数)方法
详细代码:
1、
package com.tank;

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

public class TankGame extends JFrame{
	
	MyPanel mp = null;
	
	public static void main(String[] args) {
		TankGame test = new TankGame();

	}
		
		//构造函数
	public TankGame(){
		mp = new MyPanel();
		Thread t  = new Thread(mp);
		t.start();//不启动run()方法不会定时重绘
		
		this.add(mp);
		this.addKeyListener(mp);
		
		this.setSize(410, 300);
		this.setTitle("坦克大战");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
		
	}
	

}

//炸弹类
class Bomb{
	int x, y;
	int life = 13;
	boolean isLive =true;
	
	public Bomb(int x, int y){
		this.x = x;
		this.y = y;
	}
	
	//生命周期	如不定义周期,爆炸效果会瞬间执行完毕
	public void lifeDown(){
		if (life>0){
			life--;
		}else{
			isLive = false;
		}	
	}
}


class MyPanel extends JPanel implements KeyListener, Runnable{
	//定义我的坦克
	Hero hero = null;
	
	//定义敌军坦克组,vector tanks 简写为vts
	Vector <Enemy> vts= new Vector <Enemy>();
	
	int eSize = 3;
	
	//定义一个炸弹集合
	Vector <Bomb> vBombs= new Vector<Bomb>();
	
	//定义三张爆炸效果图
	Image image1 = null;
	Image image2 = null;
	Image image3 = null;
	
	public MyPanel(){
		hero = new Hero(186, 235);
		hero.setColor(0);
		
		//初始化爆炸效果图
		image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
		image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));
		image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));
		//初始化敌军坦克
		for(int i=0; i<eSize; i++){
			Enemy eTank = new Enemy(i*186, 0);
			eTank.setColor(1);
			eTank.setDirect(1);
			vts.add(eTank);
			Thread t = new Thread(eTank);
			t.start();
			
		}
		
	}
	
	//判断英雄坦克是否击中目标
	public void hitEnemy(){
		//取出每一颗存活的炮弹与坦克进行对比
		for(int i=0; i<hero.vb.size(); i++){
			Bullet b = hero.vb.get(i);
			if(b.isLive){	//如果炮弹存活,则取出敌方存活的坦克与其匹配
				for(int j=0; j<vts.size(); j++){
					Enemy e = vts.get(j);
					if(e.isLive){
						this.isHit(b, e);//对比该炮弹是否击中该敌军坦克(即炮弹进入该坦克坐标区域)
					}
				}
			}
		}
	}
	//判断敌方坦克是否击中hero坦克
	public void hitHero(){
		//取出敌方坦克
		for(int i=0; i<vts.size(); i++){
			//取出坦克
			Enemy e = vts.get(i);
			//取出每一颗敌方炮弹
			for(int j=0; j<e.eb.size(); j++){
				Bullet b = e.eb.get(j);
				this.isHit(b, hero);
			}
		}
	}
	
	
	
	//重写paint方法
	public void paint(Graphics g){
		super.paint(g);
		g.fillRect(0, 0, 410, 300);
		
		//调用画坦克函数 画出英雄的坦克
		if(hero.isLive){
			this.drawTank(this.hero.getX(), this.hero.getY(), g, this.hero.getDirect(), this.hero.getColor());
		}
		
		//从vb向量中取出炮弹
		for(int i=0; i<hero.vb.size(); i++){
			Bullet myBullet = hero.vb.get(i);
			//画出炮弹
			if(myBullet!=null && myBullet.isLive==true){//如果无isLive条件,子弹虽然不会移动,但是会一直存在
				g.drawOval(myBullet.x, myBullet.y, 2, 2);
			}
			if(myBullet.isLive==false){
				hero.vb.remove(myBullet);
			}
		}
			//画出爆炸效果
		for(int i=0; i<vBombs.size(); i++){
			//取出爆炸对象
			Bomb bomb = vBombs.get(i);
			if(bomb.life>8){
				g.drawImage(image1, bomb.x, bomb.y, 30, 30, this);
			}else if(bomb.life>4){
				g.drawImage(image2, bomb.x, bomb.y, 30, 30, this);
			}else {
				g.drawImage(image3, bomb.x, bomb.y, 30, 30, this);
			}
			bomb.lifeDown();//生命周期减少
			if(bomb.isLive==false){
				vBombs.remove(bomb);
			}
		}
		
		//画出敌军坦克
		for(int i=0; i<vts.size(); i++){
			Enemy e = vts.get(i);
			if(e.isLive){	//画出存活的敌军坦克(被炮弹击中后敌方坦克的isLive状态变为false,即死亡)
				this.drawTank(e.getX(), e.getY(), g, e.getDirect(), vts.get(i).getColor());
					//画出敌方炮弹
				for(int j=0; j<e.eb.size(); j++){
					Bullet b = e.eb.get(j);
					if(b.isLive){
						g.drawOval(b.x, b.y, 2, 2);
					}else{
						e.eb.remove(j);
					}
				}
			}
		}
			/*附加:上面情况会出现敌方坦克已死亡,已发射的炮弹其实还存在,但是不会执行到绘出那一步
			 * 这里再重新添加个判断条件,当敌方坦克已死亡,即:!e.isLive时
			 * 不绘出死亡的坦克,但继续副出已发出且处于存活状态的炮弹
			 */
		for(int i=0; i<vts.size(); i++){
			Enemy e = vts.get(i);
			if(!e.isLive){
					//只画出敌方坦克死亡前发射的炮弹
				for(int j=0; j<e.eb.size(); j++){
					Bullet b = e.eb.get(j);
					if(b.isLive){
						g.drawOval(b.x, b.y, 2, 2);
					}else{
						e.eb.remove(j);
					}
				}
			}
		}
		
		
	}
	//击中后显示目标效果
	public void isHit(Bullet b, Tank t){
		switch(t.direct){
			//敌军坦克方向为上、下时状态
		case 0:
		case 1:
			if(b.x>t.x && b.x<t.x+20 && b.y>t.y && b.y<t.y+30){
				b.isLive = false;
				t.isLive = false;
				Bomb bomb = new Bomb(t.x, t.y);	//击中时创建一个爆炸对象
				vBombs.add(bomb);	//加入Vector中
			}
			//敌军坦克方向为左、右时状态
		case 2:
		case 3:
			if(b.x>t.x && b.x<t.x+30 && b.y>t.y && b.y<t.y+20){
				b.isLive = false;
				t.isLive = false;
				Bomb bomb = new Bomb(t.x, t.y);	
				vBombs.add(bomb);
			}
		}
		
	}
	
	//画坦克函数
	public void drawTank(int x, int y, Graphics g, int direct, int color){
			//定义坦克颜色
		switch	(color){
		case 0:
			g.setColor(Color.GREEN);
			break;
		case 1:
			g.setColor(Color.red);
			break;
		}
			判断坦克方向
		switch (direct){
			//向上
		case 0:
			g.fill3DRect(x, 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+10, x+10, y);
			g.fill3DRect(x+15, y, 5, 30, false); 
			break;
			//向下
		case 1:
			g.fill3DRect(x, 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+10, x+10, y+30);
			g.fill3DRect(x+15, y, 5, 30, false);
			break;
			//向左
		case 2:
			g.fill3DRect(x, y+10, 30, 5, false);
			g.fill3DRect(x+5, y+15, 20, 10, false);
			g.fillOval(x+10, y+15, 10, 10);
			g.drawLine(x+15, y+20, x, y+20);
			g.fill3DRect(x, y+25, 30, 5, false);
			break;
			//向右
		case 3:
			g.fill3DRect(x, y+10, 30, 5, false);
			g.fill3DRect(x+5, y+15, 20, 10, false);
			g.fillOval(x+10, y+15, 10, 10);
			g.drawLine(x+15, y+20, x+30, y+20);
			g.fill3DRect(x, y+25, 30, 5, false);
			break;
		}
		
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO 自动生成的方法存根
		
	}

	@Override
	public void keyPressed(KeyEvent e) {
		
		if(e.getKeyCode() == KeyEvent.VK_UP){
			this.hero.setDirect(0);
			this.hero.moveUp();
		}else if((e.getKeyCode() == KeyEvent.VK_DOWN)){
			this.hero.setDirect(1);
			this.hero.moveDown();
		}else if((e.getKeyCode() == KeyEvent.VK_LEFT)){
			this.hero.setDirect(2);
			this.hero.moveLeft();
		}else if((e.getKeyCode() == KeyEvent.VK_RIGHT)){
			this.hero.setDirect(3);
			this.hero.moveRight();
		}
			//判断玩家是否按下发射炮弹键(空格键)
		if(e.getKeyCode() == KeyEvent.VK_SPACE){
			
			if(hero.vb.size()<5){	//限定每次能发射的最大炮弹数
				this.hero.shot();
			}
		}
		this.repaint();/*run()方法中已经定时重绘,这里可以不必重绘,
						但是由于延时重绘会导致英雄坦克的运动显得不流畅*/
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO 自动生成的方法存根
		
	}

	@Override//每隔100毫秒重绘一下炮弹
	public void run() {
		// TODO 自动生成的方法存根
		while(true){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			//判断是否击中敌方坦克
			this.hitEnemy();
			
			//判断敌方坦克是否击中英雄坦克
			this.hitHero();
			this.repaint();
		}	
	}
	
}
2、
package com.tank;

import java.util.Vector;

class Tank{
	//坦克横、纵坐标 
	int x = 0;	
	int y = 0;	
	//坦克颜色
	int color = 0;
	//是否存活
	boolean isLive = true;
	public int getColor() {
		return color;
	}

	public void setColor(int color) {
		this.color = color;
	}

	//坦克方向   0 = 上, 1 = 下,2 = 左, 3 = 右
	int direct = 0;

	public int getDirect() {
		return direct;
	}

	public void setDirect(int direct) {
		this.direct = direct;
	}

	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 Tank(int x, int y){
		this.x = x; 
		this.y = y;
	}
}

	//英雄坦克——我的
class Hero extends Tank{
	//创建英雄坦克的炮弹
	Bullet b = null;
	//创建向量
	Vector <Bullet> vb = new Vector <Bullet>();
	//移动速度
	int speed = 3;
	//坦克的初始位置
	public Hero (int x, int y){
		super(x, y);	
	}
	//我的坦克 移动方法
	public void moveUp(){
		y-=speed;
	}
	public void moveDown(){
		y+=speed;
	}
	public void moveLeft(){
		x-=speed;
	}
	public void moveRight(){
		x+=speed;
	}
	
		//坦克开炮
	public void shot(){
		switch(this.direct){
		case 0:
			b = new Bullet(x+10, y, this.direct);//向上
			vb.add(b);//将炮弹加入向量
			break;
		case 1:
			b = new Bullet(x+10, y+30, this.direct);//向下
			vb.add(b);
			break;
		case 2:
			b = new Bullet(x, y+20, this.direct);//向左
			vb.add(b);
			break;
		case 3:
			b = new Bullet(x+30, y+20, this.direct);//向右
			vb.add(b);
			break;
		}
			//启动炮弹线程 
		Thread t = new Thread(b);
		t.start();
	}
	
}

//敌方坦克     实现线程接口
class Enemy extends Tank implements Runnable{
	
	//移动速度
	int speed = 1;
	
	//定义一个向量存放敌方坦克的炮弹
	Vector <Bullet> eb = new Vector <Bullet>();

	public Enemy(int x, int y) {
		super(x, y);
	}

	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			
			switch(this.direct){
			case 0:		//上
				for(int i=0; i<25; i++){
					if(y>0){
						y-=speed;
					}
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
				}
				break;
			case 1:		//下
				for(int i=0; i<30; i++){
					if(y<300-30){ //必须要减去一个y轴的长度,不然坦克y点在边界时,其部分出界了
						y+=speed;
					}
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
				}
				break;
			case 2:		//左
				for(int i=0; i<35; i++){
					if(x>0){
						x-=speed;
					}
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
				}
				break;
			case 3:		//右
				for(int i=0; i<40; i++){
					if(x<400-30){
						x+=speed;
					}
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
				}
				break;
			}
			
			if(isLive){
				if(eb.size()<5){
					Bullet b = null;
					switch(direct){
					case 0:
						b = new Bullet(x+9, y, this.direct);//向上
						eb.add(b);//将炮弹加入向量
						break;
					case 1:
						b = new Bullet(x+9, y+30, this.direct);//向下
						eb.add(b);
						break;
					case 2:
						b = new Bullet(x, y+19, this.direct);//向左
						eb.add(b);
						break;
					case 3:
						b = new Bullet(x+30, y+19, this.direct);//向右
						eb.add(b);
						break;
					}
					Thread t = new Thread(b);
					t.start();
				}
			}
			
			
			
				//坦克产生一个随机方向
			this.direct = (int)(Math.random()*4);
				//坦克死亡后退出线程
			if(this.isLive == false){
				break;
			}
		}
		
	}
	
}

//炮弹类
class Bullet implements Runnable{
	int x, y;
	int direct;	//坦克方向决定炮弹方向
	int speed = 6;
	boolean isLive = true;//用于判定炮弹是否死亡
	
	public Bullet(int x, int y, int direct){
		this.x = x;
		this.y = y;
		this.direct = direct;
	}
	
	@Override//炮弹运行
	public void run() {
		while(isLive){
			try {
				Thread.sleep(130);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			switch(direct){
			case 0:
				y-=speed;
				break;
			case 1:
				y+=speed;
				break;
			case 2:
				x-=speed;
				break;
			case 3:
				x+=speed;
			}
			if(x<0 || x>400|| y<0 || y>300){
				isLive = false;
			}
		}
		
	}
	
}

演示效果:







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值