改写《魔塔》前篇07:碰撞检测(附:前期阶段项目下载)

       前面已经初步实现了勇士在地图内的移动。这一篇我们就 开始加入碰撞检测,让勇士在碰到墙壁之后无法行走,到地图边缘时也不会走出去。

      我们先来实现墙壁的碰撞逻辑。大家可以先思考一下,如何判断勇士撞到墙了?相信你已经有了一些思路了:可以在menuCallBackMove方法中判断目标地点的图块类型,如果是墙壁的话,就不让勇士移动。没错,这就是我们将要采用的方法。下面我们看一下如何用代码实现这个逻辑。

(1)先熟悉一下CCTMXLayer中的一个重要方法tileGIDAt(CCPoint tileCoordinate)。此方法可以根据传入的Tilemap坐标,返回坐标位置的图块编号,如果该位置没有图块,则返回0.有了这个方法,就可以方便地判断目标位置是否有墙壁了。现在只需要将勇士的cocos2d-x坐标转换为Tilemap坐标即可。转换方法如下,在计算y坐标时,用最大的y值减去当前y值即可。首先我们在HelloWorldScene.h文件里声明方法tileCoordForPosition,即把“CCPoint tileCoordForPosition(CCPoint position);”添加到声明方法里即可。然后在.cpp文件的最后添加下面代码。

CCPoint HelloWorld::tileCoordForPosition(CCPoint position)
{
	int x=position.x/map->getTileSize().width;
	int y=(((map->getMapSize().height-1)*map->getTileSize().height)-position.y)/map->getTileSize().height;
	return ccp(x,y);
}

(2)在HelloWorldScene.h头文件里定义几个碰撞类型:

typedef enum

{

   kNone=1,//可以通行

   kWall,//墙

   kEnemy,//敌人

}CollisionType; //碰撞类型

(3)添加一个方法checkCollision(用于碰撞检测)。注意:在获取图块ID之前,先判断目标位置是否在地图范围内,如果超出了地图范围,则返回kWall类型,阻止勇士移动。首先在HelloWorldScene.h文件添加方法的声明,即“CollisionType checkCollision(CCPoint heroPosition);”。然后在.cpp文件里实现此方法,代码如下:

CollisionType HelloWorld::checkCollision(CCPoint heroPosition)
{
	//cocos2d-x坐标转换为Tilemap坐标
	CCPoint tileCoord=tileCoordForPosition(heroPosition);
	//如果勇士坐标超过地图边界,返回kWall类型,阻止其移动
	if(heroPosition.x<0||tileCoord.x>map->getMapSize().width-1||tileCoord.y
		<0||tileCoord.y>map->getMapSize().height-1)
		return kWall;
	//获取当前坐标位置的图块ID
	int tileGid=map->layerNamed("wall")->tileGIDAt(tileCoord);
	//如果图块ID不为0,表示有墙
	if(tileCoord){
	    return kWall;
	}
	//可以通行
	return kNone;
}

(4)在menuCallBackMove这个回调方法中调用checkCollision,检测碰撞。如果碰撞类型为墙壁,只需要设置勇士的朝向;如果无障碍,则开始行走。修改menuCallBackMove()函数如下:

void HelloWorld::menuCallBackMove(CCObject* pSender)
{
	//正在移动中,不接受新的指令
	if (isHeroWalking)
		return;

    CCNode *node = (CCNode *) pSender;
	//按钮的tag就是需要行走的方向
	int targetDirection = node->getTag();

	//移动的距离
	CCPoint moveByPosition;
	switch(targetDirection)
	{
	case kDown:
		moveByPosition=ccp(0,-32);
		break;
	case kLeft:
		moveByPosition=ccp(-32,0);
		break;
	case kRight:
		moveByPosition=ccp(32,0);
		break;
	case kUp:
		moveByPosition=ccp(0,32);
		break;
	}

	//计算目标坐标,用当前勇士坐标加上移动距离
	CCPoint targetPosition = ccpAdd(heroSprite->getPosition(), moveByPosition);
	//调用checkCollision检测碰撞类型,如果是墙壁,则只需要设置勇士的朝向
	if (checkCollision(targetPosition) == kWall)
	{
		setFaceDirection((HeroDirection)targetDirection);
		return;
	}

	//利用CCSpawn将行走动画和移动同时执行
	CCAction *action = CCSequence::create(
		CCSpawn::create(
		CCAnimate::create(walkAnimation[targetDirection]),
		CCMoveBy::create(0.28f,moveByPosition),
		NULL),
        //把方向信息传递给onWalkDone方法
		CCCallFuncND::create(this, callfuncND_selector(HelloWorld::onWalkDone), (void*)targetDirection),
			NULL);
	//主角执行动作
	heroSprite->runAction(action);
	//人物开始移动,设置标识为true
	isHeroWalking = true;
}

现在编译运行程序,控制勇士在地图上行走,当遇到墙的时候,勇士不会再穿墙而过了,而是乖乖地站在原地不动。

                

最后附上前期阶段项目源码的下载地址:点此下载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值