TileMap实例化地图对象的代码移动对象层不会跟着动吗

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
学习的路上,与君共勉。使用cocos2d-x制作基于Tile地图的游戏(一) - 推酷
使用cocos2d-x制作基于Tile地图的游戏(一)
本教程基于子龙山人翻译的cocos2d的IPHONE教程,用cocos2d-x for XNA引擎重写,加上我一些加工制作。教程中大多数文字图片都是原作者和翻译作者子龙山人,还有不少是我自己的理解和加工。感谢原作者的教程和子龙山人的翻译。本教程仅供学习交流之用,切勿进行商业传播。
子龙山人翻译的Iphone教程地址:
程序截图:
在这个分为几部分教程中(我还没想好是几部分⊙﹏⊙b汗),我将会教大家如何使用cocos2d-x来做一个基于tile地图的游戏,当然还有Tiled地图编辑器。(我们小时候玩的小霸王小学机里面的游戏,大部分都是基于tile地图的游戏,如重装机兵,坦克大战、冒险岛、吞食天地等)我们将会创建一个忍者在沙漠中找东西吃的小游戏,并且被怪物追赶的游戏-_-
在这第一部分教程中,我将教大家如何使用Tile来创建地图,怎样把地图加到游戏中,怎么让地图跟随玩家滚动,以及怎样使用对象层。
如果你还没有准备好的话,你可能需要先从
》系列教程开始学起,因为我们这个教程使用了大量的基本概念,而这些概念都可以从上面的教程中获取。
好了,让我们玩一玩tile地图吧!
打开VS2010,新建一个cocos2d-x项目。命名为cocos2dTIleMapGameDemo,同样的,openxLIve这个服务我们也用不到,所以那个勾同样去掉。同样的,添加和修复引用也是必要的。
接下来,下载游戏资源文件(
),这个资源文件包里包含了以下内容:
一些音效。
一些背景音乐。
我们将会使用的tile集合--它实际上会和tile地图编辑器一块儿使用,但是,我想把它放在这里,余下的事情会变得更容易。
一些额外的“特殊”的tile,我将会在后面加以说明。
一旦你获得了这些资源,解压并把它添加到你的Content工程的“Resources”目录下面。
如果一切顺利,所有的文件应该都在你的工程里了。是时候制作我们的地图了!
使用Tile来制作地图
cocos2d-x支持使用Tile地图编辑器(
)创建的TMX格式的地图。
下载完之后,直接双击运行安装。点击文件\新文件,然后会出现以下对话框:
在 地图方向部分,你可以选择正常。
接下来,设置地图的大小。记住,这个大小是以tile为单位的,而不是以像素为单位。我们将创建一个尽量小的地图,因此选择32&32(现在发现50*50的地图WP7不能加载全,最大32*32。不过在test工程里面的示例再怎么样的地图都行。不过人家用的摄影机,不是我这种的设置位置的方法,现在还没有研究为啥)
最后,你指定每个地图的宽度和高度。你这里选择的宽度和高度要根据你的实际的tile图片的尺寸来做。这个教程使用的样例tile的尺寸是32&32,所以在上面的选项中选择32&32.
接下来,我们把制作地图所需要的tile集合导入进来。点击菜单栏上面的“地图”菜单,“新图块.”,然后会出现下面的窗口:
为了获得图片,点击Browse按钮,然后定位到你的Resource文件夹,选择 tmw_desert_spacing.png文件,然后加到工程中去。它会基于文件名自动填充名字。点击确定即可。
将会看到图块窗口中显示了一些tiles。现在,你可以制作地图了!点击一个Tile。你就可以在任何设置图块了。这个就像画图工具,什么画刷也能用,具体看工具栏,这样可以快速制作地图。
充分发挥你的聪明才智!确保增加至少一对建筑物在地图上,因为后面我们需要一些东西来做碰撞。
一旦你完成了地图的绘制工作,在Layers选项卡的层上面双击(现在可以说是“图层1”),然后重命名为“background”。然后点击“文件\保存”并且保存文件到你的工程的Resource文件夹中,并且命名为“TileMap.tmx”。
把tile地图添加到cocos2d的场景中
现在新建一个类,命名为
。来作为我们游戏场景。并且里面的代码修改为:
class TileMapScene:CCScene
public TileMapScene()
this.addChild(TileMapLayer.node());
class TileMapLayer : CCLayer
public override bool init()
if (!base.init())
public static new TileMapLayer node()
TileMapLayer layer = new TileMapLayer();
if (layer.init())
并且修改导演类里面的
。修改如下:
//CCScene pScene = cocos2dTIleMapGameDemoScene.scene();
CCScene pScene = new TileMapScene();
现在需要添加两个引用。ICSharpCode.SharpZipLib.DLL和zlib.net.DLL。这两个DLL可以在cocos2d-x的安装包的Test工程的bin目录下面找到。然后在解决方案资源管理器里面选择TileMap.tmx文件,选择属性,确认Content Importer和Content Processor如下面所选,如果没找到下面选项,确认Content工程的引用中的cocos2d.Content.Pipeline.Importers正确引用
现在打开TileMap.tmx文件。
确认image 的source路径为相对路径,相对Tmx文件的相对路径。
做完上面的工作后,现在再添加一些声明到TileMapLayer类中。
CCTMXTiledMap tileMap =
CCTMXLayer background =
并且添加以下代码到Init中。
tileMap = CCTMXTiledMap.tiledMapWithTMXFile(&Resources/TileMap&);
background = tileMap.layerNamed(&background&);
addChild(tileMap, -1);
这里,我们调用CCTMXTiledMap类的一些方法,把我们刚刚创建的地图文件加载进去。
一些简明的CCTMXTiledMap的背景知识。它是一个CCNode,你可以设置它的位置和比例等。这个地图的孩子是一些层,而且提供了一个帮助函数可以让你通过层的名字得到层对象--我们上面就是通过这种方面获得地图背景的。每一个层都是一个CCSpriteSheet的子类,这里考虑了性能的原因--但是这也意味着每一个层只能有一个tile集。
因此,我们这里做的所有这些,就是指向一个tile地图,然后保存背景层的引用,并且把tile地图加到TileMapLayer层中。
好了,就这么多!编译并运行工程,你将会看到地图的左下角出现在模拟器中。
还不错!但是,这还不是一个游戏!我们还需要三个东西:a)游戏主角,b)主角初使位置和c)能够移动视图,这样就好像是第一视角了。
好了,接下来让我们来解决这些问题。
tiled对象层和设置tile地图位置
tiled支持两类层--tile层(就是我们目前使用的层),还有对象层。
对象层允许你在地图上圈出一些区域,来指定一些事件的发生。比如,你可能想制作一个区域,在那里怪物将会跳出来,或者是一个区域,只要进入就会死掉。这我们这个例子中,我们将创建一个区域来显示我们的游戏主角。
因此,找到Tiled的菜单,点击” 图层\添加对象层”,命名为“Objects”,然后按回车键。
我们只想要选择一个tile来让主角显示。先在工具栏上面选择添加对象。
因此,在你的地图上选择一个tile。这个区域的大小实际上并没有关系,因为我们仅仅使用x、y坐标。
然后,上面的灰蓝色对象框上面点右键,选择“对象属性”, 取名为“SpawnPoint&,然后选择确定:
现在,保存TMX文件,并且记得更新到Resource文件夹。
然后往TileMapLayer里面添加一个声明:
CCSprite player =
同时修改Init方法(在return true前面添加):
CCTMXObjectGroup objects = tileMap.objectGroupNamed(&Objects&);
if (objects != null)
//Debug.WriteLine(objects.Properties.ToString());
foreach (var item in objects.Objects)
if (item.ContainsValue(&SpawnPoint&))
x = Convert.ToInt32(item[&x&]);
y = Convert.ToInt32(item[&y&]);
player = CCSprite.spriteWithFile(@&Resources/Player&);
player.position = new CCPoint(x, y);
this.addChild(player);
this.setViewpointCenter(player.position);
好了,让我们先歇会儿,来解释一下对象层和对象组。首先,注意你通过CCTMXTiledMap对象的objectGroupNamed方法来获得对象层(而不是layerNamed方法)。它返回一个特殊的CCTMXObjectGroup对象。
我们然后调用CCTMXObjectGroup类的Objects是一个List&IDictionary&string,string&&对象,其有一个name的key的value就是我们定义的SpawnPoint,这个字典包含了关于对象的大量信息,包括x和y坐标值,宽度和高度。在这个例子中,我们只关心x和y坐标,因此,我们提取出这两个信息,并且设置player的位置。
PS:在这里随意提下调试技巧吧。本来我也不懂这个
CCTMXObjectGroup类是怎么回事,也不懂里面的数据是怎么保存的。虽然知道是一个字典的List,但是不知道我需要的信息在哪,那么就在上面的for循环前面添加一个断点。然后运行到断点处对objects.Objects对象进行快速监视,在快速监视窗口查找需要的信息。这个方法对于不认识的对象可以很好了解其情况。
最后,我想设置这个视图为玩家所在的位置。因此,添加下面一个新方法到文件中:
void setViewpointCenter(CCPoint position)
CCSize winSize = CCDirector.sharedDirector().getWinSize();
float x = Math.Max(position.x, winSize.width / 2);
float y = Math.Max(position.y, winSize.height / 2);
x = Math.Min(x, (tileMap.MapSize.width * tileMap.TileSize.width) - winSize.width / 2);
y = Math.Min(y, tileMap.MapSize.height * tileMap.TileSize.height - winSize.height / 2);
CCPoint acturalPosition = new CCPoint(x, y);
CCPoint centerView = new CCPoint(winSize.width / 2, winSize.height / 2);
CCPoint viewPoint = CCPointExtension.ccpSub(centerView, acturalPosition);
this.position = viewP
好了,让我解释一下。假设这个函数是设置camera的中心。我们允许用户传入地图上任何x、y坐标值--但是如果你仔细想一下,有些东西我们并不想让它显示出来--比如,我们不想让屏幕超过地图的边界(那些区域仅仅是一个空白区域!)
比如,看看下面这幅图:
看一下,什么时候camera的中心会小于winSize.width/2或者winSize.height/2,部分视图将会在屏幕之外?类似的,我们需要检查上面的界限区间,也和我们这里的情形一样。
因此,我们把这个函数看作是设置camera的视角中心点。然而。。。那不完全是我们想要的。在cocos2d里面有一种方式可以直接操作一个CCNode的camera,但是那会使事情变得更复杂。我们需要另一种替代方法,那就是移动整个层。
看看下面的图:
想像一个大的地图,我们查看从0到winSize.height/width的坐标。我们的视图的中心点是centerOfView,而且我们知道我们要把这个中心设置到哪里(actualPositon)。因此,为了使实际的位置和视图中心相吻合,我们只需要把地图往左下角移动即可!
这个可以通过使实际的位置减去视图的中心位置来实现,然后设置TileMapLayer层到那个点。
唉!太多理论了--让我们看点实际的吧!编译并运行项目,如果一切顺利,你将会看到忍者在场景当中,然而视角也移过来了。
似乎上面的忍者放置太靠左下角了。。。。不过也可以看出来视觉移过来了
使忍者移动
我们已经有一个好的开端了,但是我们的忍者只是站在那儿不动!这可不像真正的忍者!
让我们使忍者动起来吧,只需要让忍者移动到用户点击的地方就行了。在TileMapLayer类中的init增加以下代码:
this.isTouchEnabled =
然后往类中添加添加以下方法:
public override void registerWithTouchDispatcher()
CCTouchDispatcher.sharedDispatcher().addTargetedDelegate(this, 0, true);
void setPlayerPosition(CCPoint position)
player.position =
public override bool ccTouchBegan(CCTouch touch, CCEvent event_)
public override void ccTouchEnded(CCTouch touch, CCEvent event_)
CCPoint touchLocation = touch.locationInView(touch.view());
touchLocation = CCDirector.sharedDirector().convertToGL(touchLocation);
touchLocation = this.convertToNodeSpace(touchLocation);
CCPoint playerPos = new CCPoint(player.position.x, player.position.y);
CCPoint diff = CCPointExtension.ccpSub(touchLocation, playerPos);
if (Math.Abs(diff.x) & Math.Abs(diff.y))
if (diff.x & 0)
playerPos.x += tileMap.TileSize.
playerPos.x -= tileMap.TileSize.
if (diff.y & 0)
playerPos.y += tileMap.TileSize.
playerPos.y -= tileMap.TileSize.
if (playerPos.x &= tileMap.MapSize.width * tileMap.TileSize.width &&
playerPos.y &= tileMap.MapSize.height * tileMap.TileSize.height &&
playerPos.x &= 0 &&
playerPos.y &= 0)
this.setPlayerPosition(playerPos);
this.setViewpointCenter(player.position);
首先,在init方法中设置层能够接收touch事件。如果我们覆盖registerWithTouchDispatcher方法,来使这个层能够处理目标touch事件。这样会导致ccTouchBegan和ccTouchEnded方法被调用(注意是单数形式,而不是复数形式的ccTouchesBegan和ccTouchesEnded方法)
你可能会问,为什么我要讲这个,因为我们在
》里面使用的是ccTouchesBegan和ccTouchesEnded方法。那两个方法可以,在这个教程里用两种方法都可以。但是,我想向大家介绍一个新方法,因为它有两个优点:
划分UITouch集合并调度的工作全部由cocos2d-x框架来完成。每一次方法调用,你只获得了一个UITouch。“
“你可以在ccTouchBegan中返回true,这样当前的层就可以接收touch事件回调。而且,只有当你返回yes的时候,才会响应move/ended/cancelled回调. 这个就使你从一些复杂的多触摸判断中解放出来了。
不管怎么说,在我们的ccTouchEnded里面,我们转换屏幕touch坐标为局部view坐标,然后再转换成GL的坐标。这两个步骤,只需要一步完成,即调用 [self convertToNodeSpace:touchLocation].就可以了。
这是因为,touch位置只是告诉我们屏幕视口的坐标(比如100,100)。但是,我们我们滚动了地图,这个位置实际可能对应地图的(800,800)。因此,调用这个方法基于我们当前层的位置来决定touch的偏移。
接下来,计算出touch点和player的位置之差。我们必须基于touch位置选择一个方向,因此,首先,我们需要计算出是上下移动还是左右移动。然后,我们比较正负值,决定具体的方向。
相应的,我们再调整player的位置,并且设置player的位置为视口的中心位置,这个在上一节中已经用到了。
编译并运行!你现在可以点击鼠标,想让尽者移到哪,它就移到哪儿!
何去何从?
这只是这个教程的一部分。此时,你应该了解一些创建tile地图的基础了,而且知道如何把它导入到游戏当中。
这里有我们目前为止用的完整源代码(
接下,期待第二部分教程吧!在那里,我将教大家如何在地图中添加碰撞检测,如果使我们的忍者沿着墙壁快乐的奔跑!
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致}

我要回帖

更多关于 高德地图poi对象 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信