一、Cocos Creator 3.8.x 解析 Tiled 图层的核心原理
Cocos Creator 3.8.x 解析 Tiled 图层的本质是:
- 读取
.tmx/.tsx的 XML/JSON 结构(Tiled 导出格式),解析其中的图层元数据(类型、尺寸、属性); - 将解析后的数据映射到 Cocos 内置的
TileMap/TileLayer/ObjectLayer等类的实例; - 基于渲染管线将瓦片/图像/对象渲染到场景中,同时保留 Tiled 定义的层级、属性、变换等信息。
核心解析流程:
Tiled 导出文件 (.tmx)
↓ 解析 XML/JSON 结构
提取图层节点(<layer>/<objectgroup>/<imagelayer>/<group>)
↓ 映射到 Cocos 数据结构
TileLayer / ObjectLayer / ImageLayer / GroupLayer 实例
↓ 渲染/交互
Cocos 场景中可视化渲染 + 代码可操作
二、各图层解析原理 + 示例代码 + 操作示意图
1. 瓦片图层(Tile Layer)
解析原理
- Tiled 中
<layer>标签存储瓦片图层数据,包含data节点(瓦片ID数组,支持Base64/CSV编码); - Cocos 解析后将瓦片ID映射到瓦片集(Tileset)的纹理坐标,逐瓦片渲染;
- 支持瓦片的翻转/旋转(Tiled 中通过瓦片ID的高位标记,Cocos 解析后处理纹理UV)。
操作示意图
┌─────────────────────────┐
│ Tiled 瓦片图层编辑 │ ┌─────────────────────────┐
│ 1. 图层名:GroundLayer │ │ Cocos 解析后 │
│ 2. 瓦片坐标(5,5) ID=100 │──────>│ 1. getLayer('GroundLayer')│
│ 3. 瓦片翻转(水平) │ │ 2. getTileGIDAt(5,5) = 100│
└─────────────────────────┘ │ 3. 自动渲染翻转后的瓦片 │
└─────────────────────────┘
示例代码
typescript
import { _decorator, Component, Node, TileMap, TiledTile, Vec2 } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('TileLayerDemo')
export class TileLayerDemo extends Component {
@property(TileMap)
tileMap: TileMap = null!;
onLoad() {
// 1. 解析瓦片图层
const tileLayer = this.tileMap.getLayer("GroundLayer");
if (!tileLayer) {
console.error("瓦片图层不存在");
return;
}
// 2. 读取瓦片基础信息
const mapSize = this.tileMap.getMapSize(); // 地图总瓦片数
const tileSize = this.tileMap.getTileSize(); // 单瓦片像素尺寸
console.log("地图瓦片尺寸:", mapSize.width, "x", mapSize.height);
console.log("单瓦片像素:", tileSize.width, "x", tileSize.height);
// 3. 读取指定坐标瓦片(Tiled坐标:x向右,y向下)
const tileGID = tileLayer.getTileGIDAt(5, 5); // 获取瓦片ID
console.log("(5,5) 瓦片ID:", tileGID);
// 4. 读取瓦片翻转/旋转状态(Tiled的翻转标记)
const tileInfo = tileLayer.getTileInfoAt(5, 5);
if (tileInfo) {
console.log("瓦片翻转:", {
flipX: tileInfo.flipX, // 水平翻转
flipY: tileInfo.flipY, // 垂直翻转
rotate: tileInfo.rotate // 旋转(90/180/270)
});
}
// 5. 修改瓦片(动态替换)
tileLayer.setTileGIDAt(101, 5, 5); // 将(5,5)瓦片替换为ID=101的瓦片
// 6. 清空瓦片
tileLayer.removeTileAt(5, 5);
}
}
2. 对象图层(Object Layer)
解析原理
- Tiled 中
<objectgroup>标签存储对象图层,每个<object>节点对应一个对象(矩形/椭圆/多边形/点/文本); - Cocos 解析后将对象数据封装到
ObjectLayer类,保留对象的位置、尺寸、自定义属性、类型等; - 无原生渲染(仅数据),需开发者根据对象类型创建 Cocos 节点/碰撞体/渲染组件。
操作示意图
┌─────────────────────────┐
│ Tiled 对象图层编辑 │ ┌─────────────────────────┐
│ 1. 图层名:Collision │ │ Cocos 解析后 │
│ 2. 矩形对象:Obstacle1 │──────>│ 1. getObjectLayer('Collision') │
│ 3. 属性:isObstacle=true│ │ 2. 遍历objects数组 │
│ 4. 尺寸:100x50 │ │ 3. 创建BoxCollider2D │
└─────────────────────────┘ └─────────────────────────┘
示例代码
typescript
import { _decorator, Component, Node, TileMap, BoxCollider2D, Vec2, PolygonCollider2D } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ObjectLayerDemo')
export class ObjectLayerDemo extends Component {
@property(TileMap)
tileMap: TileMap = null!;
onLoad() {
// 1. 解析对象图层
const objLayer = this.tileMap.getObjectLayer("CollisionLayer");
if (!objLayer) return;
// 2. 遍历所有对象
objLayer.objects.forEach((obj, index) => {
console.log(`===== 对象 ${index + 1} =====`);
console.log("名称:", obj.name);
console.log("类型:", obj.type); // Tiled中自定义的对象类型
console.log("位置:", obj.x, obj.y); // 世界坐标
console.log("尺寸:", obj.width, obj.height); // 仅矩形/椭圆有效
console.log("自定义属性:", obj.properties); // Tiled中添加的键值对
// 3. 根据对象类型创建碰撞体
switch (obj.shape) {
case 'rect': // 矩形对象
const rectCollider = this.node.addComponent(BoxCollider2D);
rectCollider.offset = new Vec2(obj.x, obj.y);
rectCollider.size = new Vec2(obj.width, obj.height);
rectCollider.tag = obj.properties.tag || 0;
break;
case 'polygon': // 多边形对象
const polyCollider = this.node.addComponent(PolygonCollider2D);
polyCollider.points = obj.polygon.map(p => new Vec2(p.x, p.y));
break;
case 'point': // 点对象(如出生点)
console.log("出生点位置:", obj.x, obj.y);
// 可创建空节点标记位置
const spawnNode = new Node("SpawnPoint");
spawnNode.setPosition(obj.x, obj.y);
this.node.addChild(spawnNode);
break;
}
});
}
}
3. 图像图层(Image Layer)
解析原理
- Tiled 中
<imagelayer>标签存储图像图层,包含<image>子节点(指定图片路径、偏移、透明度); - Cocos 解析后自动创建
Sprite组件,关联图片资源,保留 Tiled 中设置的偏移、缩放、透明度; - 图像图层本质是"整图渲染",区别于瓦片图层的"逐瓦片拼接"。
操作示意图
┌─────────────────────────┐
│ Tiled 图像图层编辑 │ ┌─────────────────────────┐
│ 1. 图层名:Background │ │ Cocos 解析后 │
│ 2. 图片:bg.png │──────>│ 1. 自动创建Sprite节点 │
│ 3. 偏移:x=10, y=20 │ │ 2. 位置=偏移+地图原点 │
│ 4. 透明度:80% │ │ 3. opacity=0.8 │
└─────────────────────────┘ └─────────────────────────┘
示例代码
typescript
import { _decorator, Component, Node, TileMap, Sprite, Vec2, UITransform } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ImageLayerDemo')
export class ImageLayerDemo extends Component {
@property(TileMap)
tileMap: TileMap = null!;
onLoad() {
// 1. 解析图像图层(Cocos将图像图层作为子节点挂载到TileMap节点下)
const imageLayerNode = this.tileMap.node.getChildByName("BackgroundLayer");
if (!imageLayerNode) return;
// 2. 获取Sprite组件(Cocos自动创建)
const sprite = imageLayerNode.getComponent(Sprite);
console.log("图像图层图片:", sprite.spriteFrame?.name);
// 3. 读取/修改图像图层属性(对应Tiled中的设置)
const uiTransform = imageLayerNode.getComponent(UITransform);
// 偏移(对应Tiled的offsetx/offsety)
console.log("图像偏移:", imageLayerNode.position);
// 透明度(对应Tiled的opacity)
console.log("原始透明度:", imageLayerNode.opacity);
imageLayerNode.opacity = 180; // 修改透明度(0-255)
// 4. 调整图像缩放(模拟Tiled的scale)
imageLayerNode.setScale(new Vec2(1.2, 1.2));
// 5. 隐藏/显示图像图层
imageLayerNode.active = false;
}
}
4. 组图层(Group Layer)
解析原理
- Tiled 中
<group>标签存储组图层,包含多个子图层(瓦片/对象/图像图层); - Cocos 解析后将组图层映射为空节点,子图层作为该节点的子节点,保留层级结构;
- 可通过节点操作控制整个组的可见性、透明度、位置。
操作示意图
┌─────────────────────────┐
│ Tiled 组图层编辑 │ ┌─────────────────────────┐
│ 1. 组名:Level1 │ │ Cocos 解析后 │
│ ├─ GroundLayer(瓦片) │──────>│ 1. Level1(空节点) │
│ └─ Collision(对象) │ │ ├─ GroundLayer │
└─────────────────────────┘ │ └─ Collision │
└─────────────────────────┘
示例代码
typescript
import { _decorator, Component, Node, TileMap } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('GroupLayerDemo')
export class GroupLayerDemo extends Component {
@property(TileMap)
tileMap: TileMap = null!;
onLoad() {
// 1. 解析组图层(Cocos将组图层作为TileMap节点的子节点)
const groupNode = this.tileMap.node.getChildByName("Level1Group");
if (!groupNode) return;
// 2. 控制整个组的可见性
groupNode.active = false; // 隐藏整个Level1组
// 3. 遍历组内子图层
groupNode.children.forEach(child => {
console.log("组内图层:", child.name);
// 示例:禁用组内所有碰撞图层
if (child.name.includes("Collision")) {
child.active = false;
}
});
// 4. 修改组的整体偏移
groupNode.setPosition(50, 50);
// 5. 获取组内指定子图层
const groundLayer = this.tileMap.getLayer("GroundLayer"); // 跨组也可直接通过名称获取
if (groundLayer) {
console.log("组内瓦片图层:", groundLayer.name);
}
}
}
三、关键补充说明
- 坐标体系对齐 :
Tiled 的坐标原点在左上角,y轴向下;Cocos 默认坐标原点在左下角,y轴向上。Cocos 会自动转换 Tiled 坐标,无需手动调整。 - 数据编码格式 :
Tiled 导出.tmx时建议选择 CSV 编码(而非Base64压缩),便于调试;Cocos 3.8.x 兼容两种编码,但CSV更易读取原始瓦片ID。 - 示意图可视化建议 :
- 在 Tiled 中截图图层编辑界面,标注关键属性(图层名、瓦片ID、对象属性);
- 在 Cocos 编辑器中截图层级管理器,标注解析后的节点结构,与 Tiled 图层一一对应。
四、调试技巧
- 打印完整解析数据:
typescript
// 打印TileMap所有图层信息
console.log("所有图层:", this.tileMap.getAllLayers());
// 打印对象图层原始数据
console.log("对象图层原始数据:", JSON.stringify(this.tileMap.getObjectLayer("CollisionLayer")?.objects));
- 在 Cocos 编辑器中选中 TileMap 节点,在属性检查器中可直观查看解析后的图层列表、瓦片集关联状态。
以上代码可直接挂载到场景中的 TileMap 节点上运行,需提前在 Tiled 1.4.x 中创建对应类型的图层并导出 .tmx 文件,导入 Cocos 后关联到代码的 tileMap 属性即可。