cocos2d-x游戏开发系列教程-超级玛丽07-CMGameMap
背景
在上一篇博客中,我们提到CMGameScene,但是CMGameScene只是个框架,实际担任游戏逻辑的是CMGameMap类,这个博文就来了解下CMGameMap
头文件
class CMGameMap : public cocos2d::CCTMXTiledMap ,public CMReceiver { protected: enum { enTagMario = 998, //通过这个Tag查找Mario }; protected: CCArray *m_pArrayItems; //金币数组 CCArray *m_pArrayMonsters; //怪物数组 CCArray *m_pArrayBlocks; //砖块数组 float m_fMapMove; //地图偏移量 float m_fDropSpeedPlus; //掉落速度 float m_fJumpSpeed; //跳跃速度 bool m_bIsLeftKeyDown; //左键是否按下 bool m_bIsRightKeyDown; //右键是否按下 bool m_bIsJumpKeyDown; //跳跃键是否按下 bool m_bIsHeroDead; //是否死亡 public: static CMGameMap* CreateGameMap(const char* pFileName); // 返回地图指定位置上的图块 CCSprite* TileMapLayerPosToTileSprite(CCPoint TileMapLayerPos); //通过地图块坐标返回地图块类型 enumTileType TileMapPosToTileType(CCPoint HeroPos,float fMapMove); //地图块坐标转换为地图层坐标 CCPoint TileMapPosToTileMapLayerPos(CCPoint TileMapPos); //地图层坐标转换为世界坐标 CCPoint TileMapLayerPosToWorldPos(CCPoint TileMapLayerPos,float m_fMapMove); //地图层坐标转换为地图块坐标 CCPoint TileMapLayerPosToTileMapPos(CCPoint TileMapLayerPos); //返回地图偏移量 float GetMapMove(); virtual void OnCallPerFrame(float dt); protected: virtual bool Init(); void onExit(); //Mario碰撞 void MarioMove(float fT); //顶砖块 void HitBlock(CCPoint TileMapLayerPos); //删除砖块 void DeleteBlock(); //消息处理 protected: virtual void OnMsgReceive( int enMsg,void* pData,int nSize ); void OnSubMsgItemRemove(void *pData ,int nSize); //[道具移除]消息处理 void OnSubMsgMarioLevelUp(); //[马里奥长大]消息处理 void OnSubMsgMonsterDisappear(void *pData,int nSize);//[怪物消失]消息处理 void OnSubMsgStamp(void *pData,int nSize); //[被马里奥踩踏]消息处理 void OnSubMsgBlockBoxHitted(void *pData,int nSize); // [砖块被顶]消息处理 void OnSubMsgMarioBeHurt(); //马里奥被伤害的消息处理 };
从头文件上CMGameMap是从CCTMXTileMap派生,CCTMXTileMap是cocos2dx中的一个瓦片地图类,会有别的博文对这个类进行详细解释,目前我们知道它是CCNode的子类即可。
这个类作为容纳游戏逻辑的类,里面有很多的成员:
m_pArrayItems: 道具,是指在地图上显示的金币等道具
m_pArrayMonsters:怪物
m_pArrayBlocks:砖头
m_fMapMove: 在这个游戏里,地图比窗口大,窗口只能显示地图的一部分,这个值表示窗口原点和地图原点的偏移
m_fDropSpeedPlus: 马里奥掉落速度
m_fJumpSpeed:跳跃速度
m_bIsLeftKeyDown:左键是否按下
m_bisRightKeyDown:右键是否按下
m_bIsJumpKeyDown:跳跃是否按下
以上三个标记,用于连续操作
m_bIsHeroDead: 马里奥是否死亡
CreateGameMap:创建地图
TileMapLayerPosToTileSprite(CCPoint TileMapLayerPos):根据位置获得精灵
TileMapPosToTileType(CCPoint, float fMapMove):根据位置获得精灵类型
TileMapPosToTileMapLayerPos(CCPoint tileMapPos):根据地图坐标,获取砖块坐标
TileMapLayerPosToWorldPos:通过砖块坐标转化成世界坐标,也就是cocos2d的坐标
TileMapLayerPosToTileMapPos:将图层坐标转化成地图块坐标
GetMapMove:获取地图偏移
OnCallPerFrame:被CMGameScene调用的函数,进行逻辑处理,每一帧刷新都会调用该函数
Init:初始化
MarioMove:马里奥移动时,判断游戏逻辑
HitBlock:撞砖块
DeleteBlock:删除砖块
OnMsgReceive:接收到地图中的精灵发过来的消息
OnSubMsg系列函数:对响应的精灵发过来的消息进行处理
CreateGameMap
该函数是本类第一个被调用的函数,详细内容如下:
CMGameMap* CMGameMap::CreateGameMap(const char* pFileName) { do { CMGameMap* pPlayer = new CMGameMap; if (pPlayer && pPlayer->initWithTMXFile(pFileName)) { pPlayer->Init(); pPlayer->autorelease(); return pPlayer; } delete pPlayer; } while (false); CCLog("Fun CMGameMap::CreateGameMap Error!"); return NULL; }这个函数调用了initWithTMXFile函数,这个函数是初始化瓦片地图的函数,在别的博客里详细解释
Init
init函数负责初始化地图中所有的精灵,各就各位,准备游戏
bool CMGameMap::Init() { do { //初始化成员变量 m_fMapMove = 0; m_fDropSpeedPlus = 0; m_fJumpSpeed = 0; m_bIsLeftKeyDown = false; m_bIsRightKeyDown = false; m_bIsJumpKeyDown = false; m_bIsHeroDead = false; //初始化游戏对象数组 m_pArrayItems = CCArray::create(); m_pArrayItems->retain(); m_pArrayMonsters = CCArray::create(); m_pArrayMonsters->retain(); m_pArrayBlocks = CCArray::create(); m_pArrayBlocks->retain(); //初始化Mario CMMario* pMario = CMMario::CreateHero(this); CC_BREAK_IF(pMario==NULL); pMario->setPosition(TileMapPosToTileMapLayerPos(ccp(2,11))); addChild(pMario,enZOrderFront,enTagMario); //pMario->SetStatus(enMarioStatusBig); //隐藏原落坑判断层 CCTMXLayer* pTrapLayer = layerNamed("trap"); CC_BREAK_IF(pTrapLayer==NULL); pTrapLayer->setVisible(false); //初始化显示金币 CCTMXLayer* pCoinLayer = layerNamed("coin"); CC_BREAK_IF(pCoinLayer==NULL); pCoinLayer->setVisible(false); //获得地图的瓦片数量 int nMapHorizontalTileNum = pCoinLayer->boundingBox().size.width/getTileSize().width; int nMapVerticalTileNum = pCoinLayer->boundingBox().size.height/getTileSize().height; //遍历每片瓦片,寻找金币,建立并加入金币集合 for (int i = 0;i<nMapHorizontalTileNum;i++) { for (int j = 0;j<nMapVerticalTileNum;j++) { if (TileMapPosToTileType(ccp(i,j),m_fMapMove)==enTileTypeCoin) { //将瓦片地图坐标转换为瓦片地图层坐标 CCPoint CoinTileMapLayerPos = TileMapPosToTileMapLayerPos(ccp(i,j)); CMItemCoin* pCoin = CMItemCoin::CreateItemIcon(CoinTileMapLayerPos,getTileSize(),pMario,this); if (pCoin==NULL) { CCLog("Coin init Error!"); } pCoin->setPosition(CoinTileMapLayerPos); pCoin->setAnchorPoint(ccp(0,0)); m_pArrayItems->addObject(pCoin); addChild(pCoin); } } } //初始化怪物显示 CCTMXObjectGroup* pObjectLayer = objectGroupNamed("objects"); CC_BREAK_IF(pObjectLayer==NULL); CCArray *ObjectArray = pObjectLayer->getObjects(); CCDictionary *pDic = NULL; for (unsigned int i = 0; i < ObjectArray->count(); i++) { pDic = (CCDictionary *)ObjectArray->objectAtIndex(i); int PosX = ((CCString*)pDic->objectForKey("x"))->intValue(); int PosY = ((CCString*)pDic->objectForKey("y"))->intValue(); PosY -= this->getTileSize().height; CCPoint TileXY = ccp(PosX, PosY); CCString *strName = (CCString*)pDic->objectForKey("name"); CCString *strType = (CCString*)pDic->objectForKey("type"); // 进行怪物的初始化,先根据名字来判断是不是enemy,再细分enemy类型 if (strName->m_sString == "enemy") { if (strType->m_sString == "mushroom") { CMMonsterMushrooms *pMonster = CMMonsterMushrooms::CreateMonsterMushrooms(TileXY,pMario,this,this); if (pMonster==NULL) { CCLog("pMonster==NULL!"); } pMonster->setPosition(ccp(TileXY.x,TileXY.y)); pMonster->setAnchorPoint(ccp(0,0)); m_pArrayMonsters->addObject(pMonster); addChild(pMonster,enZOrderFront); } if (strType->m_sString == "tortoise") { CMMonsterTortoise *pMonster = CMMonsterTortoise::CreateMonsterTortoise(TileXY,pMario,this,this); if (pMonster==NULL) { CCLog("pMonster==NULL!"); } pMonster->setPosition(ccp(TileXY.x,TileXY.y)); pMonster->setAnchorPoint(ccp(0,0)); m_pArrayMonsters->addObject(pMonster); addChild(pMonster,enZOrderFront); } if (strType->m_sString == "flower") { CMMonsterFlower *pMonster = CMMonsterFlower::CreateMonsterFlower(TileXY,pMario,this,this); if (pMonster==NULL) { CCLog("pMonster==NULL!"); } pMonster->setPosition(ccp(TileXY.x,TileXY.y)); pMonster->setAnchorPoint(ccp(0,0)); m_pArrayMonsters->addObject(pMonster); addChild(pMonster,enZOrderFront); } } } //初始化砖块显示 CCTMXLayer* pBlockLayer = layerNamed("block"); CC_BREAK_IF(pBlockLayer==NULL); pBlockLayer->setVisible(false); //获得地图的瓦片数量 // int nMapHorizontalTileNum = pCoinLayer->boundingBox().size.width/getTileSize().width; // int nMapVerticalTileNum = pCoinLayer->boundingBox().size.height/getTileSize().height; //遍历每片瓦片,寻找瓦片,建立并加入瓦片集合 for (int i = 0;i<nMapHorizontalTileNum;i++) { for (int j = 0;j<nMapVerticalTileNum;j++) { if (TileMapPosToTileType(ccp(i,j),m_fMapMove)==enTileTypeBlock) { //解析得到当前砖块的属性 int GID = pBlockLayer->tileGIDAt(ccp(i,j)); CCDictionary *pDic = propertiesForGID(GID); CC_BREAK_IF(pDic==NULL); CCString *strBlockType = (CCString*)pDic->objectForKey("blockType"); if (strBlockType==NULL) { continue; } int nBlockType = strBlockType->intValue(); //将瓦片地图坐标转换为瓦片地图层坐标 CCPoint BlockTileMapLayerPos = TileMapPosToTileMapLayerPos(ccp(i,j)); CMItemBlock* pBlock = CMItemBlock::CreateItemBlock(BlockTileMapLayerPos,getTileSize(),pMario,this,(enumBlockType)nBlockType); if (pBlock==NULL) { CCLog("Block init Error!"); } pBlock->setPosition(BlockTileMapLayerPos); pBlock->setAnchorPoint(ccp(0,0)); m_pArrayBlocks->addObject(pBlock); addChild(pBlock); } } } return true; } while (false); CCLog("Fun CMGameMap::Init Error!"); return false; }
这里很多精灵是从TMX地图中获得的,因此如果需要进一步学习马里奥的话,需要先了解TMX地图了。