danielzzu 阅读(414) 评论(0)

尊重开发者的劳动成果,转载的时候请务必注明出处http://blog.csdn.net/haomengzhu/article/details/17327287


<捕鱼达人>回顾

【cocos2d-x IOS游戏开发-捕鱼达人1】内容介绍

上节回顾

【cocos2d-x IOS游戏开发-城市跑酷15】完善积分板【CCLabelBMFont】


到现在为止,如果不做碰撞检测,就会看到主角一直在一条线上运动,甚至还会被房子遮挡;

也不会撞到忽然高起来的房子,也不会从房子上掉下来;

所以就需要在update函数里增加碰撞检测,以增强游戏的可玩性!!!


首先来了解一下CCNODE的几个常用到的几个函数

 CCNode类的setPosition,getPosition函数:如果是一个Node的Child则获取的坐标就是该Node的本地坐标;

另一个关键问题就是在cocos2d-x里就是各种对象的大小问题
因为在cocos2d-x里CCNode对象有缩放的方法setScaleX和setScaleY
所以在获取对象大小的时候必须根据情况明确指定获取对象原始大小,还是缩放后的大小。
当然cocos2d-x里提供了对应函数来完成这些操作:
getContentSize函数来获得节点原始的大小。只是逻辑尺寸,不是像素
boundingBox函数来获得经过缩放和旋转之后的外框盒大小。
getContentSizeInPixels获得的是像素点大小

再来看下:像素点和逻辑点关系
逻辑点大小 = 像素大小/contentScaleFactor.
getVisibleSize:默示获得视口(可视区域)的大小,
若是DesignResolutionSize跟屏幕尺寸一样大,则getVisibleSize便是getWinSize。
getVisibleOrigin:默示可视区域的出发点坐标,
这在处理惩罚相对地位的时辰很是有效,确保节点在不合辨别率下的地位一致。

最后看下坐标转换:
GL坐标系,cocos2d-x默认坐标系:
CCPoint CCDirector::convertToGL(const CCPoint& uiPoint)
{
     CCSize s = m_obWinSizeInPoints;
     float newY = s.height - uiPoint.y;
}

屏幕坐标系:   默认原点在左上角
CCPoint CCDirector::convertToUI(const CCPoint& glPoint)
{
     CCSize winSize = m_obWinSizeInPoints;
     float oppositeY = winSize.height - glPoint.y;
     return ccp(glPoint.x,oppositeY);
}

两种坐标的X方向没有变,只变了Y方向,cocos2d-x里默认的GL坐标系,即左下角为原点ccp(0.0f,0.0f)


到这里,我们就很清楚了,碰撞检测可以这样实现:

碰撞检测:检查XY轴,即检查底部碰撞和侧边碰撞,

从房子上掉下来:利用boundingBox,获取当前主角的位置,已经小于了主角是身体的时候就认为是掉房子下面了;

看具体的代码:

碰撞检测实现代码:

void Terrain::checkCollision (Player * player) {

	//检查主角状态,死亡则跳出
	if (player->getState() == kPlayerDying) 
		return;

	//街区总块数
	int count = _blocks->count();
	Block * block;
	//是否在空中
	bool inAir = true;
	int i;

	for (i = 0; i < count; i++) {

		block = (Block *) _blocks->objectAtIndex(i);
		if (block->getType() == kBlockGap) 
			continue;
		
		//if within x, check y (bottom collision)
		//当主角和房子在X轴上时
		if (player->right() >= this->getPositionX() + block->left()
			&& player->left() <= this->getPositionX() + block->right()) {
            
			if (player->bottom() >= block->top() && player->next_bottom() <= block->top()
				&& player->top() > block->top()) {
                player->setNextPosition(ccp(player->getNextPosition().x, block->top() + player->getHeight()));
				player->setVector ( ccp(player->getVector().x, 0) );
				// Sets the rotation (angle) of the node in degrees
                player->setRotation(0.0);
                inAir = false;
                break;
			}
		}
	}

	for (i = 0; i < count; i++) {
		block = (Block *) _blocks->objectAtIndex(i);
		if (block->getType() == kBlockGap) 
			continue;

		//now if within y, check x (side collision)
		//右侧房子突然高起
		if ((player->bottom() < block->top() && player->top() > block->bottom())
			|| (player->next_bottom() < block->top() && player->next_top() > block->bottom())) {

				if (player->right() >= this->getPositionX() + block->getPositionX() 
					&& player->left() < this->getPositionX() + block->getPositionX()) {

						player->setPositionX( this->getPositionX() + block->getPositionX() - player->getWidth() * 0.5f );
						player->setNextPosition(ccp(this->getPositionX() + block->getPositionX() - player->getWidth() * 0.5f, player->getNextPosition().y));
						player->setVector ( ccp(player->getVector().x * -0.5f, player->getVector().y) );
						//主角装墙上了
						if (player->bottom() + player->getHeight() * 0.2f < block->top()) {
							player->setState(kPlayerDying);
							return;
						}

						break;
				}
		}
	}

	if (inAir) 
	{
		//设置下降状态
		player->setState(kPlayerFalling);
	}
	else 
	{
		//设置一直移植状态
		player->setState(kPlayerMoving);
		player->setFloating (false);
	}
}

	//主角未死亡则检查碰撞冲突
	if (_player->getState() != kPlayerDying) 
		_terrain->checkCollision(_player);
主角掉下去了:
	//获取主角位置
	if (_player->getPositionY() < -_player->getHeight() ||
		_player->getPositionX() < -_player->getWidth() * 0.5f) {
        if (_state == kGamePlay) {
            
            _running = false;

            //create GAME OVER state           
            _state = kGameOver;}}