• 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。


    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

  • 相关阅读:
    2017.3.22上午
    2017.3.21下午
    2017.3.21上午
    git上传到阿里云code
    spring+ibatis整合
    Aop资料整理
    java加密算法之AES小记
    单例的八种写法:推荐静态内部类和枚举
    dubbo入门示例
    自定义注解判空简单示例
  • 原文地址:https://www.cnblogs.com/new0801/p/6177283.html
Copyright © 2020-2023  润新知