cocos2d-x游戏开发系列教程-坦克大战游戏之子弹的碰撞检测处理

在上篇我们加上了简单的坦克之间的碰撞检测,这篇我们继续加上子弹之间,

子弹与坦克之间的碰撞检测,对于上一篇碰撞处理不太完美的地方我们继续改进。

1.子弹之间的碰撞

	//玩家子弹和敌方子弹之间的碰撞
	CCObject* pObj;
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		Bullet* enemyBullet = ((Tank*)pObj)->getBullet();
		if (playerBullet->getFlyState() && enemyBullet->getFlyState())
		{
			if (IsRectIntersect(playerBullet->getMovedRect(), enemyBullet->getMovedRect()))
			{
				enemyBullet->stopFire();
				playerBullet->stopFire();
				break;
			}
		}
	}

我们通过玩家子弹playerBullet与敌人子弹之间的碰撞检测,如果碰撞了调用了子弹的stopFire函数。

2.如果子弹相撞了,当然是子弹直接消失,然后设置子弹飞行状态为false,我们来看看stopFire的函数具体实现:

bool Bullet::stopFire()
{
	if (mFlyState == true)
	{
		mFlyState = false;
		setVisible(false);
		unscheduleUpdate();

		return true;
	}

	return false;
}
其中mFlyState表示飞行状态,然后设置了不可见,取消了定时器,不再做子弹运动的计算。

3.我们再添加玩家子弹和敌人坦克的碰撞:

	//玩家子弹和敌方坦克的碰撞
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		if (playerBullet->getFlyState())
		{
			Tank* enemyTank = (Tank*)pObj;
			if (IsRectIntersect(playerBullet->getMovedRect(), enemyTank->getMovedRect()))
			{
				mEnemyTanks->removeObject(pObj);
				enemyTank->remove();
				playerBullet->stopFire();
				break;
			}
		}
	}
可以看到检测碰撞后从敌人坦克数组中移除了坦克对象,然后调用了坦克的remove命令,

来释放此坦克对象占用的内存,然后调用了玩家子弹的stopFire。

扫描二维码关注公众号,回复: 5036913 查看本文章

4.下面看看坦克对象的remove实现:

void Tank::remove()
{
	mTileMapInfo->getTileMap()->removeChild(this);
}

他简单的调用了地图的removeChild函数,将自己从地图中移除了。

5.最后看看敌人子弹和玩家坦克的碰撞处理:

	//敌人子弹和玩家的碰撞
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		Bullet* enemyBullet = ((Tank*)pObj)->getBullet();
		if (enemyBullet->getFlyState())
		{
			if (IsRectIntersect(enemyBullet->getMovedRect(), mTank->getMovedRect()))
			{
				mTank->setVisible(false);
				enemyBullet->stopFire();
				break;
			}
		}
	}
发生碰撞后,简单的将玩家坦克设置为不可见,然后停止敌人子弹开火。

6.碰撞函数基本上全部修改完毕,看看最后碰撞函数整体:

void EnemyAI::collisionTest()
{
	Bullet* playerBullet = mTank->getBullet();

	//坦克之间的碰撞
	CCArray* ccTmpArray = CCArray::create();
	ccTmpArray->addObjectsFromArray(mEnemyTanks);
	ccTmpArray->addObject(mTank);
	CCObject* pObjSrc;
	CCARRAY_FOREACH(ccTmpArray, pObjSrc)
	{
		Tank* tankSrc = (Tank*)pObjSrc;
		CCObject* pObjdst;
		CCARRAY_FOREACH(ccTmpArray, pObjdst)
		{
			Tank* tankDst = (Tank*)pObjdst;
			if (tankSrc != tankDst)
			{
				CCRect rectDst;
				if (ccTmpArray->indexOfObject(pObjSrc) > ccTmpArray->indexOfObject(pObjdst))
				{
					//之前的坦克已经确定了要移动的位置
					rectDst = tankDst->getMovedRect();
				}
				else
				{
					//还没有确定要移动的坦克
					rectDst = tankDst->boundingBox();
				}
				if (IsRectIntersect(tankSrc->getMovedRect(), rectDst))
				{
					//确保在移动之前没有重合
					if (!IsRectIntersect(tankSrc->boundingBox(), rectDst))
					{
						tankSrc->setBlock(true);
					}
				}
			}
		}
	}

	//玩家子弹和敌方子弹之间的碰撞
	CCObject* pObj;
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		Bullet* enemyBullet = ((Tank*)pObj)->getBullet();
		if (playerBullet->getFlyState() && enemyBullet->getFlyState())
		{
			if (IsRectIntersect(playerBullet->getMovedRect(), enemyBullet->getMovedRect()))
			{
				enemyBullet->stopFire();
				playerBullet->stopFire();
				break;
			}
		}
	}

	//玩家子弹和敌方坦克的碰撞
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		if (playerBullet->getFlyState())
		{
			Tank* enemyTank = (Tank*)pObj;
			if (IsRectIntersect(playerBullet->getMovedRect(), enemyTank->getMovedRect()))
			{
				mEnemyTanks->removeObject(pObj);
				enemyTank->remove();
				playerBullet->stopFire();
				break;
			}
		}
	}

	//敌人子弹和玩家的碰撞
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		Bullet* enemyBullet = ((Tank*)pObj)->getBullet();
		if (enemyBullet->getFlyState())
		{
			if (IsRectIntersect(enemyBullet->getMovedRect(), mTank->getMovedRect()))
			{
				mTank->setVisible(false);
				enemyBullet->stopFire();
				break;
			}
		}
	}
}

可以看到上面的坦克和坦克之间的碰撞检测,相比较上一篇中的坦克间的碰撞检测更加精确,

解决了上篇文章中坦克之间可能卡死的状况。

7.对于坦克行为的控制也做了少许修改:

void EnemyAI::tankAction(float delta)
{
	CCObject* pObj;
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		Tank* tank = (Tank*)pObj;

		//坦克按照上次的方向一直往前走
		int Rotation = tank->getRotation();
		tank->command((enumOrder)(Rotation / 90 + 1));

		//坦克每隔一秒开一次火
		tank->setBulletDelta(tank->getBulletDelta() + delta);
		if (tank->getBulletDelta() > 1)
		{
			//开火后,如果子弹在飞行中,归零计时
			if (tank->command(cmdFire))
			{
				tank->setBulletDelta(0.0);
			}
		}
	}
	//检测坦克之间的碰撞
	collisionTest();
	move();
}
上面函数在控制玩坦克行为后,检测了是否发生了碰撞,最后才调用move来移动坦克位置。

看看move函数的实现:

void EnemyAI::move()
{
	mTank->move();
	CCObject* pObj;
	CCARRAY_FOREACH(mEnemyTanks, pObj)
	{
		Tank* tank = (Tank*)pObj;
		//如果坦克阻塞,换个方向
		if (tank->getBlock())
			tank->setRotation((int)(CCRANDOM_0_1() * 3.8) * 90);
		//如果上面的判断完成后,坦克根据自己的阻塞状态移动
		tank->move();
	}
}
move函数在检测了坦克是否阻塞,如果阻塞则随机切换坦克运行方向,

然后调用了坦克自身的move函数移动到相应位置。

最后我们来看看运行效果:

完整代码下载地址:

http://download.csdn.net/detail/yincheng01/6779739

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自www.cnblogs.com/wicnwicnwh/p/10309750.html