如何使用tiledmap 下载地图

温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
在这篇教程里,我们会讲解如何使用cocos2d和Tiled Map Editor创建一个基于tiled map的游戏.作为例子,我们会制作一个小游戏.游戏的主要内容是一个忍者在沙漠里寻找可口的西瓜吃. 这篇教程主要学习的内容有:如何创建Tiled M如何将地图载入到游戏内;如何让地图跟随玩家滚动;如何使用对象层. 下一节里,我们再介绍:如何在地图上制作可碰撞区域;如何使用tile属性;如何制作可碰撞物体和动态改变地图;如何确定你的小忍者没有吃撑:) 当然,如果你是个iphone开发新手,作为基础知识的准备,我建议你先阅读一下. 创建游戏骨架 下面我们要创建游戏骨架.并且准备好需要的资源文件. 打开XCode,File\New Project,选择cocos2d Application创建一个新工程. 接下来,,这里面包含了游戏需要的资源: 主角精灵一些游戏音效(使用制作)游戏背景音(使用Garage Band制作,)用于构造tiled map的元件一些特殊的元件,后面会详细解释 将下载到的资源解包拖入xcode的resources组,记得选中”Copy items into destination group’s folder(if needed)”. 这样,一切准备就绪. 创建游戏地图 Cocos2d支持使用开源软件(貌似被伟大的墙挡住了,天朝的用户可以直接访问它在,杯具!)创建的TMX格式地图. 如果你访问上面的链接,你会发现有两个版本可用.一个使用Qt应用程序框架编写,另一个使用Java编写.这是因为最初Tiled Map Editor使用Java编写,后来移植到Qt框架上.使用哪个版本都可以.在这篇教程里,我们以使用Qt版本的为例,因为它将作为今后的开发主线.有些 人喜欢使用java版本,是因为还有些老版本上的功能尚未移植到Qt框架上. 运行Tiled Map Editor,新建一个地图.填写如下对话框
在orientation选项内,可以选择Orthogonal(平面直角)或Isometric(45度视角,传说中的2.5D),这里选择Orthogonal. 接下来需要设置地图大小.这里的数值是指有多少格tiled元件,并不是像素.选择50×50即可. 最后,确定tile元件的大小.根据美工提供的元件大小设置.这个教成立,我们使用32×32的大小. 接下来,将tile元件添加到地图内绘制地图.在Map菜单许做呢New Tileset,填写下面的对话框.
点击Browser从电脑里找到tmw_desert_spacing.png文件(下载的资源包内) 保持长宽数据为32×32. 对于margin和spacing,我没有找到文档说明,但是我认为它们的意义是:
* Margin 表示当前tiled在开始搜索实际像素时应该忽略多少个像素 (译者注:我理解应该是两个tiled元件之间的间距)
* Spacing 表示读取下一个tiled数据后应该向前推进多少个像素(译者注:我理解应该是两个tiled元件之间的空隙,不过,这好像与Margin重复了…) 如果你仔细观察tmw_desert_spacing.png,你会发现每个tiled元件之间都有1像素的黑边.这样的图片需要将margin和spacing设置为1
点击OK,tiled元件将被显示在Tilesets窗口内.现在你可以开始绘制地图了.点击工具条上的Stamp(印章)图标,选择一个tiled元件,在地图内需要的位置点击放置地图元件.
按上面的方法绘制一张地图. 至少在地图上绘制几个建筑,因为后面我们要用到它们.
一些快速技巧最好记住:
* 你可以一次添加多个tiled元件到地图里.(画一个方块选中多个tiled元件).
* 可以使用油漆筒按钮填充地图背景.
* 可以在view菜单里放大缩小地图. 画好第图后,双击Layers窗口里的层(一般是取名为Layer1),改名为Background.在File菜单内选择Save,将地图保存到xcode项目内,取名tiledmap.tmx 将Tiled Map添加到Cocos2d Scene中 将刚才创建的tmx文件拖入项目resources内.打开HelloWorldLayer.h文件,添加一些代码. 123456789101112131415#import "cocos2d.h"
// HelloWorld Layer @interface HelloWorld : CCLayer { & & CCTMXTiledMap *_tileM & & CCTMXLayer *_
} @property (nonatomic, retain) CCTMXTiledMap *tileM @property (nonatomic, retain) CCTMXLayer * // returns a Scene that contains the HelloWorld as the only child +(id)
@end 在HelloWorldLayer.m添加代码 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647// Import the interfaces #import "HelloWorldScene.h"
// HelloWorld implementation @implementation HelloWorld
// Right after the implementation section @synthesize tileMap = _tileM @synthesize background = _
// Replace the init method with the following -(id) init { & & if( (self=[super init] )) { & & & &
& & & & self.tileMap = [CCTMXTiledMap tiledMapWithTMXFile:@"TileMap.tmx"]; & & & & self.background = [_tileMap layerNamed:@"Background"]; & & & &
& & & & [self addChild:_tileMap z:-1]; & & & &
& & } & & return }
+(id) scene { & & // 'scene' is an autorelease object. & & CCScene *scene = [CCScene node]; & &
& & // 'layer' is an autorelease object. & & HelloWorld *layer = [HelloWorld node]; & &
& & // add layer as a child to scene & & [scene addChild: layer]; & &
& & // return the scene & & return }
// on "dealloc" you need to release all your retained objects - (void) dealloc { & & self.tileMap = nil; & & self.background = nil; & & [super dealloc]; } @end 这里我们调用CCTMXTiledMap从map文件创建了一个地图. 关于CCTMXTiledMap的一些简要介绍.它是CCNode的子类.所以我们可以设置position, scale等.这个node包含着地图的层,并且包含一些函数使你可以通过名字找到它们.为了提高性能,每一层使用的都是CCSpriteSheet的子 类. 这也意味着每个tiled元件在每一层都只有一个实例. 接下来我们要做的是利用地图和层的引用把他们添加到HelloWorld层. 编译运行代码,你将能够看到地图的左下角.
看起来不错!不过作为一个游戏,我们还需要做三件事:1.一个游戏主角;2.一个放置主角的起始点;3.移动视图,让我们的视角一直跟随主角. 这些才是开发这个游戏关键工作,我们一个个解决. 对象层和设置Tiled Map的位置. Tiled Map Editor支持两种层: tile layers(铺展层,前面我们使用过)和object layers(对象层). Object layers 允许你以一点为中心在地图上圈定一个区域.这个区域内可以触发一些事件.比如:你可以制作一个区域来产生怪物,或者制作一个区域进去就会死亡.在我们的例子里,我们制作一个区域作为主角的产生点. 打开TiledMapEditor,在Layer菜单选择Add Object Layer.新layer取名objects.注意,在object layer里不会绘制tiled元件,它会绘制一些灰色的圆角形状.你可以展开或者移动这些形状. 我们是想选择一个tile元件作为主角的进入点.所以,在地图里点击一个tiled元件,产生的形状的大小无所谓,我们会使用x,y坐标来指定.
接下来,右键选择刚才添加的灰色形状,点击Properties.设置名字为 “SpawnPoint”
也许你可以设置这个对象的Type为Cocos2D的类名.并且它会创建一个对象(比如CCSprite),但是我没有找到源代码里如何完成这些工作. 不管它,我们保留type区域为空,它将创建一个NSMutableDictionary用来访问对象的各种参数,比如x,y坐标. 保存地图回到xcode.修改HelloWorldScene.h 12345// Inside the HelloWorld class declaration CCSprite *_ & // After the class declaration @property (nonatomic, retain) CCSprite * 修改HelloWorldScene.m 12345678910111213141516171819// Right after the implementation section @synthesize player = _ & // In dealloc self.player = nil; & // Inside the init method, after setting self.background CCTMXObjectGroup *objects = [_tileMap objectGroupNamed:@"Objects"]; NSAssert(objects != nil, @"'Objects' object group not found"); NSMutableDictionary *spawnPoint = [objects objectNamed:@"SpawnPoint"]; & & & & NSAssert(spawnPoint != nil, @"SpawnPoint object not found"); int x = [[spawnPoint valueForKey:@"x"] intValue]; int y = [[spawnPoint valueForKey:@"y"] intValue]; & self.player = [CCSprite spriteWithFile:@"Player.png"]; _player.position = ccp(x, y); [self addChild:_player];
& [self setViewpointCenter:_player.position]; 我们先花一点时间解释一下object layer和object groups. 首先,我们通过CCTMXTiledMap对象的objectGroupNamed方法取回object layers.这个方法返回的是一个CCTMXObjectGroup对象. 接下来,调用CCTMXObjectGroup对象的objectNamed方法得到包含一组重要信息的NSMutableDictionary.包括x,y坐标,宽度,高度等. 在这里,我们主要需要的是x,y坐标.我们取得坐标并用它们来设置主角精灵的位置. 最后,我们要把主角作为视觉中心来显示.现在,添加下面的代码: 1234567891011121314151617-(void)setViewpointCenter:(CGPoint) position { & & & CGSize winSize = [[CCDirector sharedDirector] winSize]; & & & int x = MAX(position.x, winSize.width / 2); & & int y = MAX(position.y, winSize.height / 2); & & x = MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width)
& & & & - winSize.width / 2); & & y = MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height)
& & & & - winSize.height/2); & & CGPoint actualPosition = ccp(x, y); & & & CGPoint centerOfView = ccp(winSize.width/2, winSize.height/2); & & CGPoint viewPoint = ccpSub(centerOfView, actualPosition); & & self.position = viewP & } 同样做一下简要的解释.想象这个函数是把视线设置到取景中心.我们可以在地图里设置任何x,y坐标,但是有些坐标不能正确的处理显示.比如,我们不能让显示区域超出地图的边界.否则就会出现空白区. 下面的图片更能说明这个问题:
屏幕的宽高计算后,要与显示区域的宽高做相应的适配.我们需要检测屏幕到达地图边缘的情况. 在cocos2d里本来有一些操控camera(可以理解为可视取景区)的方法,但是使用它可能搞得更复杂.还不如靠直接移动layer里的元素来解决更简单有效. 继续看下面这张图:
把整张地图想象为一个大的世界,我们的可见区是其中的一部分.主角实际的坐标并不是世界实际的中心.但是在我们的视觉内,要把主角放在中心点,所以,我们只需要根据主角的坐标便宜,调整世界中心的相对位置就可以了. 实现的方法是把实际中心与屏幕中心做一个差值,然后把HelloWorld Layer设置到相应的位置. 好,现在编译运行,我们会看到小忍者出现在屏幕上.
使主角移动 前面进行的都不错,但是到目前为止,我们的小忍者还不会动. 接下来,我们让小忍者根据用户在屏幕上点击的位置方向来移动(点击屏幕上半部分向上移,依此类推). 修改HelloWorldScene.m的代码 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152// Inside init method self.isTouchEnabled = YES; & -(void) registerWithTouchDispatcher { & & [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
& & & & & & priority:0 swallowsTouches:YES]; } & -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { & & return YES; } & -(void)setPlayerPosition:(CGPoint)position { & & _player.position = } & -(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event { & & & CGPoint touchLocation = [touch locationInView: [touch view]]; & & &
& & touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation]; & & touchLocation = [self convertToNodeSpace:touchLocation]; & & & CGPoint playerPos = _player. & & CGPoint diff = ccpSub(touchLocation, playerPos); & & if (abs(diff.x) & abs(diff.y)) { & & & & if (diff.x & 0) { & & & & & & playerPos.x += _tileMap.tileSize. & & & & } else { & & & & & & playerPos.x -= _tileMap.tileSize.
& & & & } & & & & } else { & & & & if (diff.y & 0) { & & & & & & playerPos.y += _tileMap.tileSize. & & & & } else { & & & & & & playerPos.y -= _tileMap.tileSize. & & & & } & & } & & & if (playerPos.x &= (_tileMap.mapSize.width * _tileMap.tileSize.width) && & & & & playerPos.y &= (_tileMap.mapSize.height * _tileMap.tileSize.height) && & & & & playerPos.y &= 0 && & & & & playerPos.x &= 0 )
& & { & & & & & & [self setPlayerPosition:playerPos]; & & } & & & [self setViewpointCenter:_player.position]; & } 首先,我们在init方法里设置屏幕接受触摸事件.接下来,覆盖registerWithTouchDispatcher方法来注册我们自己的触摸 事件句柄.这样,ccTouchBegan/ccTouchEnded方法会在触摸发生时回调(单点触摸),并且屏蔽掉ccTouchesBegan /ccTouchesEnded方法的回调(多点触摸) 你可能奇怪,为什么不能使用ccTouchesBegan/ccTouchesEnded方法呢?是的,我们的确可以使用,但是不建议这么做,有两点原因:
* 你不需要再处理NSSets,事件分发器会帮你处理它们,你会在每次触摸得到独立的回调.
* 你可以在ccTouchBegan事件返回YES来告知delegate这事你想要的事件,这样你可以在move/ended/cancelled等后续的事件里方便的处理.这比起使用多点触摸要省去很多的工作. 通常,我们会将触摸的位置转换为view坐标系,然后再转换为GL坐标系.这个例子里的小变化,只是调用了一下 [self convertToNodeSpace:touchLocation]. 这是因为触摸点给我们的是显示区的坐标,而我们其实已经移动过地图的位置.所以,调用这个方法来得到便宜后的坐标. 接下来,我们要搞清楚触摸点与主角位置的相对关系.然后根据向量的正负关系,决定主角的移动方向. 我们相应的调节主角的位置,然后设置屏幕中心到主角上. 注意:我们需要做一个安全检查,不要让我们的主角移出了地图. 好了,现在可以编译运行了,尝试触摸屏幕来移动一下小忍者吧.
接下来做什么? 现在你已经了解了如何创建一个基于tiled map的游戏. 这里是根据这篇教程完成的代码: 下一篇里,我们将学习如何在地图里检测碰撞(或者说,设置不同的通过性),因为现在我们的小忍者是可以穿墙的…
阅读(17934)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'[译]在Tiled Map中使用碰撞检测(一) 创建基于Tiled Map的游戏',
blogAbstract:'
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}用户名:guoshuang_123
访问量:277
注册日期:
阅读量:1297
阅读量:3317
阅读量:436548
阅读量:1123711
51CTO推荐博文
1.地图的创建,我利用的是tiled的软件,仿照上面的博客创建了地图2.地图的加载,我用的是vs2010和cocos2dx2.0.4版本tiled = CCTMXTiledMap::create("ortho-objects.tmx");//加载地图//tiled-&setScale(0.8f);this-&addChild(tiled,1,111);tiled-&setPosition(ccp(0,0));int mapwidth = tiled-&getMapSize().width * tiled-&getTileSize().int mapheigt = tiled-&getMapSize().height *tiled-&getTileSize().3.我的主角是一个小人,在地图上面来回运动,动画创建不写了,现在写一下我的左右移动的检测函数,因为瓦片的坐标与屏幕的坐标是不同的,屏幕的坐标是以左下角为原点,但是瓦片的坐标是以左上角为原点坐标,假设地图为m行n列,那么左上角坐标为(0,0),右下角的坐标就为(m-1,n-1)void Map::playermaphcollision(){CCPoint playerpos = gamelayer-&getPosition();CCSize playersize = gamelayer-&getContentSize();CCTMXTiledMap *map = (CCTMXTiledMap*)getChildByTag(111);int idexx,//获取布景层CCTMXLayer *layer = map-&layerNamed("logic");for (int playery = playerpos.y - playersize.playery & playerpos.y;playery++){//主角在左边界idexx =(playerpos.x-playersize.width/2)/map-&getTileSize().idexy =map-&getMapSize().height- (playerpos.y/map-&getTileSize().height);CCPoint pos = ccp(idexx,idexy-1);int titleGid = layer-&tileGIDAt(pos);//获取图层元素的gid值if(titleGid & 0){//CCDictionary的作用就是读取xml的文件的类CCDictionary *titledic = map-&propertiesForGID(titleGid);//根据gid获取xml里面的属性值if (titledic){CCString *mvalua = (CCString*)titledic-&objectForKey("collion");//根据键值获取value的值if (mvalua){int mv = mvalua-&intValue();//转换为我们所需要的类型if (mv == 2){playerpos.x = (idexx+1)*map-&getTileSize().width+playersize.width/2;gamelayer-&setPosition(playerpos);}}}}//右移的情况,暂时没右移,可以忽略idexx = (playerpos.x + playersize.width/2)/map-&getTileSize().idexy = map-&getMapSize().height- (playerpos.y/map-&getTileSize().height);CCPoint pos1 = ccp(idexx,idexy);int tilegid = layer-&tileGIDAt(pos1);if (tilegid & 0){CCDictionary *titledic1 = map-&propertiesForGID(tilegid);if (titledic1){CCString *mava1 = (CCString*)titledic1-&objectForKey("collion");int mv1 = mava1-&intValue();if (mv1 == 2){playerpos.x = (idexx-1)*map-&getTileSize().width-playersize.width/2;gamelayer-&setPosition(playerpos);}}}}}4.检测碰撞bool Map::iscollision(CCSprite *mysprite,CCSprite *testsprite){CCPoint ownpos = mysprite-&getPosition();CCPoint otherpos = testsprite-&getPosition();CCSize ownsize = mysprite-&getContentSize();CCSize othersize = testsprite-&getContentSize();CCRect ownrect = CCRectMake(ownpos.x-ownsize.width/2,ownpos.y-ownsize.height/2,ownsize.width,ownsize.height);CCRect otherrect = CCRectMake(otherpos.x-othersize.width/2,otherpos.y-othersize.height/2,othersize.width,othersize.height);if (ownrect.intersectsRect(otherrect)){}}这个写法很多新手一个,有些地方错了,大家给我说一下本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:未分类┆阅读(0)┆评论(0)4509人阅读
游戏(29)
程序截图:
  这篇教程是《如何使用cocos2d制作基于tiled地图的游戏》的第二部分。在上一个教程中,我们创建了一个简单的基于tiled地图的游戏,里面有一个忍者在沙漠里寻找可口的西瓜!
  在中,我们介绍了如何基于tiled创建地图,怎样把地图增加到游戏中去,以及如何滚动地图来跟随主角移动、还有如何使用对象层。
  在这部分教程中,我们将会介绍如何在地图中制作可以碰撞的区域,如何使用tile属性,如果收集游戏物品并且动态地修改地图、如何确保你的忍者不会吃得太饱!
  因此,让我们继续我们上篇教程所学并且让它更像一个真实的游戏吧!
tiled地图和碰撞检测
  你可能已经注意到了,目前我们的忍者可以毫无阻拦地穿过墙壁和障碍物。他是一个忍者,但是即使是真正的忍者,他也没这么厉害啊!
  因此,我们需要找到一种方法,通过把一些tile标记成“可碰撞的”,这样的话,我们就可以防止玩家穿过那些点的位置。有很多方法可以做得到(包括使用对象层),但是,我想向你们展示一种新的技术。我认为它更高效,并且也是一次好的学习锻炼--使用一个元层(meta layer)和层属性。
  让我们开始动手吧!再一次启动Tiled软件,点击“Layer\Add tile Lyaer...”,并且命名为“Meta”,然后选择OK。我们将在这个层里面加入一些假的tile代表一些“特殊tile”。
  因此,现在我们需要增加我们的特殊tile。点击“Map\New tileset...”,在你的Resources文件夹下面找到mate_tiles.png,然后选择打开。设置Margin和Spacing都为1并点击OK。
  这时,你可以在Tilesets区域看到一个新的标签。打开它,而且你会看到2个tile:一个红色的和一个绿色的。
  这些tile并没有什么特殊的东西--我只是制作了一个简单的图片,里面包含了一个红色的和一个绿色的半透明tile。接下来,我们把红色的tile当作是“可碰撞的”(后面我们会用到绿色的),然后,合适地绘制我们的场景。
  因此,确保Meta层被选中,选择stamp工具,选择红色的tile,然后把任何你不想让忍者通过的地图都涂一遍。当你做完的时候,应该看起来像下面的图示一样:
  接下来,我们可以设置tile的属性,这样的话,我们在代码中就可以识别这个tile是“可以碰撞的(穿不过去的)”。在Tileset里面的红色tile上在,右击,选择“Properties...“。增加一个新的属性,叫做”Collidable“,并且设置成”Ture“:
  (由于版本的关系,我这里补充我上传的Tiled编辑器(java版本)如何设置属性!!!)
& & & &首先,选择TileSets--&TileSetManager,并选中meta_tiles,出现如下所示图:
& &&然后点击右下角的“Edit”按钮(就是垃圾回收站下面那个图标),接下来会出现下图所示:(接着就选中红色tile和绿色tile,然后添加Collidable属性并设置为True就ok啦)
  保存map,并返回Xcode。在HelloWorldScene.h中做如下改动:
//&Inside the HelloWorld class declaration
CCTMXLayer&*_
//&After the class declaration
@property (nonatomic, retain) CCTMXLayer&*
  同时修改HelloWorldScene.m文件如下:
//&Right after the implementation section
@synthesize meta&=&_
//&In dealloc
self.meta&=&
//&In init, right after loading background
self.meta&=&[_tileMap layerNamed:@&Meta&];
_meta.visible&=&NO;
//&Add new method
-&(CGPoint)tileCoordForPosition:(CGPoint)position {
int&x&=&position.x&/&_tileMap.tileSize.
int&y&=&((_tileMap.mapSize.height&*&_tileMap.tileSize.height)&-&position.y)&/&_tileMap.tileSize.
return&ccp(x, y);
  好了,让我们先停一会儿。像之前一样,我会meta层声明了一个成员变量,而且从tile map中加载了一个引用。注意,我们把这个字当作是不可见的,因为我们并不想看见这些对象,它们的存在只是为了说明,那个区域是可以碰撞的。
  接下来,我们增加一个新的帮助方法,这个方法可以帮助我们把x,y坐标转换成”tile坐标“。每一个tile都有一个坐标,从左上角的(0,0)开始,到右下角的(49,49)。(本例中,地图的大小是49×49)
  上面的截屏是java版本的tiled界面。能否显示tile的坐标,我不确定这个功能在QT版本的tiled中是否存在。不管怎么说,我们将要使用的一些功能会使用tile坐标,而不是x,y坐标。因此,我们需要一种方式,将x,y坐标转换成tile坐标。这正是那个函数所需要做的。
   获得x坐标非常容易--我们只需要让它除以一个tile的宽度就可以了。为了得到y坐标,我们不得不翻转一些东西,因为,在cocos2d里面(0,0)是在左下角的,而不是在左上角。
  接下来,把setPlayerPosition替换成以下内容:
CGPoint tileCoord&=&[self tileCoordForPosition:position];
int&tileGid&=&[_meta tileGIDAt:tileCoord];
if&(tileGid) {
NSDictionary&*properties&=&[_tileMap propertiesForGID:tileGid];
if&(properties) {
NSString&*collision&=&[properties valueForKey:@&Collidable&];
if&(collision&&&&[collision compare:@&True&]&==&NSOrderedSame)
_player.position&=&
  在这里,我们把玩家的x,y坐标转换成tile坐标。然后,我们使用meta层中的tileGIDAt方法来获取指定位置点的GID号。
  对了,什么是GID呢?GID代表”全球唯一标志符“(我个人意见)。但是,在这个例子中,我认为它只是我们使用的tile的一种标识,它可以是我们想要移动的红色区域。
  当我们使用GID来查找指定tile的属性的时候。它返回一个属性字典,因此,我们可以遍历一下,看是否有”可碰撞的“物体被设置成”true“,或者是gij仅仅就是那样。编译并运行工程,因此还没有设置玩家的位置。
  就这么多!编译并运行程序,它将会向你展示,现在你不能够通过那些红色的tile组成的地方了吧:
动态修改Tiled Map
  目前为此,我们的忍者已经有一个比较有意思的冒险啦,但是,这个世界有一点点无趣。而且简单无任务事可做!加上,我们的忍者看起来比较贪吃,而且背景将会随着玩家移动而移动。因此,让我们创建一些东西让忍者来玩吧!
  为了使之可行,我将不得不创建一个前景层,这样做可以让用户收集东西。那样的话,我们仅仅从前景层中删除不用的tile(当tile被玩角拾取的时候),这个过程中,背景将会随之移动。
  因此,打开Tiled,选择”Layer\Add Tile Layer...“,把这个层命名为”Foreground“,然后选择OK。确保前景层被选择,而且增加一对可以拾取的物品在游戏中。我喜欢放置一些向西瓜或者别的什么东西。
  现在,我们需要把这些tile标记成可以拾取的,类似的,参照我们是如何把tile标志成可以碰撞的。选择Meta层,转换到Meta_tiles。现在,我们需要使这些tile可以拾取,点击”Layer\Move Layer Up“来确保你的meta层是在最顶层,并且保持绿色可见的。
  接下来,我们需要为tile增加属性,这样把它标记成可拾取的。点键点击Tilesets选项卡里的绿色的tile,然后点“Properties...”,再增加一个新的属性,命名为“Collectable”,值设置为“True”。
  保存地图,然后返回到Xcode。在HelloWorldScene.h中做如下修改:
//&Inside the HelloWorld class declaration
CCTMXLayer&*_
//&After the class declaration
@property (nonatomic, retain) CCTMXLayer&*
  同时,相应地修改HelloWorldScene.m:
//&Right after the implementation section
@synthesize foreground&=&_
//&In dealloc
self.foreground&=&
//&In init, right after loading background
self.foreground&=&[_tileMap layerNamed:@&Foreground&];
//&Add to setPlayerPosition, right after the if clause with the return in it
NSString&*collectable&=&[properties valueForKey:@&Collectable&];
if&(collectable&&&&[collectable compare:@&True&]&==&NSOrderedSame)
[_meta removeTileAt:tileCoord];
[_foreground removeTileAt:tileCoord];
  这里是一个常用的方法,用来保存前景层的句柄。不同之处在于,我们测试玩家正朝之移动的tile是否含有“Collectable”属性。如果有,我们就使用removeTileAt方法来把tile从mata层和前景层中移除掉。编译并运行工程,现在你的忍者可以尝尝西瓜的滋味啦!
创建一个计分器
  我们忍者非常高兴地吃西瓜啦,但是,作为一个游戏玩家,我们想知道自己到底吃了多少个西瓜。你懂的,我们并不想让他吃得太胖。
  通常的做法是,我们在层上面添加一个label。但是,等一下:我们在不停地移动这个层,那样的话,label就会看不到了,怎么办?
  这是一个非常好的机会,如果在一个场景中使用多个层--这正是我们现在面临的难题。我们将保留HelloWorld层,但是,我们会再增加一个HelloWorldHud层来显示我们的label。(Hud意味着Heads up display,大家可以google一下,游戏中常用的技术)
  当然,这两个层之间需要一种方式联系起来--Hud层应该知道什么时候忍者吃了一个西瓜。有许许多多的方式可以使2个不同的层相互通信,但是,我只介绍最简单的。我们在HelloWorld层里面保存一个HelloWorldHud层的句柄,这样的话,当忍者吃了一个西瓜就可以调用Hud层的一个方法来进行通知。
  因此,在HelloWorldScene.h里面增加下面的代码:
//&Before HelloWorld class declaration
@interface HelloWorldHud : CCLayer
-&(void)numCollectedChanged:(int)numC
//&Inside HelloWorld class declaration
HelloWorldHud&*_
//&After the class declaration
@property (nonatomic, assign)&int&numC
@property (nonatomic, retain) HelloWorldHud&*
  同样的,修改HelloWorldScene.m文件:
//&At top of file
@implementation HelloWorldHud
-(id) init
if&((self&=&[super init])) {
CGSize winSize&=&[[CCDirector sharedDirector] winSize];
label&=&[CCLabel labelWithString:@&0&&dimensions:CGSizeMake(50,&20)
alignment:UITextAlignmentRight fontName:@&Verdana-Bold&&
fontSize:18.0];
label.color&=&ccc3(0,0,0);
int&margin&=10;
label.position&=&ccp(winSize.width&-&(label.contentSize.width/2)&
-&margin, label.contentSize.height/2+&margin);
[self addChild:label];
-&(void)numCollectedChanged:(int)numCollected
[label setString:[NSString stringWithFormat:@&%d&,
numCollected]];
//&Right after the HelloWorld implementation section
@synthesize numCollected&=&_numC
@synthesize hud&=&_
//&In dealloc
self.hud&=&
//&Add to the +(id) scene method, right before the return
HelloWorldHud&*hud&=&[HelloWorldHud node];&
[scene addChild: hud];
layer.hud&=&
//&Add inside setPlayerPosition, in the case where a tile is collectable
self.numCollected++;
[_hud numCollectedChanged:_numCollected];
  一切很明了。我们的第二个层从CCLayer派生,只是在它的右下角加了一个label。我们修改scene把第二个层也添加进去,然后传递一个Hud类的引用给HelloWorld层。然后修改HelloWorldLayer层,当计数器改变的时候,就调用Hud类的方法,这样就可以相应地更新Hud类了。
  编译并运行,如果一切ok,你将会在屏幕右下角看到统计忍者吃西瓜的Label。
来点音效和音乐
  如果没有很cool的音效和背景音乐的话,这就不能算作是一个完整的游戏教程了。
  增加音效和音乐非常简单,只需在HelloWolrdScene.m作如下修改:
//&At top of file
#import&&SimpleAudioEngine.h&
//&At top of init for HelloWorld layer
[[SimpleAudioEngine sharedEngine] preloadEffect:@&pickup.caf&];
[[SimpleAudioEngine sharedEngine] preloadEffect:@&hit.caf&];
[[SimpleAudioEngine sharedEngine] preloadEffect:@&move.caf&];
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@&TileMap.caf&];
//&In case for collidable tile
[[SimpleAudioEngine sharedEngine] playEffect:@&hit.caf&];
//&In case of collectable tile
[[SimpleAudioEngine sharedEngine] playEffect:@&pickup.caf&];
//&Right before setting player position
[[SimpleAudioEngine sharedEngine] playEffect:@&move.caf&];
现在,我们的忍者可以开怀大吃了!
何去何从?
  这个系列的教程,就此完结了。距离上次翻译时间长了点。通过这个教程的学习,你对cocos2d里面的tiled map的使用,应该有一个非常好的理解了。这里有这个教程的
  接下来,我会接着翻译下一篇,是原作者的一个朋友写的,这个系列教程的终结版:
  如果你看了这个教程,有什么好的意见或建议,可以自由发言,谢谢!
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:977216次
积分:7687
积分:7687
排名:第2618名
原创:49篇
转载:304篇
评论:51条
(2)(5)(1)(13)(12)(7)(34)(13)(19)(6)(7)(6)(22)(11)(12)(22)(4)(13)(31)(24)(40)(2)(2)(2)(9)(4)(7)(3)(3)(5)(8)(4)

我要回帖

更多关于 tiledmap 资源 的文章

 

随机推荐