如何使用cocos tiledmap2d制作基于tiled地图的游戏

cocos2d-x + TiledMap 详解
瓦片地图类之CCTMXTiledMap
瓦片地图就是游戏的背景。
这篇文章为大家介绍,瓦片地图类CCTMXTiledMap,我们先来学习它的初始化方法,代码如下:
根据一个TMX文件来创建一个背景地图
static CCTMXTiledMap * create (const char *tmxFile);
根据一个TMX文件以及资源路径,来创建一个背景地图
static CCTMXTiledMap * create (const char *tmxString, const char *resourcePath);
CCTMXTiledMap的成员函数:
//得到地图背景的尺寸
virtual const CCSize & getMapSize (void)
//设置地图背景的尺寸
virtual void setMapSize (const CCSize &var)
//得到地图背景中砖块元素的尺寸
virtual const CCSize & getTileSize (void)
//设置地图背景中砖块元素的尺寸
virtual void setTileSize (const CCSize &var)
//获得物体层中所有对象
virtual CCArray * getObjectGroups (void)
//设置物体层的容器
virtual void setObjectGroups (CCArray *var)
//获得地图的属性
virtual CCDictionary * getProperties (void)
//设置地图属性
virtual void setProperties (CCDictionary *var)
//构造函数
CCTMXTiledMap ()
//析构函数
virtual ~CCTMXTiledMap ()
//一个初始化函数
bool initWithTMXFile (const char *tmxFile)
//另一个初始化函数
bool initWithXML (const char *tmxString, const char *resourcePath)
//根据图层的名字,来获得图层
CCTMXLayer * layerNamed (const char *layerName)
//根据物体层的名字,来获得物体层
CCTMXObjectGroup * objectGroupNamed (const char *groupName)
//根据属性的名字,来获得数值
CCString * propertyNamed (const char *propertyName)
//根据GID,获得属性字典
CCDictionary * propertiesForGID (int GID)
Cocos2d-x 瓦片地图图层类CCTMXLayer
这篇文章为大家介绍瓦片地图的图层:-x中的图层分为2种,一个为砖块拼接的图层,另一个是物体层。我们这篇将给大家介绍2种图层的公有方法:
代码如下: [plain]
//返回图层尺寸的大小
virtual const CCSize & getLayerSize (void)
//设置图层尺寸的大小
virtual void setLayerSize (const CCSize &var)
//返回砖块尺寸的大小
virtual const CCSize & getMapTileSize (void)
//设置砖块尺寸的大小
virtual void setMapTileSize (const CCSize &var)
//返回砖块属性信息
virtual CCTMXTilesetInfo * getTileSet (void)
//设置砖块属性信息
virtual void setTileSet (CCTMXTilesetInfo *var)
//返回图层属性字典(包含了所有属性)
virtual CCDictionary * getProperties (void)
//设置图层属性
virtual void setProperties (CCDictionary *var)
//构造函数
CCTMXLayer ()
//析构函数
virtual ~CCTMXLayer ()
//初始化函数,参数为:砖块配置对象,图形配置对象,地图配置对象
bool initWithTilesetInfo (CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo)
//释放图层中砖块的拼接信息
void releaseMap ()
//返回指定位置的砖块对象
CCSprite * tileAt (const CCPoint &tileCoordinate)
//返回指定位置砖块对象的ID
unsigned int tileGIDAt (const CCPoint &tileCoordinate)
//返回指定位置砖块对象的ID
unsigned int tileGIDAt (const CCPoint &tileCoordinate, ccTMXTileFlags *flags)
//设置指定位置砖块对象的ID
void setTileGID (unsigned int gid, const CCPoint &tileCoordinate)
//设置指定位置砖块对象的ID
void setTileGID (unsigned int gid, const CCPoint &tileCoordinate, ccTMXTileFlags flags)
//移除指定位置砖块对象
void removeTileAt (const CCPoint &tileCoordinate)
//返回指定坐标的地图位置
CCPoint positionAt (const CCPoint &tileCoordinate)
//返回指定属性数值
CCString * propertyNamed (const char *propertyName)
//创建图层中的砖块
void setupTiles ()
//得到图层的名字
const char * getLayerName ()
//设置图层的名字
void setLayerName (const char *layerName)
TiledMap实践
本文实践自 Ray Wenderlich 的文章《How To Make a Tile-Based Game with Cocos2D》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.0.4进行学习和移植。这个游戏是关于一个忍者在沙漠中寻找西瓜的故事。
在这部分内容,将会学习到如何用Tile创建一个地图,如何加载地图到游戏,如何让地图跟随玩家滚动,以及如何使用对象层。下一部分内容,将介绍如何在地图中创建可碰撞的区域,如何使用Tile属性,如何创建可拾取的物品和动态修改地图,以及如何确保忍者不会吃撑掉。
步骤如下:
1.新建Cocos2d-win32工程,工程名为TileGame,去除Box2D选项,勾选Simple Audio Engine in Cocos Denshion选项;
2.下载本游戏所需的资源,将资源放置Resources目录下;
3.使用Tiled工具制作地图。首先,下载开源的Tiled Map Editor工具,当前版本为0.9。在Tiled工具,点击菜单栏&文件&新文件,在弹出的对话框中,填入如下内容:
地图方向分为:正常、45度。地图大小填入的是tile单位。块大小是资源每个tile的实际像素大小,在本篇中,使用32x32大小。点击确定。
4.接着,把所需要的tile集合加入到工具中。菜单栏&地图&新图块,填入如下内容:
点击浏览,选择Resources目录下的tmw_desert_spacing.png文件,会自动填充名称内容。块的宽高都为32像素。边距就是当前tile块开始计算实际像素时,应该跳过多少像素,宽高一样。间距就是两个tile块之间的像素距离,宽高一样。看看tmw_desert_spacing.png文件,可以看到每个tile块都1像素的黑色边框,这就是为什么要设置边距和间距为1像素。
点击确定。
5.可以看到tile块出现在图块窗口中。现在可以开始画地图。点击菜单栏&视图&显示网格,可以开启网格参照线。点击工具栏图章刷,然后在图块窗口点选一个tile块,接着在地图中,点击放入你所想要的位置。
用工具栏填充,把地图背景填充成同一个tile块,这里为沙漠背景。可以从图块窗口点选多个tile块,可按Ctrl键多选,这样可以一次性将多个tile块放入地图中。进行制作地图,确保至少有一对建筑在地图上,因为后面需要一些东西来做碰撞。一旦完成了地图的制作,双击图层窗口中的当前层块层 1,重命名为Background。然后点击工具栏保存,命名为TileMap.tmx,保存在Resources目录下。
6.将Tile地图加入到场景中。在HelloWorldScene.h文件中,添加如下代码:
CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXTiledMap*, _tilemap, Tilemap);
CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXLayer*, _background, Background);
在HelloWorldScene.cpp文件中,构造函数添加如下:
HelloWorld::HelloWorld()
_tilemap = NULL;
_background = NULL;
初始化init函数,修改如下:
bool HelloWorld::init()
bool bRet =
CC_BREAK_IF(! CCLayer::init());
this-&setTileMap(CCTMXTiledMap::create(TileMap.tmx));
this-&setBackground(_tileMap-&layerNamed(Background));
this-&addChild(_tileMap, -1);
} while (0);
bool HelloWorld::init()
bool bRet =
CC_BREAK_IF(! CCLayer::init());
this-&setTileMap(CCTMXTiledMap::create(TileMap.tmx));
this-&setBackground(_tileMap-&layerNamed(Background));
this-&addChild(_tileMap, -1);
} while (0);
7.编译运行,可以看到整个地图的左下角,如下图所示:
要让它成为一个游戏,还需要三件事:玩家、玩家初始点、移动视图以便能够看到玩家。
8.Tiled支持两种类型层:tile层和对象层。对象层允许你在地图上可能发生事件的区域绘制矩形。比如:你可能需要一个怪物出生区域,或者一个一进入就会挂掉的区域。在这里,我们给玩家创建一个出生地。菜单栏&图层&添加对象层,命名为Objects,点击工具栏插入对象,在地图上选择一个位置并点击它,这时会出现一个灰色的矩形框,右键选择对象属性,名称填入SpawnPoint,如下图所示:
按确定按钮。保存地图。
9.在HelloWorldScene.h文件中,添加如下声明:
CC_SYNTHESIZE_RETAIN(cocos2d::CCSprite*, _player, Player);
在HelloWorldScene.cpp构造函数中,添加如下:
_player = NULL;
在init初始化函数,添加如下:
CCTMXObjectGroup *objects = _tileMap-&objectGroupNamed(Objects);
CCAssert(objects != NULL, Objects' object group not found);
CCDictionary *spawnPoint = objects-&objectNamed(SpawnPoint);
CCAssert(spawnPoint != NULL, SpawnPoint object not found);
int x = spawnPoint-&valueForKey(x)-&intValue();
int y = spawnPoint-&valueForKey(y)-&intValue();
this-&setPlayer(CCSprite::create(Player.png));
_player-&setPosition(ccp(x, y));
this-&addChild(_player);
this-&setViewpointCenter(_player-&getPosition());
添加一个方法setViewpointCenter,代码如下:
[plain] view plaincopyprint?
void HelloWorld::setViewpointCenter(CCPoint position)
// 求出屏幕的范围包括宽和高
CCSize winSize = CCDirector::sharedDirector()-&getWinSize();
//显示屏幕中心点的坐标大于屏幕宽和高的一半
int x = MAX(position.x, winSize.width / 2);
int y = MAX(position.y, winSize.height / 2);
//求出的是整个瓦片地图的宽
//_tileMap-&getMapSize().width瓦片地图横向有多少个瓦片
//_tileMap-&getTileSize().width每一个瓦片的宽度
int mapWidth =_tileMap-&getMapSize().width *_tileMap-&getTileSize().
//求出的是整个瓦片地图的高
//_tileMap-&getMapSize().height瓦片地图纵向有多少个瓦片
//_tileMap-&getTileSize().height每一个瓦片的高度
int mapHeight =_tileMap-&getMapSize().height *_tileMap-&getTileSize().
x = MIN(x, mapWidth- winSize.width / 2);
y = MIN(y, mapHeight - winSize.height / 2);
CCPoint actualPoint = ccp(x, y);
//屏幕的中心点
CCPoint viewCenterPoint = ccp(winSize.width / 2,winSize.height / 2);
//计算出重置显示屏幕的中心点
//ccpSub 返回的是viewCenterPoint.x - actualPoint.x和viewCenterPoint.y - actualPoint.y
CCPoint viewPoint = ccpSub(viewCenterPoint, actualPoint);
//重置显示屏幕的中心点
this-&setPosition(viewPoint);
用户传任何的坐标过来,但是有一些点不希望显示出来,比如,我们不想屏幕移出地图边界,那里只是一片空白。如图:
摄像机的中心若是小于winSize.width/2或winSize.height/2,部分的视图将会在屏幕之外。同样的,我们需要检查边界条件。到目前为止,我们一直把这个函数看作是设置摄像机中心的位置。但是,这并不是我们实际做的。实际做的是移动整个层。看下图:
想象一下,身处在一个巨大的世界中,我们能看到的区域是从0到winSize.height/width的这部分。我们视野的中心是centerOfView,并且我们知道要让中心在哪儿(actualPosition)。所以要让我们视野的中心向上向右移动到actualPosition,我们只需要让地图相对的向下向左移动即可。这一步是通过actualPosition与centerOfView坐标相减得到的,然后把HelloWorld层的坐标设为这个结果。
10.编译运行,可以看到忍者在屏幕中,如下图所示:
11.接下来,让忍者可以移动。在HelloWorldScene.cpp文件init函数中,添加如下代码:
this-&setTouchEnabled(true);
开启触摸,然后重载registerWithTouchDispatcher函数,代码如下:
void HelloWorld::registerWithTouchDispatcher(void)
CCDirector::sharedDirector()-&getTouchDispatcher()-&addTargetedDelegate(this,0,true);
注册触摸事件,这样单点触摸ccTouchBegan和ccTouchEnded会被调用。重载ccTouchBegan函数,代码如下:
bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
返回true表明接受这个触摸。添加setPlayerPosition方法,来设置玩家坐标,代码如下:
void HelloWorld::setPlayerPosition(CCPoint position)
_player-&setPosition(position);
重载ccTouchEnded方法,代码如下:
[plain] view plaincopyprint?
void HelloWorld::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
//convertToNodeSpace函数就是把OpenGL的坐标转换成CCLayer的坐标。
CCPoint touchPosition = this-&convertTouchToNodeSpace(pTouch);
//获取任务在CCLayer上的坐标
CCPoint playerPos = _player-&getPosition();
//让触摸点的坐标减去人物的坐标,等于人物要移动的方向以及移动一个位置,我们称之为移动坐标点
CCPoint diff = ccpSub(touchPosition, playerPos);
//当移动坐标点的x坐标大于y坐标点时,我们只移动x轴,反之则移动y轴
if (abs(diff.x) & abs(diff.y))
//当移动坐标点的x大于0时 我们向右移动即让人物的坐标x轴加上一个瓦片地图的宽度。
if (diff.x & 0)
//getTileSize().width获取一个瓦片地图的宽度
playerPos.x += _tileMap-&getTileSize().
//当移动坐标点的x小于0时 我们向右移动即让人物的坐标x轴减去一个瓦片地图的宽度。
//getTileSize().width获取一个瓦片地图的宽度
playerPos.x -= _tileMap-&getTileSize().
//当移动坐标点的y大于0时 我们向右移动即让人物的坐标y轴加上一个瓦片地图的高度。
if (diff.y & 0)
//getTileSize().height获取一个瓦片地图的高度
playerPos.y += _tileMap-&getTileSize().
//当移动坐标点的y小于0时 我们向右移动即让人物的坐标x轴减去一个瓦片地图的高度。
//getTileSize().height获取一个瓦片地图的高度
playerPos.y -= _tileMap-&getTileSize().
//求出这个瓦片地图的整体宽度 其中,_tileMap-&getTileSize().width得到的是瓦片地图每一个瓦片的宽度,
//_tileMap-&getMapSize().width得到的是瓦片地图横向由多少个瓦片组成
float mapWidth = _tileMap-&getTileSize().width * _tileMap-&getMapSize().
//求出这个瓦片地图的整体高度 其中,_tileMap-&getTileSize().height得到的是瓦片地图每一个瓦片的高度,
//_tileMap-&getMapSize().height得到的是瓦片地图纵向由多少个瓦片组成
float mapHeight = _tileMap-&getMapSize().height * _tileMap-&getTileSize().
//以下这个判断的意思:只有人物的坐标点在瓦片地图中才对人物的坐标点进行重新设置
//任务的坐标只有在小于瓦片地图的整体宽度和高度以及要大于0点 ,才在地图中
if (playerPos.x & mapWidth && playerPos.y & mapHeight && playerPos.x &= 0 && playerPos.y &= 0)
this-&setPlayerPosition(playerPos);
//将人物的坐标传入地图相对移动的方法,以便计算相对移动的方向。
this-&setViewPointCenter(_player-&getPosition());
计算触摸点与玩家坐标之间的差值,来决定玩家的移动方向。
convertToNodeSpace函数就是把OpenGL的坐标转换成CCLayer的坐标。
12.编译运行,点击屏幕,让忍者动起来,如下图所示:
参考资料:
1.How To Make a Tile-Based Game with Cocos2D /1163/how-to-make-a-tile-based-game-with-cocos2d
2.如何使用Cocos2D制作一款基于tile的游戏 /zh-hans/16771/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8cocos2d%E5%88%B6%E4%BD%9C%E4%B8%80%E6%AC%BE%E5%9F%BA%E4%BA%8Etile%E7%9A%84%E6%B8%B8%E6%88%8F
3.(译)如何使用cocos2d制作基于tile地图的游戏教程:第一部分/zilongshanren/archive//2012852.html
非常感谢以上资料,本例子源代码附加资源下载地址:http://download.csdn.net/detail/akof
iOS版下载地址 : /s/G8HUO
地图编辑工具: /share/link?shareid=&uk=
在第一篇《如何制作一个基于Tile的游戏》基础上,增加碰撞和拾取功能,原文《Collisions and Collectables: How To Make a Tile-Based Game with Cocos2D Part 2》,在这里继续以Cocos2d-x进行实现。有关、资源等在文章下面给出了地址。
步骤如下:
1.使用上一篇的工程;
2.打开Tiled Map Editor工具,菜单栏&图层&添加图层,命名为Meta。这个层,我们将放入一些假的tile来代表特殊tile。菜单栏&地图&新图块,点击浏览,选择Resources目录下的meta_tiles.png文件,边距和间距设置成1像素点,点击确定。可以看到在图块窗口新增了一页,里面有红色和绿色两种tile,如下图所示:
3.确认Meta层被选中,选择工具栏上图章刷,选择红色tile,绘制可碰撞区域,完成之后,大概如下图所示:
需要给这个tile设置属性来标识它,这样才能知道该tile具有碰撞属性。在图块窗口,右键红色tile,选择图块属性,新建一个属性,名称为Collidable,其值为true,如下图所示:
点击确定。保存地图。
4.打开HelloWorldScene.h文件,添加如下声明:
CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXLayer*, _meta, Meta);
在HelloWorldScene.cpp文件构造函数里,添加代码:
_meta = NULL;
在init函数里,添加背景之后,添加如下代码:
this-&setMeta(_tileMap-&layerNamed(Meta));
_meta-&setVisible(false);
这里把Meta层隐藏起来了,因为这只是作为阻挡的,不是真实可见的。添加一个新的方法,代码如下:
CCPoint HelloWorld::tileCoordForPosition(CCPoint position)
//将人物的目的的坐标的x轴坐标转换成瓦片地图中的x轴的坐标
int x = position.x / _tileMap-&getTileSize().
//将人物的目的的坐标的y轴坐标转换成瓦片地图中的y轴的坐标
int y = ((_tileMap-&getMapSize().height * _tileMap-&getTileSize().height) - position.y) / _tileMap-&getTileSize().
return ccp(x, y);
这个方法将坐标转换成tile坐标,tile坐标系如下图所示:
修改setPlayerPosition函数,代码如下:
void HelloWorld::setPlayerPosition(CCPoint position)
CCPoint tileCoord = this-&tileCoordForPosition(position);
int tileGid = _meta-&tileGIDAt(tileCoord);
if (tileGid)
CCDictionary *properties = _tileMap-&propertiesForGID(tileGid);
if (properties)
const CCString *collision = properties-&valueForKey(Collidable);
if (collision && collision-&compare(true) ==0)
_player-&setPosition(position);
在这里,我们将坐标转成tile坐标,获得这个tile坐标上的GID,再根据GID得到的属性字典,查找是否Collidable属性为true,如果是则直接返回。
5.编译运行,可以看到忍者不能穿过红色区域了。如下图所示:
6.动态修改Tiled地图。我们为忍者增加可以吃的东西,比如这里的西瓜。创建一个可拾取的前景层,当忍者从tile拾取东西时,就把这个tile从前景层中移除。菜单栏&图层&添加图层,命名为Foreground。注意,若是之前有在Background层绘制过西瓜的,需要用底图块,比如这里的沙漠块填充覆盖,以免达不到吃西瓜的效果。然后,选中Foreground层,选择西瓜tile块,在地图上进行绘制。如下图所示:
为西瓜标识可拾取。选择Meta层,图块切换到meta_tiles页,选择绿色tile,绘制到地图上西瓜tile区域。需要先把Meta层前置,点击菜单栏&图层&前置图层,确保Meta层在最上层。如下图所示:
在图块窗口,右键绿色tile块,选择图块属性,新建一个属性,名称为Collectable,其值为true。点击确定。保存地图。
7.打开HelloWorldScene.h文件,添加如下声明:
CC_SYNTHESIZE_RETAIN(cocos2d::CCTMXLayer*, _foreground, Foreground);
在HelloWorldScene.cpp文件构造函数里,添加代码:
_foreground = NULL;
在init函数里,添加背景之后,添加如下代码:
this-&setForeground(_tileMap-&layerNamed(Foreground));
在setPlayerPosition函数检测Collidable属性之后,添加检测Collectable属性,代码如下:
const CCString *collectable = properties-&valueForKey(Collectable);
if (collectable && collectable-&compare(true) ==0)
_meta-&removeTileAt(tileCoord);
_foreground-&removeTileAt(tileCoord);
8.编译运行,可以看到忍者把西瓜吃掉了,如下图所示:
9.创建计分器。为忍者记录所吃西瓜的数量。我们创建一个新层HelloWorldHud来显示分数。在HelloWorldScene.h文件中,添加如下代码:
class HelloWorldHud : public cocos2d::CCLayer
virtualbool init();
CREATE_FUNC(HelloWorldHud);
void numCollectedChanged(int numCollected);
cocos2d::CCLabelTTF *
在HelloWorldScene.cpp文件中,进行实现,代码如下:
bool HelloWorldHud::init()
bool bRet =
CC_BREAK_IF(! CCLayer::init());
CCSize winSize = CCDirector::sharedDirector()-&getWinSize();
lable = CCLabelTTF::create(0, Verdana-Bold, 18.0, CCSizeMake(50,20), kCCTextAlignmentRight);
lable-&setColor(ccc3(0, 0, 0));
int margin = 10;
lable-&setPosition(ccp(winSize.width - (lable-&getContentSize().width / 2) - margin,
lable-&getContentSize().height / 2 + margin));
this-&addChild(lable);
} while (0);
void HelloWorldHud::numCollectedChanged(int numCollected)
lable-&setString(CCString::createWithFormat(%d, numCollected)-&getCString());
接下去在HelloWorld类,添加HelloWorldHud层指针,在HelloWorldScene.h文件中HelloWorld类里,添加如下代码:
CC_SYNTHESIZE(int, _numCollected, NumCollected);
CC_SYNTHESIZE_RETAIN(HelloWorldHud*, _hud, Hud);
在HelloWorldScene.cpp文件HelloWorld类构造函数里,添加代码:
_numCollected = 0;
_hud = NULL;
在scene()函数里,添加如下代码:
HelloWorldHud *hud = HelloWorldHud::create();
scene-&addChild(hud);
layer-&setHud(hud);
在setPlayerPosition函数,检测到Collectable属性为true时,添加如下代码:
_numCollected++;
_hud-&numCollectedChanged(_numCollected);
10.编译运行,现在可以看到右下角有一个西瓜计分器,如下图所示:
11.增加音效和音乐。在HelloWorldScene.cpp文件HelloWorld类init函数里,添加如下代码:
CocosDenshion::SimpleAudioEngine::sharedEngine()-&preloadEffect(pickup.wav);
CocosDenshion::SimpleAudioEngine::sharedEngine()-&preloadEffect(hit.wav);
CocosDenshion::SimpleAudioEngine::sharedEngine()-&preloadEffect(move.wav);
CocosDenshion::SimpleAudioEngine::sharedEngine()-&playBackgroundMusic(TileMap.wav);
在setPlayerPosition函数,检测到Collidable属性为true,添加如下代码:
CocosDenshion::SimpleAudioEngine::sharedEngine()-&playEffect(hit.wav);
检测到Collectable属性为true,添加如下代码:
CocosDenshion::SimpleAudioEngine::sharedEngine()-&playEffect(pickup.wav);
在设置玩家坐标前,添加如下代码:
CocosDenshion::SimpleAudioEngine::sharedEngine()-&playEffect(move.wav);
12.编译运行,现在忍者的行动将有配乐,效果图:
参考资料:
1.Collisions and Collectables: How To Make a Tile-Based Game with Cocos2D Part 2/1186/collisions-and-collectables-how-to-make-a-tile-based-game-with-cocos2d-part-2
2.碰撞与拾取:如何使用Cocos2D制作一款基于tile的游戏第2部分/zh-hans/19250/%E7%A2%B0%E6%92%9E%E4%B8%8E%E6%8B%BE%E5%8F%96%EF%BC%9A%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8cocos2d%E5%88%B6%E4%BD%9C%E4%B8%80%E6%AC%BE%E5%9F%BA%E4%BA%8Etile%E7%9A%84%E6%B8%B8%E6%88%8F%E7%AC%AC2
3.(译)碰撞检测和收集物品:如何使用cocos2d制作基于tiled地图的游戏:第二部分/zilongshanren/archive//2033620.html
非常感谢以上资料,本例子源代码附加资源下载地址:http://download.csdn.net/detail/akof
iOS版下载地址(1): /share/link?shareid=&uk=
iOS版下载地址(2):/s/HWUeY
学习的路上,与君共勉。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'您所在的位置: &
基于Cocos2D-X的砖块地图教程
基于Cocos2D-X的砖块地图教程
Jorge Jordán
通过文章你将学习如何添加砖块地图到游戏中,跟着玩家滚动地图,并使用对象图层。也会学到如何使用地图编辑器去创造砖块地图本身。同时还有如何在地图上创造碰撞领域,如何使用砖块属性,如何创造可收集的道具并动态地修改地图,以及如何确保你的忍者不会吃太多东西。
这是Cocos2D-X砖块地图教程系列,你将在此创造一款有关沙漠中的忍者寻找美味的西瓜的简单游戏。
需要注意的是该教程是关于Cocos2D-X,即Cocos2D-iPhone的跨平台C++移植。所以你在此编写的代码将适用于iPhone,Android和更多平台上!
在本系列文章的第一部分中,你将学习如何添加砖块地图到游戏中,跟着玩家滚动地图,并使用对象图层。你将学到如何使用地图编辑器去创造砖块地图本身。
而第二部分是关于如何在地图上创造碰撞领域,如何使用砖块属性,如何创造可收集的道具并动态地修改地图,以及如何确保你的忍者不会吃太多东西。
注:本篇教程类似于Cocos2D-iPhone教程。
让我们开始创造砖块地图吧!
对于这一教程,你需要安装最新的Cocos2D-X版本(游戏邦注:在写本篇教程的时候更新到2.1.4)。如果你还未拥有最新版本的Cocos2D-X,先下载它并在终端运行如下命令去安装模版:
cd&~/Downloads/cocos2d-x-2.1.4&./install-templates-xcode.sh&-f&-u&
然后使用iOS\cocos2d-x\cocos2dx模版在Xcode创造一个新项目。点击Next,将项目命名为TileGame,将项目设置为Universal,点击Next然后点击Create。
你将在这一项目中使用ARC,所以如果这是你第一次听到ARC,我会鼓励你先了解下它。模版并不是默认使用ARC,但幸运的是,我们能够轻松地进行 修改。前往Edit\Refactor\Convert to Objective-C ARC。往下拉并只选择文件main.m,
AppDelegate.cpp, HelloWorldScene.cpp,然后点击Check并完成向导的步骤。
select targets(from raywenderlich)
创建并运行,然后确保一切都还正常运行&-你应该能够看到标准的&你好世界&屏幕。
接下来下载游戏资源的压缩文件。压缩文件包含如下内容:
你将面向玩家对象使用的精灵。
一些伴随着cfxr效用所创造的音效(你将会在教程中用到)。
一些伴随着Garage Band所创造的背景音乐。
你将用到的一些砖块设置&-这将伴随着你将使用的地图编辑器,但我认为我们能够更轻松地将其与其它内容包含在一起。
一些额外的&特别&砖块,将在之后进行详细解释。
当你下载了资源后,打开它并将TileGameResources文件夹拖到项目的Resources群组中。在项目菜单里,右击 Resources群组,并选择Add Files to
&TileGame&&选择Resources/TileGameResources文件夹,核实选中了Copy items into
destination group&s folder (if needed)以及Create groups for any added
folders,然后点击完成。
如果一切顺利的画,所有的文件都将出现在你的项目中。
你的项目应该如下:
tile game(from raywenderlich)
现在我们将开始创造地图!
Cocos2D-X支持基于开放源Tiled Map Editor去创造地图并将其以TMX格式进行保存。
下载Tiled Map Editor。在编写本篇教程的时候,其最新版本是0.9.0。
然后运行Tiled,前往File\New,并如下填写对话内容:
new map(from raywenderlich)
在定向区域中,你可以在Orthogonal或Isometric间做出选择。在此你将选择Orthogonal。
接下来你将设置地图的大小。记住这是在砖块中,而不是像素中。你将创造一个较小的地图,所以在此你应该选择50&50。Tiled将基于像素呈现给 你总体地图的大小,即在New Map对话的最底部。这是在长度和宽度的基础上将地图大小(50个砖块)乘以砖块的大小(32像素)所计算出来的。
最后,你将明确宽度和高度。你在此所选择的是取决于美术人员所设置的砖块。对于本篇教程,你将使用一些伴随着Tiled编辑器的样本砖块,即32&32规格,选择它便点击OK。
接下来你必须添加砖块设置去绘制你的地图。在菜单栏上点击Map,然后关掉New Tileset&,并如下填写对话框内容:
new tileset(from raywenderlich)
为了获得图像,点击Browse并导航至你自己的TileGame/Resources/TileGameResources文件夹,然后选择你之前从资源压缩中下载的tmw_desert_spacing.png文件,并将其添加到项目中。它将自动根据文件名填写名字。
你可以将宽度和高度设置为32&32,因为这也是砖块的大小。对于边缘和间隔:
边缘是关于在Tiled开始寻找真正的砖块像素前应该为当前的砖块略过多少多少像素(包括宽度和高度)。
间隔是关于Tiled在明确了实际砖块像素并转向下一个砖块数据之后应该前进多少像素(包括宽度和高度)。
如果你着眼于tmw_desert_spacing.png,你将发现每个砖块都围绕着一个1像素的黑色边缘,这也解释了边缘和间隔为1的设置。
tile(from raywenderlich)
当你点击OK时,你将看到砖块呈现在Tilesets窗口中。现在你可以开始绘制了。点击工具栏的Stamp Brush图标,然后点击地图上的任何一个位置去放置一个砖块。
tileset(from raywenderlich)
所以继续绘制地图&-尽可能发挥创造性!确保添加至少一些建筑到地图上,因为你在之后将需要一些碰撞内容。
tileset(from raywenderlich)
为了更轻松地绘制内容,你可以着眼于一些快捷方法。以下是最常用到的一些方法:
你可以在Tileset选择器中围绕着一系列砖块拖曳一个盒子,并同时放下多个相邻的砖块。
你可以通过View\Zoom In和View\Zoom Out进行放大和缩小。
z键将在基于Stamp Brush工具编辑地图时进行旋转。
在一些新功能中你可能会注意到Mini-map。这是一个很棒的功能,它让你能够看到一个迷你地图!着眼于我在Mini-map最下方的迷宫中的糟糕尝试。红色盒子代表你在主要编辑窗口中看到的区域。
tileset(from raywenderlich)
当你在阅读下一个区域中的滚动时牢牢记住这一Mini-map视图。
需要注意的是这一教程的资源是出现在地图前的&&所以如果你很懒的话便可以直接利用它。如果你这么做,你应该在Tiled打开地图并明确它是如何设置的。
当你完成地图的绘制时,在Layers视图中双击Tile
Layer,将名字改为Background。然后点击File\Save,并将文件保存到TileGame项目中的TileGame \Resources\TileGameResources,将文件命名为TileMap.tmx,并覆盖现有的文件。
你将在之后使用Tiled做其它事,但是现在让我们将这一地图带进游戏中!
添加Tiled地图到Cocos2D-X场景中
打开HelloWorldScene.h,在#include &cocos2d.h&之后添加如下内容:
using&namespace&cocos2d;&
这能指导编辑器去使用cocos2d命名空间,所以你不需要为所有内容加上cocos2d的前缀。
然后添加以下内容到类定义中,即在花括号之后:
private:&CCTMXTiledMap&*_tileM&CCTMXLayer&*_&
这创造了一个实例变量去追踪砖块地图本身,并创造了另一个实例变量去追踪地图的背景层。你将在之后学到更多有关砖块地图层面的内容。
接下来,用如下内容换掉HelloWorldScene.cpp:
CCTMXObjectGroup&*objectGroup&=&_tileMap-&objectGroupNamed(&Objects&);&&if(objectGroup&==&NULL){&CCLog(&tile&map&has&no&objects&object&layer&);&return&false;&}&&CCDictionary&*spawnPoint&=&objectGroup-&objectNamed(&SpawnPoint&);&&int&x&=&((CCString)*spawnPoint-&valueForKey(&x&)).intValue();&int&y&=&((CCString)*spawnPoint-&valueForKey(&y&)).intValue();&&_player&=&new&CCSprite();&_player-&initWithFile(&Player.png&);&_player-&setPosition(ccp(x,y));&&this-&addChild(_player);&this-&setViewPointCenter(_player-&getPosition());&
最后一行有个预兆&&但不要担心,你很快就能到达那里。
让我们暂停一会并解释对象层面和对象群组。首先注意你是通过在CCTMXTiledMap对象中(而不是layerNamed)通过objectGroupNamed方法检索对象层面。它返回了一个特殊的CCTMXObjectGroup对象。
然后objectGroup调用了objectNamed方法去获得一个CCDictionary,并包含了一些有关对象的有用信息,如x和y轴,宽度和高度。在教程的这一部分,你需要关心的便是x和y轴,将其设置为玩家精灵的位置。
在代码块的最后你设置了视图去明确玩家的位置。所以现在添加如下内容到HelloWorldScene.h中:
&void&setViewPointCenter(CCPoint&position);&
并添加一个新方法到HelloWorldScene.cpp(在文件的最下方最好):
void&HelloWorld::setViewPointCenter(CCPoint&position)&{&&CCSize&winSize&=&CCDirector::sharedDirector()-&getWinSize();&&int&x&=&MAX(position.x,&winSize.width/2);&int&y&=&MAX(position.y,&winSize.height/2);&x&=&MIN(x,&(_tileMap-&getMapSize().width&*&this-&_tileMap-&getTileSize().width)&&&winSize.width&/&2);&y&=&MIN(y,&(_tileMap-&getMapSize().height&*&_tileMap-&getTileSize().height)&&&winSize.height/2);&CCPoint&actualPosition&=&ccp(x,&y);&&CCPoint&centerOfView&=&ccp(winSize.width/2,&winSize.height/2);&CCPoint&viewPoint&=&ccpSub(centerOfView,&actualPosition);&this-&setPosition(viewPoint);&}&
这是关于砖块的解释。想象这一函数设置了摄像机的中心位置。它让用户能够进入地图中x,y轴的任何位置&-但是你有可能不想呈现出某些点,如你可能不想要屏幕超过地图的边缘(那么它便只会呈现出黑边!)。
diagram(from raywenderlich)
如果摄像机的中心小于winSize.width/2或winSize.height/2,那么部分视角是否会脱离屏幕?同样的,检查最上方的界限也很重要,这也是setViewPointCenter所做的。
到目前为止这一函数被当成设置了摄像机所面对的中心位置。然而,这并不是它真正做的。这是在Cocos2D-X中操控CCNode的摄像机的一种方法,但使用它会比你将使用的解决方法(移动整个层面)更复杂。
着眼于这一图解:
diagram(from
raywenderlich)想象一个大世界,你将着眼于坐标轴,即从0到winSize.height/width。你的视图的中心是 centerOfView,你便能清楚自己想要以哪里为中心(actualPosition)。所以为了用实际位置去匹配视图中心位置,你需要做的便是向 下倾斜地图!
通过从视图中心减去实际位置你便能够做到这点,然后将HelloWorld层面设为该位置。
说了这么多理论,是时候执行它们了!创建并运行项目,如果一切运行正常,你将在屏幕上看到忍者,并且视图会不断移动去呈现他的行动。
simulator(from raywenderlich)
让忍者移动
这是个好的开始,但是你的忍者还只是站在那里!这并不像真正的忍者。你将朝着用户敲打的方向移动忍者而让他动起来。添加如下代码到HelloWorldScene.h的公共部分:
void&registerWithTouchDispatcher();&void&setPlayerPosition(CCPoint&position);&bool&ccTouchBegan(CCTouch&*touch,&CCEvent&*event);&void&ccTouchEnded(CCTouch&*touch,&CCEvent&*event);&
然后打开HelloWorldScene.cpp并将如下代码添加到init:
this-&setTouchEnabled(true);&
这将层面设置为可碰触的,所以它将关注于碰触事件。接下来添加如下方法到文件最底端:
#pragma&mark&&&handle&touches&&void&HelloWorld::registerWithTouchDispatcher()&{&CCDirector::sharedDirector()-&getTouchDispatcher()-&addTargetedDelegate(this,&0,&true);&}&&bool&HelloWorld::ccTouchBegan(CCTouch&*touch,&CCEvent&*event)&{&return&true;&}&&void&HelloWorld::setPlayerPosition(CCPoint&position)&{&_player-&setPosition(position);&}&&void&HelloWorld::ccTouchEnded(CCTouch&*touch,&CCEvent&*event)&{&CCPoint&touchLocation&=&touch-&getLocationInView();&touchLocation&=&CCDirector::sharedDirector()-&convertToGL(touchLocation);&touchLocation&=&this-&convertToNodeSpace(touchLocation);&&CCPoint&playerPos&=&_player-&getPosition();&CCPoint&diff&=&ccpSub(touchLocation,&playerPos);&&if&(&abs(diff.x)&&&abs(diff.y)&)&{&if&(diff.x&&&0)&{&playerPos.x&+=&_tileMap-&getTileSize().&}&else&{&playerPos.x&-=&_tileMap-&getTileSize().&}&}&else&{&if&(diff.y&&&0)&{&playerPos.y&+=&_tileMap-&getTileSize().&}&else&{&playerPos.y&-=&_tileMap-&getTileSize().&}&}&&&if&(playerPos.x&&=&(_tileMap-&getMapSize().width&*&_tileMap-&getTileSize().width)&&&&playerPos.y&&=&(_tileMap-&getMapSize().height&*&_tileMap-&getTileSize().height)&&&&playerPos.y&&=&0&&&&playerPos.x&&=&0&)&{&this-&setPlayerPosition(playerPos);&}&&this-&setViewPointCenter(_player-&getPosition());&}&
在此你覆盖了registerWithTouchDispatcher方法去处理目标碰触事件。这将导致ccTouchBegan/ccTouchEnded方法(单数情况)被调用,而不是ccTouchesBegan/ccTouchesEnded方法(复数情况)。
你可能会好奇单数情况和复数情况有什么区别。不过在这种情况下我们没有必要去弄清楚这些问题。但是我还是想向所有人介绍这一方法,因为它带有2个主要优势:
&你不需要处理NSSets,调度程序能够区分它们。每次调用你将获得一个UITouch。&
&你可以通过在ccTouchBegan返回YES而要求一个UITouch。要求碰触的更新只会被发送到要求它们的委托中。所以如果你删除/结束/取消更新,你就需要确保它是你的碰触。这将让你无需在执行多点碰触时做各种检查。&
不管怎样,在你的ccTouchEnded位置上,你像往常那样将位置转换成视图坐标轴,然后再转换成GL坐标轴。而新任务便是你调用了this-&convertToNodeSpace(touchLocation)。
这是因为碰触位置将提供给你用户在视口中轻敲的坐标轴(例如100,100)。但是你可能已经滚动了地图,所以它将匹配(800,800)的位置。所以调用这一方法将基于你如何移动层面而抵消碰触。
接下来你将明确碰触点和玩家位置的区别。你将基于碰触选择一个方向,所以首先你应该决定是上下移动还是左右移动。然后你将判断是正数还是复数而进行上下移动。
你将相对地调整玩家位置,然后将视图中心设置为玩家的位置,这是你在上部分便写下的内容!
注意你必须添加一个安全检查以确保不会将玩家带离地图外部!
所以创建并运行项目,然后尝试它!现在你应该能够轻敲屏幕去移动忍者了!
simulator(from raywenderlich)
这时候你已经知道如何创造地图并将其整合到游戏中了。而在第二部分教程中你将进一步学习如何添加碰撞检测到地图中以避免忍者能够轻松地穿越墙壁。【编辑推荐】【责任编辑: TEL:(010)】
关于&&的更多文章
Cocos2d是一个开源框架,用于构建2D游戏、演示程序和其他图形界
随着云计算、物联网、大数据、移动互联网的大发展,你应该知道这些。
当下,移动App的开发相当火热,Android的和iOS的开发
关于App营销,了解哪类App最能引起用户关注,以及不同
在iOS开发过程中,尤其是对于新手来说,都会遇到或多
数据库技术是计算机科学中一个重要的组成部分,它正在以日新月异的速度发展。数据库的基本原理和应用技术已经成为高等院校的学生
Windows Phone专家
Android开发专家
51CTO旗下网站

我要回帖

更多关于 tiled地图编辑器 的文章

 

随机推荐