cocos2d-x游戏开发系列教程-超级玛丽09-怪物激活与移动
在游戏中,很多怪物本身是会移动的,这里主要有蘑菇怪,乌龟等。
说起怪物的移动,首先在游戏里先要考虑怪物的抽象和设计。
在CMMonster.h中,有个类CMMonsterBasic,这个类抽象了所有的怪物,具体的怪物都是它的派生类,比如CMMonsterMushrooms蘑菇怪。
CMMonsterBasic继承自CCNode和CMSender,所以怪物都是渲染对象,并且有消息发送功能。
怪物基本类的接口:
virtual bool init(CCPoint ptMonsterPos,CMMario *pMario,CMGameMap *pGameMap,CMReceiver *pReceiver); 初始化
virtual bool OnCollisionMario() = 0; 与马里奥相撞处理
virtual void Dead(enMonsterDeadType DeadType); 怪物死亡
virtual bool OnCallPerFrame(float fT); 帧刷新定时调用
void MonsterTurn(); 怪物转向,比如蘑菇怪遇到阻挡它的墙时,它会转向
怪物类的基本数据
CMMario *m_pMario; 马里奥对象
CMGameMap *m_pGameMap; 地图对象
enMoveDirection m_MoveDirection; 移动方向
bool m_bIsActivation; 是否激活
float m_fDropSpeedPlus; 掉落加速度
bool m_bIsTouched; 是否相撞
怪物的创建:
当游戏开始时,根据tmx地图中的标记,创建怪物对象并放置到响应位置,具体代码在CMGameMap的init函数中
创建完怪物之后,将其加入到数组中,这些怪物刚刚创建时候,都是不激活的,也就是不会动的
怪物的激活和移动:
触发怪物的激活的原理在于判断怪物是不是已经进入视图,如果没有进入视图,那么怪物不需要动。但是判断是否进入视图还是很麻烦的,所以在马里奥程序里,是用马里奥和怪物的距离,来触发怪物的激活的。
怪物的激活和移动都是在virtual bool OnCallPerFrame(float fT); 函数中,这个函数是CMGameMap的帧更新函数调用过来的,也就是说每次帧更新,每个怪物都会响应这个函数。在这个函数里,负责激活和移动,以及判断怪物和马里奥的碰撞。
下面我们以蘑菇怪的帧更新函数来学习怪物帧更新处理。
bool CMMonsterMushrooms::OnCallPerFrame( float fT )
{
do
{
//是否激活
if (m_bIsActivation==true)
{
//移动与碰撞
if (m_MoveDirection == enMoveLeft)
{
//用怪物左方的2个瓦片来判断移动碰撞
CCSprite* pTileSpriteLeftTop = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX(),getPositionY()+getContentSize().height));
CCSprite* pTileSpriteLeftMid = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX(),getPositionY()+getContentSize().height/2));
if (pTileSpriteLeftTop!=NULL || pTileSpriteLeftMid!=NULL)
{
m_MoveDirection = enMoveRight;
}
else
{
setPositionX(getPositionX()-1);
}
}
else if(m_MoveDirection == enMoveRight)
{
//用怪物右方的2个瓦片来判断移动碰撞
CCSprite* pTileSpriteRightTop = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+getContentSize().width,getPositionY()+getContentSize().height));
CCSprite* pTileSpriteRightMid = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+getContentSize().width,getPositionY()+getContentSize().height/2));
if (pTileSpriteRightTop!=NULL || pTileSpriteRightMid!=NULL)
{
m_MoveDirection = enMoveLeft;
}
else
{
setPositionX(getPositionX()+1);
}
}
//用怪物下方的三个瓦片来判断掉落碰撞
CCSprite* pTileSpriteBottomMid = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+boundingBox().size.width/2,getPositionY()));
CCSprite* pTileSpriteBottomLeft = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+COLLISION_POS_ADJUSTMENT,getPositionY()));
CCSprite* pTileSpriteBottomRight = m_pGameMap->TileMapLayerPosToTileSprite(ccp(getPositionX()+boundingBox().size.width-COLLISION_POS_ADJUSTMENT,getPositionY()));
if (pTileSpriteBottomLeft!=NULL || pTileSpriteBottomMid!=NULL || pTileSpriteBottomRight!=NULL)
{
//掉落速度归零
m_fDropSpeedPlus = 0;
}
else
{
setPositionY(getPositionY()-m_fDropSpeedPlus);
//掉落加速度
m_fDropSpeedPlus += DROP_SPEED_PLUS;
}
}
return (CMMonsterBasic::OnCallPerFrame(fT)||OnCollisionMario());
} while (false);
CCLog("fun CMMonsterMushrooms::OnCallPerFrame Error!");
return false;
}首先判断是否激活了,如果激活了那么则判断它的移动,它不需要按键驱动,按照时间移动它即可,遇到障碍物则返回。如果蘑菇怪在天上,则自然降落。
最后调用基类的定时刷新函数和马里奥的冲突函数。基类的定时刷新函数做什么呢
bool CMMonsterBasic::OnCallPerFrame(float fT)
{
do
{
//判断当怪物离开地图则发消息删除自己
if (getPositionX()<0 || getPositionY()<0)
{
TCmd_Remove_Monster* pData = new TCmd_Remove_Monster;
pData->pMonster = this;
SendMsg(enMsgMonsterDisappear,pData,sizeof(pData));
return true;//需要删除自己
}
CC_BREAK_IF(m_pMario==NULL);
//判断马里奥与当前怪物的距离,用以激活。
if (abs(m_pMario->getPositionX() - getPositionX())<MONSTER_ACTIVE_DISTANCE)
{
m_bIsActivation = true;
}
return false;//不需要删除自己
} while (false);
CCLog("fun CMMonsterBasic::OnCallPerFrame Error!");
return false;
}基类的函数主要要做的事情是:
1)如果怪物离开地图,则自杀。自杀是通过发送消息给地图类,让地图类杀掉本对象
2)如果怪物与马里奥的距离小于某个值,则激活,激活的意思就是这个怪物开始运动了
浙公网安备 33010602011771号