在游戏开发过程中,我们会遇到超过屏幕大小的地图,例如即时战略游戏,使得玩家可以在地图中滚动游戏画面。这类游戏通常会有丰富的背景元素,如果直接使用背景图切换的方式,需要为每个不同的场景准备一张背景图,而且每个背景图都不小,这样会造成资源浪费。瓦片地图就是为了解决这问题而产生的。一张大的世界地图或者背景图可以由几种地形来表示,每种地形对应一张小的图片,我们称这些小的地形图片为瓦片。把这些瓦片拼接在一起,一个完整的地图就组合出来了,这就是瓦片地图的原理。
参考
Tiled Map Editor 使用说明
Cocos2d-x 3.x基础学习:瓦片地图TiledMap
cocos2d-x中讲解TileMap地图编辑器的高级用法(一)
cocos2d-x中讲解TileMap地图编辑器的高级用法(二)
cocos2d-x中讲解TileMap地图编辑器的高级用法(三)
cocos2d-x中讲解TileMap地图编辑器的高级用法(对象层部分)
Tiled Map Editor Keyboard Shortcuts
官方文档
Tiled地图编辑器 Tiled Map Editor 的使用(一)基础功能+地形功能
Egret + TiledMap 快速上手
一、Tiled Map Editor简介
Tiled Map Editor是一款开源的地图编辑器,使用qt开发,因此可以跨平台,而且因为开源,所以大家还可以根据自己的需求进行加工和修改,这一点很重要。这里为刚接触游戏开发的同学插一句,为什么要开发地图编辑器呢,我们就用整张图做地图不就好了吗?这里简单回答一下,好处有两个:第一个是极大的减少用图的面积,这样就减少了在运行时系统占用的内存,具体原理问你们的boss或者度娘。第二个好处是可以通个打散的地图方便在格子中做很多事件,方便判断,比如做地图行走障碍判断,做触发事件判断。
打开官方首页(http://www.mapeditor.org/)后,直接点击DownLoad at itch.io
按钮进入下载链接(https://thorbjorn.itch.io/tiled)。如果官网改版,也可以直接从下载页http://www.mapeditor.org/download.html找到下载链接。打开下载会弹出赞助该软件的付费页面,如果不想付费,可以直接点击 No thanks, just take me to the downloads,会带你进入一个免费下载的链接。
二、Tiled Map Editor基本操作
1.新建地图
编辑器地图方向可以选择 “正常”或者“45度”两种,这个是很多其他编辑器没有的功能,大部分的编辑器都只支持单一方向的地图编辑,所以这也是我选择TileMap这款编辑器来开发的原因。
2.新建图块
点击浏览按钮,可以选samples中自带的tmw_desert_spacing.png。这里块的宽高就是32,然后解释一下边距和间距:
Margin就是当前的tile计算自身的像素的时候,它需要减去多少个像素(宽度和高度都包含在内)。(类比word、css的margin)
Spacing 就是相邻两个tile之间的间隔(同时考虑宽度和高度)(类比word、css的spacing)
如果你看看 tmw_desert_spacing.png,你将会看见每一个tile都有一个像素的空白边界围绕着,这意味着我们需要把margin和spacing设置为1。
3.常见工具按钮
这一排就是工具按钮,一般做地图的时候用前3个按钮
第一个是图章,单个刷,或者一个矩形的图块刷用这个工具
第二个是填充,
第三个是橡皮擦
大家试一下就知道用法了,记住,在图块层上的时候可以用鼠标一次框选一个矩形的图块哦,然后用第一个图章刷就很方便快速了。
TIPS:选中图块,按键盘“X”快捷键可以实现图块原地水平翻转,“Y”是垂直翻转,“Z”键可以循环90度翻转。非常实用。
更多指令,可以参考Tiled Map Editor Keyboard Shortcuts
4.左下角为对齐点
如果有以前用过地图编辑器的同学肯定清楚,一般的地图编辑器设定了地图的块大小的话,那么图片的块切割大小也就必须是和地图单块的大小一致的。但是我们的TileMap这款编辑器可以分开设置,例如地图块大小设置3232,图片块大小我可以设置成5264,或者其他6431都可以,等你设置好了,在地图块填充的时候就会发现,TileMap会自动以左下角为对齐点。比如我把一个图片切成6064的图片效果如下
看见了吗,深色部分表示我放置的点,那么超过的部分就自动向上和向右延伸了,所以我们会看见在cocos2d-x的TileMaps资源下面会有这样的图存在
5.参照tmx格式理解图层和对象层
使用CSV保存tmx后缀格式后,用文本编辑器打开可以看到如下内容
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" tiledversion="2018.04.18" orientation="orthogonal"
renderorder="right-down" width="30" height="10" tilewidth="32"
tileheight="32" infinite="0" nextobjectid="13">
<tileset firstgid="1" name="newDesert" tilewidth="32" tileheight="32"
spacing="1" margin="1" tilecount="48" columns="8">
<image source="../../tiled-windows-64bit-snapshot/examples
/tmw_desert_spacing.png" width="265" height="199"/>
<tile id="29">
<properties>
<property name="isCanPass" type="bool" value="true"/>
<property name="tileType" type="int" value="1"/>
</properties>
</tile>
<tile id="31">
<animation>
<frame tileid="30" duration="1000"/>
<frame tileid="31" duration="1000"/>
<frame tileid="38" duration="1000"/>
</animation>
</tile>
<tile id="39">
<properties>
<property name="isCanPass" type="bool" value="false"/>
</properties>
</tile>
</tileset>
<tileset firstgid="49" name="Tile01" tilewidth="32" tileheight="32"
tilecount="560" columns="20">
<image source="../../tiled-windows-64bit-snapshot/examples
/Tile01.PNG" width="640" height="896"/>
</tileset>
<layer name="块层 1" width="30" height="10">
<properties>
<property name="layer" value="layaAir"/>
<property name="testBool" type="bool" value="true"/>
</properties>
<data encoding="csv">
40,30,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40,30,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40,30,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40,30,40,40,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40,30,30,30,32,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40,40,40,40,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup name="SpriteLayer">
<properties>
<property name="pName" type="bool" value="true"/>
</properties>
<object id="10" name="xName" x="66" y="58" width="119" height="114"/>
</objectgroup>
</map>
第一部分是两个tileset,记录了素材图块切割属性。因为要确保ID唯一,所以使用firstgid来标注这个图块左上角起始编号,如Tile00图块,它左上角第一个图块编号就是49。因为它前面有个newDesert图块是8*6=48,已经占用了48个ID。
在newDesert图块中,还定义了一个动画和两个自定义属性。其中针对id=29的图块,isCanPass=true,而id为39的isCanPass=false。
这里有点奇怪,如果左上角的ID=1的话,这个格子应该是30呀,可见左上角的ID在图块内部是从0开始的。同样,动画中标记的素材ID也是从0开始的
第二部分是layer
<layer name="块层 1" width="30" height="10">
<properties>
<property name="layer" value="layaAir"/>
<property name="testBool" type="bool" value="true"/>
</properties>
可以看到自定义属性的存储方式。至于图块则用CSV格式来记录了里面的数据,0代表没有,1代表tile01.png的左上角第一个图块,2代表tile01.png左上角左数第二个图块。
tiled支持两类层--tile层(就是我们目前使用的层),还有对象层。对象层一般用来添加除背景以外的游戏元素-道具、障碍物等。比如,你可能想制作一个区域,在那里怪物将会跳出来,或者是一个区域,只要进入就会死掉。对象组中的对象在TMX文件中以键值对形式存在,因此可以直接在TMX文件中对他进行修改。对象层具体用法参考cocos2d-x中讲解TileMap地图编辑器的高级用法(对象层部分)
<objectgroup name="SpriteLayer">
<properties>
<property name="pName" type="bool" value="true"/>
</properties>
<object id="10" name="xName" x="370" y="66" width="119" height="114"/>
</objectgroup>
可以看出,对象层不再以layer作为标签名,而是以objectgroup作为标签名。保存自定义属性的方式仍然和tiled层一样,而保存的对象则是以object作为标签来存储。
以下例子是在cocos中取出对象层的代码,参考Tiledmap基本使用教程
//创建tiled地图,刚才创建的工程名字就是Text6.
auto m_ptmap = TMXTiledMap::create("Test6.tmx");
//获取到对象层,就是刚才创建的SpriteLayer对象层!
auto m_ptobjectGroup = m_ptmap->getObjectGroup("SpriteLayer");
//将该对象层的对象全部取出来。
auto m_vecobject = m_ptobjectGroup->getObjects();
//这里可以测试下对象的个数,刚才的例子我们只画了一个name
log("对象个数 %d````", m_vecobject.size());
//这里遍历所有的对象来做个测试,其实就只有一个
for (auto it = m_vecobject.begin(); it != m_vecobject.end(); it++)
{
//将取出来的对象转为ValueMap类型,接下来大家都懂了吧。
ValueMap map = it->asValueMap();
//取出该对象的名字转为Cstring类型。
log("%s",map.at("name").asCString();)
//这里大家可以看到输出为“name”。
}
再总结一下图层,对象层,图片层区别
图层:用于分隔不同作用的地图元素以方便管理和实现层叠显示。举例跑酷的场景中可以将地面、背景建筑、碰撞物体等分层放置,对于背景只是用来增加画面效果不会用于判断碰撞等事件,墙壁等瓦片图如果不能充满整个图块就会造成颜色不协调(同一个图块位置无法放置两种不同的瓦片图),所以层的出现解决了这个棘手的问题,保证了背景可以存在上面又能用墙壁等瓦片图遮挡显示一部分图片。
图层主要放置不会改变的图片,如地面或墙壁等(当然游戏中也会有会塌陷的地面)
对象层:主要用于放置NPC、金币、主角、宝箱等,该类特点是经常会移动、变换形态、显示或隐藏等。另外对于我们自定义的一些选框、路径等也可以放在此层中
图像图层:字面意思用于放置整张的图片。属性框中可以选择使用的图片文件、位置、RGB透明度等,实际使用中很少用到,而且cocos论坛中有使用者提出使用这个后会导致地图解析出错。
6.地形
参考Tiled地图编辑器中使用地形,这篇博客实际上是翻译了官方的英文帮助,另外也参考了Tiled地图编辑器 Tiled Map Editor 的使用(一)基础功能+地形功能
载入图块后,常规的操作是选右边的图块,然后到坐标地图中画图,或者是先选沙地图块,然后选择工具栏中的油漆桶填充整个地图。当你长时间绘制地图时候就会觉得麻烦了,边角位置都要重新选择一次图块来绘制,那么有没有办法把地图变成根据我们的绘制自动选择边界图片呢,后面请看地形。
个人理解,地形这个功能,就是针对整个图块进行分类,把不同的地形图块给标记出来。至于编辑器如何根据这个标记生成绘制边界,暂时还没有想明白。
首先,如果是在tmx文件中,可以找到需要标记的图块,点击Edit tileset,进入相应的tsx文件。当然也可以直接打开这个tsx文件。
通过主菜单->视图->视图和工具栏,打开地形窗口。可以使用+号来新建地形了。
注意红圈中标注的半圆,可以很方便地标注一些圆形区域。当然点击擦除地形时,同样也是这样的半圆进行消除。
以desert.tsx为例,标注了四种类型。即desert沙漠,brick青砖,cobblestone鹅卵石,dirt泥土。
和brick相同,把cobblestone和dirt标注后,剩余的就全是desert了。
从图块窗口切换到地形窗口,即tmx文件中。你会见到4种地形。点击沙地开始画,你会立即发现并没有什么特别的事情发生。这是因为此时还没有其他瓦片在地图上,所以地形工具不知道如何提供帮助(因为我们图块种没有与“空”地形的过渡)。既然这样,那么此时我们最好先把整个地图用沙地填满。先暂时切回“图块”窗口,选择沙地瓦片然后使用“填充”工具。我们切回地形窗口,使用地形刷来画一些地形。现在你可以看到效果啦!
三、素材资源下载
1.爱给免费素材
2.https://opengameart.org/
开源游戏素材网站,内容很多也很杂,需要自己搜索出适用的素材。其中并不是所有素材都可以商用的,要仔细看每个素材的共享条款。
3.http://www.6m5m.com/
4.http://kenney.nl/assets
免费的游戏素材网站,素材包风格统一,画风走卡通路线,适合用来制作各种小游戏。而且这些素材可以免费试用,商用也可以。