cocos2d-x+Tiledmap中实现自由跳跃和移动
最近在学习cocos2d-x,遇到一个问题:在tiledMap中,怎么实现类似超级玛丽跳跃和移动那样的算法?
游戏主角假设也是一个瓦片大小,在如下的场景中如何实现游戏主角的自由移动?
1.算法描述
1.
heroPosition_nextFrame = heroPosition_currentFrame + ccp(speedX, 0) + ccp(0, speedY)
2.
determinePoint[4] = CCPoint(heroPosition_nextFrame.x, heroPosition_nextFrame.y)
CCPoint(heroPosition_nextFrame.x + heroSize.width, heroPosition_nextFrame.y)
CCPoint(heroPosition_nextFrame.x + heroSize.width, heroPosition_nextFrame.y + heroSize.height)
CCPoint(heroPosition_nextFrame.x, heroPosition_nextFrame.y + heroSize.height)
CCPoint(heroPosition_nextFrame.x + heroSize.width, heroPosition_nextFrame.y + heroSize.height)
CCPoint(heroPosition_nextFrame.x, heroPosition_nextFrame.y + heroSize.height)
3.
CollisionPosition getPointCollisionPosition( cocos2d::CCPoint heroPosition_core, cocos2d::CCPoint determinedPoint, cocos2d::CCPoint&)
4.
Update m_fMaxDisUp, m_fMaxDisDown, m_fMaxDisLeft, m_fMaxDisRight
5.
Update HeroPosition
第一步,根据英雄当前位置+当前水平/垂直方向移动速度得到下一帧英雄的位置;
第二步,根据英雄的位置+英雄的大小获取英雄四个顶点的位置,作为监测点
第三步,任何时候,英雄都必定处于如下的九宫格之中,根据英雄的位置+监测点的位置获取碰撞类型(LeftUp, Up, RightUp, Right, RightDown, Down, LeftDown, Left, NoCollision)和碰撞块的坐标
第四步,根据碰撞和英雄到相对位置,更新m_fMaxDisUp, m_fMaxDisDown, m_fMaxDisLeft, m_fMaxDisRight,这四个值分别代表英雄上、下、左、右能移动的最大距离
第五步,根据英雄当前位置+水平/垂直方向速度+m_fMaxDisUp, m_fMaxDisDown, m_fMaxDisLeft, m_fMaxDisRight更新英雄位置
2.需要注意的细节
2.1初始化
每次预测下一帧的英雄位置的时候,都会修改m_fMaxDisUp, m_fMaxDisDown, m_fMaxDisLeft, m_fMaxDisRight,所以在第三步执行
getPointCollisionPosition之前需要初始化
m_fMaxDisUp, m_fMaxDisDown, m_fMaxDisLeft, m_fMaxDisRight为地图的大小:
m_pHero->InitializeMoveScope(this->m_pMap->getMapSize());
void GameobjHero::InitializeMoveScope(cocos2d::CCSize mapSize)
{
m_fMaxDisUp = mapSize.height;
m_fMaxDisDown = 0;
m_fMaxDisLeft = 0;
m_fMaxDisRight = mapSize.width;
}
2.2顶点碰撞
以右上角碰撞为例,当前的算法并没有区别如下三种碰撞。很显然,第一种碰撞需要更新的是m_fMaxDisRight,第二种碰撞需要更新的是m_fMaxDisUp,而第三种碰撞着需要更新两者。
//hero is at the right side of the collision tiled
if(IS_FLOAT_POSITIVE(m_pHero->getPositionX() - (collisionTiledPosition.x + 1) * m_pMap->getTiledSize().width)
&& IS_FLOAT_POSITIVE((m_pHero->getPositionY() + m_pHero->getContentSize().height) - collisionTiledPosition.y * m_pMap->getTiledSize().height))
{
m_pHero->setMaxDisLeft(max(m_pHero->getMaxDisLeft(), (collisionTiledPosition.x + 1) * m_pMap->getTiledSize().width));
m_pHero->setLeftCollided(true);
}
//hero is at the down side of the collision tiled
else if(IS_FLOAT_POSITIVE((collisionTiledPosition.x + 1) * m_pMap->getTiledSize().width - m_pHero->getPositionX())
&& IS_FLOAT_POSITIVE(collisionTiledPosition.y * m_pMap->getTiledSize().height - (m_pHero->getPositionY() + m_pHero->getContentSize().height)))
{
m_pHero->setMaxDisUp(min(m_pHero->getMaxDisUp(), (collisionTiledPosition.y - 1) * m_pMap->getTiledSize().height));
m_pHero->setUpCollided(true);
}
else
{
m_pHero->setMaxDisLeft(max(m_pHero->getMaxDisLeft(), (collisionTiledPosition.x + 1) * m_pMap->getTiledSize().width));
m_pHero->setMaxDisUp(min(m_pHero->getMaxDisUp(), (collisionTiledPosition.y - 1) * m_pMap->getTiledSize().height));
m_pHero->setLeftCollided(true);
m_pHero->setUpCollided(true);
}
但是右下角和左下角处理第三种碰撞的方式和上述不一样,右下角和左下角不需要设置m_fMaxDisRight和m_fMaxDisLeft,因为在移动的过程中,需要每一帧都将垂直方向的速度设置为一个负数,实现没有瓦片时的下坠效果,所以在英雄每移动一个完整的瓦片,都会发生右下角或者左下角的第三种碰撞,此时如果设置了m_fMaxDisRight或m_fMaxDisLeft,英雄将无法