大地图实现,由各部分对Tiled的支持开始。
前言
项目中需要用到“大”地图玩法,来实现一些GVE、GVG玩法,根据游戏类型及玩法体量,选择最合适的TileMap来实现。
但眼光要不仅于此,由TileMap开始,向其他游戏类型的技术方案进行拓展了解。
通过本篇文章,可以了解:
- Tiled地图编辑器的介绍
- 其他大地图方案技术
Tiled
Tiled是一个编辑2D游戏地图的编辑器,可以帮助开发游戏的内容。
优点
- 可快速制作关卡地图,策划可视化编辑,降低配置成本
- 支持多种压缩格式,支持多层级设置,完全可作为关卡编辑器使用
标准
可导出的格式
- [常用] TMX
- CSV
- GMX
- JSON
- JS
- LUA
压缩模式
- XML
- CSV
- BASE64
- 无
- GZIP
- ZLIB
- Z标准
支持类型
- 直90°
- 斜45°
- 斜45°交错
- 六边形
概念
坐标系(OpenGL坐标系原点在左下角,需要转换)
- 原点:左上角
- 单位:瓦片数量(非像素)
- x轴方向:自左向右
- y轴方向:自上向下
瓦片锚点
- 瓦片地图锚点默认为(0, 0),每个瓦片锚点默认为(0, 0),且可修改
遮挡关系
- 地图层之间,存在 ZOrder,ZOrder大的在上层
- 瓦片之间,渲染顺序为自左向右,自上向下
各元素
- 属性
- 所有的属性都是key-value键值对形式存储;除了指定的属性外还有自定义属性可灵活配置
- 类型
- 地图属性
- 图层属性
- 对象属性
- 自定义属性
- bool
- color
- float
- int
- string
- file
- 图层
- 图块层
- 规则图块拼接铺设
- 为了便于编辑,支持一些刷子工具
- 填充工具
- 图章刷
- 选择1块或多块图块绘制,
- 按住shift可以绘制一条线段
- 按住ctrl+shift可以绘制一个椭圆
- 地形刷
- 提供角落地形过度的编辑方式
- 支持图章刷的shift和ctrl+shift规则
- 王氏刷
- 类似于地形刷,但可以编辑边和角
- 填充
- 将相邻的同图块全部替换成指定图块
- 填充形状工具
- 选择一块区域填充图块
- 按住shift可以填充正方形和圆形
- 图章刷
- 选择工具(选择指定区域修改,不可修改其他区域)
- 矩形选择
- 自定义矩形区域
- 魔术棒
- 相连的同地块
- 同地块选择
- 地图内所有同地块
- 矩形选择
- 填充工具
- 对象层
- 自定义对象的放置,支持形状/图片
- 图像层
- 前景后景图的设置
- 组
- 管理
- 图块层
- 对象
- 在对象层可以放置对象,支持矩形、圆形、三角形、图片等等方式
- 可以对对象进行旋转、放缩、翻转、修改大小等等
- 可以在对象添加自定义属性,方便进行与游戏内逻辑关联
- 图块集
- 图块集是绘制图块层与对象的图片来源
- 对于图块层的图块集,指定宽高,来截取使用,还支持设置边界值
- 对于对象的图块集,每个图块都是自己一个完整的图片,方便整个绘制
- 一个图块层只能绑定一张图块集
- 图块集是绘制图块层与对象的图片来源
支持
Cocos2d
Cocos2d引擎对TileMap的支持
主要文件:
- CCTMXTiledMap.h & CCTMXTiledMap.cpp
- 主类,解析并绘制TileMap
- CCTMXLayer.h & CCTMXLayer.cpp
- TileMap图块层结构
- CCTMXObjectGroup.h & CCTMXObjectGroup.cpp
- TileMap对象层结构
- CCTMXXMLParser.h & CCTMXXMLParser.cpp
- 解析TileMap的工具类
- CCFastTMXTiledMap.h & CCFastTMXTiledMap.cpp
- v3.2新增方法,对应CCTMXTiledMap
- CCFastTMXLayer.h & CCFastTMXLayer.cpp
- v3.2新增方法,对应CCTMXLayer
引擎通过CCTMXXMLParser的相关方法解析地图,创建 TMXTiledMap 对象,该对象子节点都是 TMXLayer对象,对应TileMap的图块层,包含 TMXObjectGroup 对象数组,对应TileMap的对象层。
所创建出的地图,仅仅包含图块层的初始化与应用,并不会将对象创建出来,只是解析了数据进行存储。(使用图片对象,并不会在地图中创建出对象,依旧需要自己来获取对象层数据,进行创建)
创建流程
- 【外部调用】通过 TMXTiledMap:create / TMXTiledMap:createWithXML 方法,使用TMX格式或XML格式文件创建地图对象
- 【解析】通过SAXParser解析地图文件,生成TMXMapInfo对象
- 这一步是将地图数据解析成自己的数据结构
- 类型
- TMXTilesetInfo,图块集数据结构
- TMXLayerInfo,图块层数据结构
- TMXMapInfo,地图数据结构
- 【构建】通过解析的数据结构,构建地图对象
- 这一步是根据数据创建具体对象,包含加载图集,创建每个图片等
- 类型
- 简单的地图属性,直接赋值
- 对象层数据,直接赋值
- 图块层数据,需要配合图块集数据与地图数据,共同创建出TMXLayer对象(一个SpriteBatchNode对象)
重要枚举
1 | // 地图方向枚举 |
TMXTiledMap系列
TMXTiledMap负责解析并绘制TMX地图。
- 每个图块层都被解析并创建为TMXLayer对象(一个SpriteBatchNode子类,若层被设置为不可见则不会被解析创建),可以在运行期间通过层名或层级(从0开始)获取TMXLayer对象。
- 每个对象层都被解析并创建为TMXObjectGroup对象,可以在运行期间通过层名来获取TMXObjectGroup对象。
- 每个属性都被存储为key-value键值对,每个对象都提供获取属性的方法。
限制
- 每个图块层只支持一个图块集
- 不支持嵌入式图片
- 仅支持XML格式(不支持JSON格式)
TMXLayer代表TileMap的图块层对象
- 是SpriteBatchNode子类,默认情况下使用TextureAtlas渲染图块
- 如果在运行时修改图块,该图块会成为一个Sprite,否则不会创建Sprite对象
- 创建的Sprite可以支持旋转、放缩、移动等API
- 通过设置图块层不同属性来启用不同特性
- cc_vertexz,OpenGL深度测试
- cc_alpha_func,OpenGL透明度测试
FastTMXTiledMap系列
大部分与TMXTiledMap差不多,主要区别在于FastTMXTiledMap系列的图块层对象并非继承自SpriteBatchNode,而是继承自Node;
老版TMXTiledMap借助于SpriteBatchNode对同图集图片合批做绘制优化处理,新版FastTMXTiledMap重写绘制方法,使用PrimitiveCommand渲染指令,在绘制时根据相机可见性,规划矩形区域,只对矩形区域内的顶点进行批量上传,从而节省了绘制的顶点数。
性能上,Draw Call是一样的,但是FastTMXTiledMap GL Verts(顶点数)更少,绘制效率更高。
1 | void TMXLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flags) |
但是,在项目使用中,如果将地图挂载到3D相机上,会有裁剪问题,暂时未解决。
优化
通过Tiled编辑器,可以导出TMX格式文件或XML文件,引擎直接对它解析。
但依旧有一些不足
- 并非会解析所有字段
- 比如,对象旋转后的属性是无法解析出来的
- 对对象层数据只解析不处理
在实际使用时,为了性能优化与业务需求,在导出TMX文件,又通过python脚本,进行二次加工。
通过python脚本,主要处理:
- 修改GID,所用到的图片都放在一个图集中,然后修改映射关系
- 计算对象在引擎显示的屏幕坐标(空间换时间,这样就不需要在使用时计算了)
- 属性转移
- 有些属性 旋转、翻转 等,不会被引擎解析
- 将这些属性转为自定义属性,便于解析
还有一些想法,还未实施
- 分离图块层与对象层
- 原因:
- Tiled编辑器,可以导出lua格式文件
- cocos2d引擎解析对象层数据,但不绘制,浪费解析性能
- 方案:
- Tiled编辑器导出tmx文件,只包含图块层,给引擎解析与绘制
- Tiled编辑器导出lua文件,只包含对象层,给业务代码解析与绘制
- 原因:
Unity
之前Unity不支持使用Tiled,通过插件来支持
后来,Unity官方支持了 瓦片地图 相关功能
- Unity 2017.2 版中添加了瓦片地图
- Unity 2018.2 中添加了六边形瓦片地图 (Hexagonal Tilemap) 功能
- Unity 2018.3 中添加了等距瓦片地图 (Isometric Tilemap) 功能
- Unity 2020.1 2D Tilemap Editor 不再随 Editor 安装过程一起安装,而是必须从 Package Manager 下载
推荐教程:
Unity Tilemap模块全攻略
服务器
默认文件是tmx格式,tmx实际上就是xml格式文件,可以当成xml进行解析。
标签类型
- map,存储tilemap的主要信息,朝向、宽高、格子数及大小等
- tileset,存储tilemap的图片资源信息,图片资源ID(GID)的映射关系
- layer,图块层
- data,图块层内图块位置及GID对应信息,可以被压缩
- objectgroup,对象层
- ojbect,每个对象的属性信息键值对
- imagelayer,图像层
TMX样例
1 | <?xml version="1.0" encoding="UTF-8"?> |
Tiled编辑器也支持导出为json格式,方便服务器解析。
标签同xml的差不多,也就格式上会有些变化。
JSON样例
1 | { "compressionlevel":-1, |
拓展
主流大地形渲染
TileMap
利用一些小图片拼出一个大地图
优点
- 结构简单,方便优化
- 加载整个TileMap,图片都在一个图集中,可以批量绘制,地图加载压力轻
缺点
- 只能满足特定视距下LOD的细节程度
- 重复感很强,不容易做大结构和氛围
游戏
- 率土之滨
- 文明6移动版
多层纹理混合
利用一张Mask图的多通道,控制多张贴图进行纹理混合
优点
- 制作简单,性能压力小
缺点
- 可混合的通道及贴图数有限,难以做出丰富的效果
游戏
- 万国觉醒
Virtual Texture
通过 Indirection Map,将贴图载入Physical Texture。
优点
- 效果细节丰富
- 美术自由度高
- 内存和DrawCall可控
缺点
- 手机端效果不明确
游戏
- 一些端游
- 一些主机游戏
Texture Array
存储一个数组,每个元素是一张图
优点
- 减少bind次数
- 适合层与层之间的颜色混合
缺点
- 严格要求尺寸、格式
- OpenGL ES 3.0以上才支持
程序化工具选型
Substance
程序化贴图常用工具
可在一定程度上满足贴图需求,但无法生成模型、数据表等资源,需要第三方工具
Houdini
行业程序化流程常用工具,移动游戏上 吃鸡类游戏、《原神》等都有所使用。
特点
- 基于节点
- 非破坏式流程,快速迭代
- 操作属性,可将任意信息存储在几何中
- 定制化程度高,可以单靠编程完成整个流程
- 处理数据流,外部仅关心数据输入与输出
大地图技术
除了上面的渲染技术与工具,还有一些大地图数据处理上的一些技术。
比如:
- 精度问题处理
- 区域划分
- 节点中转
- 坐标转换
- LOD(level of detail)
- Streaming
- Caching
- AOI(Area Of Interest)
更详细内容,可跳转知乎:开放世界游戏中的大地图背后有哪些实现技术?
参考资料:
- Tiled文档(English)
- Tiled论坛
- cocos2dx - tmx地图分层移动处理
- Tiled2Unity
- SuperTiled2Unity
- Unity Tilemap模块全攻略
- 瓦片地图
- 像素填充率,纹理填充率,显存带宽
- 基于高度的纹理混合shader
- 浅谈Virtual Texture
- 开放世界游戏中的大地图背后有哪些实现技术?
- 天美F1引擎专家:如何利用PCG技术加速大世界地形生产?
- 揭秘《鸿图之下》的场景技术
- 技术分析 探讨大世界游戏的制作流程及技术——大场景制作技术概况篇
v1.5.2