Java小游戏坦克大战(三)

1、今天的东西感觉比较难,主要完成了以下几个功能,

10:坦克和墙壁的碰撞

11:子弹和墙体的碰撞

12:敌人坦克的AI,增加敌人坦克的处理控制。

但是一些方法写的比较复杂,不废话了,下面是今天完成的任务。

10、首先我们完成坦克碰到墙壁会停止的功能,大体的思路是这样:

坦克是否碰上了砖墙:
        将坦克的坐标找到地图的某一个单元格,或者是某几个单元格,然后根据相应的坐标和方向,得到三个点的坐标,然后使用这三个点的坐标,依次检测是否产生碰撞了。只要有一个点产生了碰撞,那么就坐标还原,后续的碰撞检测就不需要做了。也就是说这就是一个检测坦克的坐标和设置的砖块为“1”的坐标是否一致,一致则停止,我们这里要设置四个点,我在这里以设置X坐标为例子:

/**
	 * 增加了向右的坐标的-1
	 * 设置坦克的X坐标的方法
	 * @param x
	 */
	public void setX(int x){

		if(x < 0){//坦克到了左边界
			x = 0;
		}

		//右边界
		if(x >= Constant.FRAME_WIDTH-TANK_WIDTH){
			//坦克的x 坐标 x = Constant.FRAME_WIDTH-TANK_WIDTH  最大值。
			x = Constant.FRAME_WIDTH-TANK_WIDTH-1;
		}
		//备份没撞墙之前的x 坐标
		int oldX = this.x;
		this.x = x;

		//根据方向,得到三个点的坐标,然后使用这三个点的坐标,依次检测是否产生碰撞了。
		//只要有一个点产生了碰撞,那么就坐标还原,后续的碰撞检测就不需要做了
		int collideX,collideY;
		boolean isCollide;
		switch(dir){
		case DIR_UP:
			//第一个点
			collideX = this.x;
			collideY = this.y;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				this.x = oldX;
				return;
			}
			//第二个点
			collideX = this.x+TANK_WIDTH/2;
			collideY = this.y;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				this.x = oldX;
				return;
			}
			//第三个点
			collideX = this.x+TANK_WIDTH;
			collideY = this.y;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				this.x = oldX;
				return;
			}
			break;
		case DIR_DOWN:
			//第一个点
			collideX = this.x;
			collideY = this.y+TANK_WIDTH;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				this.x = oldX;
				return;
			}
			//第二个点
			collideX = this.x+TANK_WIDTH/2;
			collideY = this.y+TANK_WIDTH;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				this.x = oldX;
				return;
			}
			//第三个点
			collideX = this.x+TANK_WIDTH;
			collideY = this.y+TANK_WIDTH;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				this.x = oldX;
				return;
			}
			break;
		case DIR_LEFT:
			//第一个点
			collideX = this.x;
			collideY = this.y;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				//不让坦克的坐标还原了,而是设置为碰撞块的边缘的坐标
				//是否能知道碰撞的块的行号和列号??
				//地图的列单元
				int mapColTile = collideX/Map.TILE_WIDTH;
				int mapColTileX = (mapColTile+1)*Map.TILE_WIDTH;

				this.x = mapColTileX;
				return;
			}
			//第二个点
			collideX = this.x;
			collideY = this.y+TANK_WIDTH/2;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				int mapColTile = collideX/Map.TILE_WIDTH;
				int mapColTileX = (mapColTile+1)*Map.TILE_WIDTH;

				this.x = mapColTileX;
				return;
			}
			//第三个点
			collideX = this.x;
			collideY = this.y+TANK_WIDTH;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				int mapColTile = collideX/Map.TILE_WIDTH;
				int mapColTileX = (mapColTile+1)*Map.TILE_WIDTH;

				this.x = mapColTileX;
				return;
			}
			break;
		case DIR_RIGHT:
			//第一个点
			collideX = this.x+TANK_WIDTH;
			collideY = this.y;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				int mapColTile = collideX/Map.TILE_WIDTH;
				int mapColTileX = mapColTile*Map.TILE_WIDTH;

				this.x = mapColTileX-Tank.TANK_WIDTH-1;
				return;
			}
			//第二个点
			collideX = this.x+TANK_WIDTH;
			collideY = this.y+TANK_WIDTH/2;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){

				int mapColTile = collideX/Map.TILE_WIDTH;
				int mapColTileX = mapColTile*Map.TILE_WIDTH;

				this.x = mapColTileX-Tank.TANK_WIDTH-1;
				return;
			}
			//第三个点
			collideX = this.x+TANK_WIDTH;
			collideY = this.y+TANK_WIDTH;
			isCollide = collideWall(collideX, collideY);
			if(isCollide){
				int mapColTile = collideX/Map.TILE_WIDTH;
				int mapColTileX = mapColTile*Map.TILE_WIDTH;

				this.x = mapColTileX-Tank.TANK_WIDTH-1;
				return;
			}
			break;
		}
	}

因为涉及到后面的功能,所以部分代码是后面功能的,所以后面设置X,Y,就不做重复地粘贴了!

11、接着,我们要完成子弹和墙壁的碰撞,以及碰撞时的特效。其实子弹的碰撞与坦克和墙体的碰撞是一样的方法,唯一的区别是当子弹接触墙体时,砖块要消失,那么怎么使得墙壁小时呢?

if (visible) {
			//子弹和墙壁碰撞
			//先求子弹的坐标对应的单元格的行和列
			int mapRowTile = (y-Constant.TITLE_BAR_HEIGHT)/Map.TILE_WIDTH;
			//地图的列单元
			int mapColTile = x /Map.TILE_WIDTH;
			
			if (MapData.mapDate0[mapRowTile][mapColTile]== Map.RED_BLOCK_DATA) {
				visible = false;
				MapData.mapDate0[mapRowTile][mapColTile] = 0;
				//将产生一个爆炸效果,放到容器中
				Explode explode = new Explode(x, y);
				GameFrame.explodes.add(explode);
			}
			}
			
		}
		
	
	//如果子弹可见
	
/
	//增加在其他的类访问子弹是否可见的属性
	public boolean isVisible() {
		return visible;
	}
	public void setVisible(boolean visible) {
		this.visible = visible;
	}

}

这就是今天上午完成的一些功能了,下午的话主要是完成地方坦克的生成以及其AI的实现。

12、在游戏中我们需要敌方的坦克来增加游戏的趣味性,生成敌方的坦克的方式与生成自己的坦克一样,都是调用相同的方法,不过就是要设置敌方坦克的生成数量以及样式,还有要让敌方坦克自己移动开炮而已,这部分的代码理解起来不难,大部分也都是运用随机函数,不过这里出现了一个数组越界的错误,其实也容易解决。不过是加1减1的问题而已!

创建敌坦克的方式和建立自己的一样:


	//创建敌人坦克的构造方法
	public Tank() {
		super();
		//随机在左上角,或者右上角
		if(MyUtil.isHappened(0.5)){//左上角
			this.x = 0;
		}else{//右上角
			this.x = Constant.FRAME_WIDTH-1-Tank.TANK_WIDTH;
		}
		this.y = Constant.TITLE_BAR_HEIGHT;
		this.dir = MyUtil.getRandomNumber(DIR_UP, DIR_RIGHT+1);
		isGood = false;
		this.color = MyUtil.getRandomColor();
	}

然后,定义控制部分:

//敌人坦克的控制部分
	private int randomInterval;
	public static final int MIN_INTERVAL = 1000;
	public static final int MAX_INTERVAL = 3000;
	//用于记录本次随机的开始时间
	private long startTime;

接着就是写敌方坦克的AI部分了,这部分写的敌方的坦克是随机方向运动,随机的一直行动下去,并且在行动的过程中也是随机一边移动,一边开炮。具体代码如下:

/**
	 * 敌人的AI逻辑
	 */
	private void enemyAi(){
		//敌人的坦克一直是行走的状态,随机的方向,时间随机[1000~5000].
		//时间到达之后,继续随机   随机的方向,时间随机[1000~5000].
		//随机控制控制部分
		long time = System.currentTimeMillis();
		if(time - startTime >= randomInterval){
			this.dir = MyUtil.getRandomNumber(DIR_UP, DIR_RIGHT+1);
			startTime = time;
			randomInterval = MyUtil.getRandomNumber(MIN_INTERVAL, MAX_INTERVAL);
		}

		switch(dir){
		case DIR_UP:
			setY(y-speed);
			break;
		case DIR_DOWN:
			setY(y+speed);
			break;
		case DIR_LEFT:
			setX(x-speed);
			break;
		case DIR_RIGHT:
			setX(x+speed);
			break;
		}
		
		//随机发射子弹
		if(Math.random() < 0.05){
			GameFrame.enemyBullets.add(fire());
		}

	}
	//坦克发射炮弹功能
	public Bullet fire(){
		int w = TANK_WIDTH >> 1;
		int bulletX = 0;
		int bulletY = 0;
		//根据坦克(根据方向)的坐标来计算炮弹的坐标
		switch(dir){
		case DIR_UP:
			bulletX = x + w;
			bulletY = y - w;
			break;
		case DIR_DOWN:
			bulletX = x + w;
			bulletY = y + 3*w;
			break;
		case DIR_LEFT:
			bulletX = x - w;
			bulletY = y + w;
			break;
		case DIR_RIGHT:
			bulletX = x + 3*w;
			bulletY = y + w;
			break;
		}
		//生成的子弹的方向和攻击力还有颜色都和坦克一致
		return new Bullet(bulletX, bulletY, dir, atk, true, color);
	}
	

好了,今天的主要任务大体上就是这么多了!今天主要解决的问题比较多,学习起来其实是比较枯燥的,但是完成之后的效果其实是比较有成就和比较有趣的!明天继续加油吧!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值