游戏地图是游戏过程重要的环节,这里我们使用地图编辑器编辑我们的地图,其中CCTMXTiledMap是我们创建地图时使用的类对象,接下来是地图编辑器的使用,免费下载地址:http://www.mapeditor.org/
地图编辑器
打开后弹出窗口,只设置地图高度和宽度(即每一行地图的块数),块的大小(根据自己所选地图),其他为默认。
接着选择“地图--->新图块”,弹出窗口,选择编辑地图块,点击“浏览”选择。
点击确定后,即可在右下角看到地图块,拖动编辑地图。
这里我们可以建立两个图层,如下图所示,一个图层存放背景,另一个存放障碍物,方便我们在做碰撞检测时使用。
完成点击“文件---->另存为”,即可生成.tmx地图文件。
地图文件的使用
当然上面的地图能生成垂直俯视和45度俯视两种类型的地图,可以根据需要编辑生成相应的地图。
这里需要注意的是,我们编辑的地图坐标和屏幕坐标一致,都是左上角为原点,但是和cocos2d坐标系不一致,所以需要做一定的转换。另外,由于新的Cocos2d引擎引入了屏幕适配,所以在设置坐标的时候,需要注意坐标转换,这个在例子中会表明。
地图文件.tmx的简单使用:
// 读取地图文件 auto map = TMXTiledMap::create("TileMap.tmx"); addChild(map);
下面是一个简单的具体事例:
创建一个新的项目“HelloMap”,在HelloMap.h:
<span style="font-size:14px;">#ifndef __HELLOMAP_H__ #define __HELLOMAP_H__ #include "cocos2d.h" #include "Box2D\Box2D.h" #include "SimpleAudioEngine.h" using namespace cocos2d; class HelloMap : public cocos2d::Layer { private: CCTMXTiledMap* _mapTile; CCSprite* _spriteNPC; public: static cocos2d::Scene* createMapScene(); virtual bool init(); void mapMenuCallBack(cocos2d::Ref* pSender); CREATE_FUNC(HelloMap); }; #endif // !__HELLOMAP_H__</span>
HelloMap.cpp:
#include "HelloMap.h" USING_NS_CC; // 定义地图块的实际大小 #define MAPTILESIZE 33*480.00/1024.00 // 按键标示(索引) typedef enum _CONTROLTAG { TAG_UP=100,TAG_DAOW,TAG_LEFT,TAG_RIGHT,TAG_FIRE }CONTROLTAG; Scene* HelloMap::createMapScene() { auto mapScene = Scene::create(); auto mapLayer = HelloMap::create(); mapScene->addChild(mapLayer); return mapScene; } bool HelloMap::init() { if (!Layer::init()) { return false; } CCSize s = Director::getInstance()->getWinSize(); // 创建地图块 _mapTile = CCTMXTiledMap::create("ok.tmx"); _mapTile->setPosition(Vec2(0,0)); this->addChild(_mapTile); // 添加游戏NPC _spriteNPC = CCSprite::create("NPC.png"); _spriteNPC->setPosition(MAPTILESIZE/2,MAPTILESIZE/2); // 将创建的精灵添加到地图中 _mapTile->addChild(_spriteNPC); // 创建菜单按钮,设置回调函数 CCMenuItemFont *upMenuItem = CCMenuItemFont::create("UP",this,menu_selector(HelloMap::mapMenuCallBack)); CCMenuItemFont *downMenuItem = CCMenuItemFont::create("DOWN",menu_selector(HelloMap::mapMenuCallBack)); CCMenuItemFont *leftMenuItem = CCMenuItemFont::create("LEFT",menu_selector(HelloMap::mapMenuCallBack)); CCMenuItemFont *rightMenuItem = CCMenuItemFont::create("RIGHT",menu_selector(HelloMap::mapMenuCallBack)); CCMenuItemFont *fireMenuItem = CCMenuItemFont::create("FIRE",menu_selector(HelloMap::mapMenuCallBack)); // 将菜单项添加到菜单 CCMenu *menu = CCMenu::create(upMenuItem,downMenuItem,leftMenuItem,rightMenuItem,fireMenuItem,NULL); menu->setPosition(0,0); this->addChild(menu); upMenuItem->setPosition(s.width / 2,s.height - 20); downMenuItem->setPosition(s.width / 2,20); leftMenuItem->setPosition(35,s.height / 2); rightMenuItem->setPosition(s.width - 40,s.height / 2); fireMenuItem->setPosition(35,s.height - 30); // 设置按键标示(索引) upMenuItem->setTag(TAG_UP); downMenuItem->setTag(TAG_DAOW); leftMenuItem->setTag(TAG_LEFT); rightMenuItem->setTag(TAG_RIGHT); fireMenuItem->setTag(TAG_FIRE); return true; } // 回调函数 void HelloMap::mapMenuCallBack(Ref* pSender) { // 获取菜单项,并获取索引 CCMenuItem *item = (CCMenuItem*)pSender; int tag = item->getTag(); // 获得精灵的当前位置和下一个节点的位置,这里(33.00 * 480.00 / 1024.00)为每块小地图快的实际像素大小 // 由于Y轴方向上地图坐标与Cocos2d坐标相反,需要转换为地图坐标,及左上角为原点 CCPoint spriteCurPos = ccp((int)(_spriteNPC->getPositionX() / (33.00 * 480.00 / 1024.00)),(int)(_mapTile->getMapSize().height - (_spriteNPC->getPositionY() / (33.00 * 480.00 / 1024.00)))); CCPoint spriteNextPos = spriteCurPos; // 根据图层名字获得图层对象,我们编辑地图时设置了两个图层,layer1存放背景,layer2存放障碍物 CCTMXLayer* ly = _mapTile->layerNamed("layer2"); // 地图块ID int GID = 0; switch (tag) { case TAG_UP: // 获取地图下一个位置节点,如果节点小于0,说明已经出边界,直接返回 spriteNextPos.y -= 1; //log("%f----!!!!!!!!------------",spriteNextPos.y); if (spriteNextPos.y < 0) return; // 获取下一个节点的ID,如果节点存在则返回 GID = ly->tileGIDAt(spriteNextPos); if (GID) return; // 碰撞检测,当NPC没走到地图中间时,即在边界的时候,只移动精灵 // 判断精灵是否到达边界或者到达Y轴的中心,这里我们屏幕的分辨率为480*320 // 这里由于Cocos2d 3.x对屏幕适配的影响,不同电脑显示的地图块的屏幕分辨率与实际分辨率会有所不同, // 因此我们需要根据电脑的显示情况进行适当的坐标调整 if (_spriteNPC->getPositionY() < 160 || (_mapTile->getContentSize().height - _spriteNPC->getPositionY() < 160 + MAPTILESIZE && _mapTile->getContentSize().height - _spriteNPC->getPositionY() > MAPTILESIZE)) { // 精灵向上移动,以cocos2d坐标系作为判断,Y轴需要加上一个地图块的距离 _spriteNPC->setPosition(_spriteNPC->getPositionX(),_spriteNPC->getPositionY() + MAPTILESIZE); } // 当NPC走到地图中间时,移动地图和精灵来代替精灵走动 else if (_mapTile->getContentSize().height - _spriteNPC->getPositionY() > 160 + MAPTILESIZE) { _mapTile->setPosition(_mapTile->getPositionX(),_mapTile->getPositionY() - MAPTILESIZE); _spriteNPC->setPosition(_spriteNPC->getPositionX(),_spriteNPC->getPositionY() + MAPTILESIZE); } break; case TAG_DAOW: // 获取下一个节点,如果节点大于59,说明已经出边界,直接返回 spriteNextPos.y += 1; if (spriteNextPos.y > _mapTile->getMapSize().height - 1) return; // 获取下一个节点的ID,如果节点存在则返回 GID = ly->tileGIDAt(spriteNextPos); if (GID) return; if ((_spriteNPC->getPositionY() > MAPTILESIZE && _spriteNPC->getPositionY() < 160 + MAPTILESIZE) || (_mapTile->getContentSize().height - _spriteNPC->getPositionY() < 160 && _mapTile->getContentSize().height - _spriteNPC->getPositionY() > 0)) { _spriteNPC->setPosition(_spriteNPC->getPositionX(),_spriteNPC->getPositionY() - MAPTILESIZE); } else if (_spriteNPC->getPositionY() < _mapTile->getContentSize().height - 160 && _spriteNPC->getPositionY() > 160 + MAPTILESIZE) { _mapTile->setPosition(_mapTile->getPositionX(),_mapTile->getPositionY() + MAPTILESIZE); _spriteNPC->setPosition(_spriteNPC->getPositionX(),_spriteNPC->getPositionY() - MAPTILESIZE); } break; case TAG_LEFT: // 获取下一个节点,如果节点小于0,说明已经出边界,直接返回 spriteNextPos.x -= 1; if (spriteNextPos.x < 0) return; // 获取下一个节点的ID,如果节点存在则返回 GID = ly->tileGIDAt(spriteNextPos); if (GID) return; if ((_spriteNPC->getPositionX() > MAPTILESIZE && _spriteNPC->getPositionX() < 240 + MAPTILESIZE) || (_mapTile->getContentSize().width - _spriteNPC->getPositionX() < 240 && _mapTile->getContentSize().width - _spriteNPC->getPositionX() > 0)) { _spriteNPC->setPosition(_spriteNPC->getPositionX() - MAPTILESIZE,_spriteNPC->getPositionY()); } else if (_spriteNPC->getPositionX() < _mapTile->getContentSize().width - 240 && _spriteNPC->getPositionX() > 240 + MAPTILESIZE) { _mapTile->setPosition(_mapTile->getPositionX() + MAPTILESIZE,_mapTile->getPositionY() ); _spriteNPC->setPosition(_spriteNPC->getPositionX() - MAPTILESIZE,_spriteNPC->getPositionY()); } break; case TAG_RIGHT: // 获取下一个节点,如果节点大于59,说明已经出边界,直接返回 spriteNextPos.x += 1; if (spriteNextPos.x > _mapTile->getMapSize().width - 1) return; // 获取下一个节点的ID,如果节点存在则返回 GID = ly->tileGIDAt(spriteNextPos); if (GID) return; if (_spriteNPC->getPositionX() < 240 || (_mapTile->getContentSize().width - _spriteNPC->getPositionX() < 240 - MAPTILESIZE && _mapTile->getContentSize().width - _spriteNPC->getPositionX() > MAPTILESIZE)) { _spriteNPC->setPosition(_spriteNPC->getPositionX() + MAPTILESIZE,_spriteNPC->getPositionY()); } else if (_mapTile->getContentSize().width - _spriteNPC->getPositionX() > 240 - MAPTILESIZE) { _mapTile->setPosition(_mapTile->getPositionX() - MAPTILESIZE,_mapTile->getPositionY()); _spriteNPC->setPosition(_spriteNPC->getPositionX() + MAPTILESIZE,_spriteNPC->getPositionY()); } break; case TAG_FIRE: // 替换地图块 ly->setTileGID(46,spriteCurPos); break; } }
由于文件过大,这里只上传类文件,源码下载:http://download.csdn.net/detail/u013707014/9003805