Tiled结合Unity实现瓦片地图——Unity实战篇

本系列文章由Aimar_Johnny编写,欢迎转载,转载请标明出处,谢谢。

http://blog.csdn.net/lzhq1982/article/details/75425915


上文说道,Tiled2Unity可以方便的把Tiled编辑器做的地图文件导出到Unity中,这方面文章不少,可是这个地图文件我们在Unity中怎么用,这方面的介绍太少了,这篇是Unity实战篇,如果觉得对您有用,就请看完后点个赞吧。

1、Tiled Map Editor中的对象

这是Tiled编辑器中唯一值得我们关心的部分,因为只有这部分能参与编程,Tiled中的图层有三种,如下图


点击新建图层的时候会弹出上面三个图层,图块层和图片层是美术关心的,只是负责显示的部分,我们程序重点关心的是对象层,所以如果你想代码操纵某个图层,一定要定义成对象层。比如我会把所有的关卡点和建筑点设置成对象层,其他如地表啊,水面啊,路啊,花花草草啊什么的,都是图块层就好了。然后切换成对象显示,我们会看到那些设置成对象的瓦片列表,都在这里了,如果没有定义名称和类型,就是下面这个样子:


选择某个对象,左侧的属性是这个样子:


这有什么用啊,除了xy,宽高,毛用都没有啊,别着急,我们还什么都没干呢。

2、对象类型编辑器

上面都是默认的,我们要经过对象类型编辑器来编辑它们,拿到我们程序需要的变量,先找到对象类型编辑器:


选择后会弹出对象编辑器,如下图:


当然默认是什么都没有的,我这里已经加上了一些内容,先看左侧——类型,我们可以为对象设置类型,每个对象都该有个类型,相同类型的对象有着相同的属性,比如我这里定义了一个关卡类型Level,如果设置了类型的颜色,我们在编辑器中可以对该类型的对象着相同的颜色,可以区分对象类型吧,无关紧要。每个类型对应后面的属性,这个看你的需求,比如我的关卡需要记录id,需要记录4个临近关卡点的id,所以我定义了上面5个变量。每个属性有个默认值,我定义为0。

3、设置每个对象的自定义属性

回到主界面,选一个对象,然后在类型那行输入你刚设置的类型,见证奇迹的时刻到了,你会发现下面的自定义属性立刻出现了你在对象编辑器中设置的该类型对应的属性,如下图:


类型我输入Level,下面就出现了那5条属性,然后我可以自定义那些属性值,比如这里它的关卡号是37,相邻关卡点只有一个,是id为30的关卡点。大家可能看到了名称那里,那是自己手动加上的,上面每一条数据,未来代码都是可以访问到的,尤其是类型和自定义属性,是我们的重点。

4、Unity内置的自定义属性

    • unity:tag
    • unity:sortingLayerName
    • unity:sortingOrder
    • unity:layer (Layer is such an overloaded term. In Unity it means the “physics” layer.)

Tiled编辑器是支持几种与Unity相关的自定义属性的,如上面,比如你在Unity中设置好tag或layer或sortingLayerName,那在Tiled编辑器中设置相同的tag、layer或sortingLayerName,将来导出后,这些对象会自动设置成Unity对应的tag、layer、sortingLayerName,下面举个sortingLayerName的例子:

首先在Unity中的Tags & Layers中的Sorting Layers里加入一个Layer,设置为Background:如下图:


注意层的关系,我把Default层拖到Background下,这样Background背景层始终在最下面。然后在Tiled编辑器中的图块层和对象层我都加了unity:sortingLayerName,设置为Background,如下:


注意图块层也是可以加自定义属性的,这样导出后,我的图块层就被自动设置为Background了,由于我生成的角色会默认为Default层,这样永远保证角色会在地图上面显示,下图是导出后Unity中该图块自动加的图层:


下面是我加入角色后会在地图上方:


tag和layer也是这么设置使用,就不多介绍了。

5、导出时加载数据

在导入到Unity后,每个对象都携带了在Tiled编辑器中的属性,除了自定义数据,并作为TileObject脚本组件绑定到对象上:


对照本篇的3,你可以看到对应关系,所以我们可以在TileObject中获得一些基础属性。

但自定义数据怎么在代码中获取呢,首先我们看Tiled2Unity在Unity中导入的包,找到ICustomTiledImporter文件,路径如下:


我们看看里面的代码:

namespace Tiled2Unity
{
    public interface ICustomTiledImporter
    {
        // A game object within the prefab has some custom properites assigned through Tiled that are not consumed by Tiled2Unity
        // This callback gives customized importers a chance to react to such properites.
        void HandleCustomProperties(GameObject gameObject, IDictionary<string, string> customProperties);

        // Called just before the prefab is saved to the asset database
        // A last chance opporunity to modify it through script
        void CustomizePrefab(GameObject prefab);
    }
}

// Examples
/*
[Tiled2Unity.CustomTiledImporter]
class CustomImporterAddComponent : Tiled2Unity.ICustomTiledImporter
{
    public void HandleCustomProperties(UnityEngine.GameObject gameObject,
        IDictionary<string, string> props)
    {
        // Simply add a component to our GameObject
        if (props.ContainsKey("AddComp"))
        {
            gameObject.AddComponent(props["AddComp"]);
        }
    }


    public void CustomizePrefab(GameObject prefab)
    {
        // Do nothing
    }
}
*/
这个类是干吗的呢,就是负责导出我们自定义数据的加载类,人家很贴心的在注释里写了个例子,可供参考。其实就两个接口, HandleCustomProperties是我们处理自定义数据的地方,它传递两个参数,gameObject是每一个对象,props是自定义属性组成的字典。CustomizePrefab是我们对导出的地图prefab可以操作的地方,传递的prefab是我们的地图prefab。

我在工程目录下建个Editor文件夹,然后在其下新建个脚本:CustomImporter_StrategyTiles,内容如下:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Tiled2Unity;

[Tiled2Unity.CustomTiledImporter]
public class CustomImporter_StrategyTiles : Tiled2Unity.ICustomTiledImporter
{

    public void HandleCustomProperties(GameObject gameObject,
        IDictionary<string, string> customProperties)
    {
		TileObject obj = gameObject.GetComponent<TileObject> ();
		if (obj != null)
        {
            // Add the terrain tile game object
			if (obj.TmxType == "Level") {
				BoxCollider2D box = gameObject.AddComponent<BoxCollider2D> ();
				box.offset = new Vector2 (2, 1.3f);
				box.size = new Vector2 (2, 1);
				TileData tile = gameObject.AddComponent<TileData>();
				tile.Id = int.Parse (customProperties ["Object_ID"]);

				for (int i = 0; i < 4; ++i) {
					string strId = "Neighbor_ID_" + (i + 1);
					if (customProperties.ContainsKey (strId)) {
						tile.neighbor[i] = int.Parse (customProperties [strId]);
					}
				}

			}     
        }
    }

    public void CustomizePrefab(GameObject prefab)
    {
        // Do nothing
    }
}
上面的代码就是我继承ICustomTiledImporter实现获得自定义属性的地方,代码很短,首先获得该对象 TileObject基础属性,然后判断其类型是否Level,是的话我做了两件事,一是加BoxCollider2D碰撞体,一是加脚本TileData储存自定义数据并绑定到对象上,自定义数据是字典,用Tiled编辑器中的key获得value就行了,然后保存在 TileData的数据中,我的 TileData特简单:

public class TileData : MonoBehaviour {

	public int Id = 0;
	public int[] neighbor = new int[4];
}

好了,这样所有的数据你都得到了,怎么编程就是你自己的事情了,注意这段代码是在Tiled2Unity导出地图到Unity时调用的,所有数据在导入时就已经都加载好了,跟游戏运行没关系。

嗯,再多说一点,除了上述数据,我们还可以获得整张地图的数据,点击我们的地图prefab,你可以看到它绑了个TiledMap脚本:

我们从中可以看到层数NumLayers,横向格子数NumTilesWide,纵向格子数NumTilesHigh,每个格子宽TileWidth,高TileHeight,导出缩放值ExportScale,地图像素宽MapWidthInPixels,高MapHeightInPixels。

如果读者还记得我设计的最小单位是32的话,那按这个最小单位我其实要用MapWidthInPixels和MapHeightInPixels计算我横向和纵向需要多少个最小单位,而不是直接用上面的NumTilesWide和NumTilesHigh,那对我没用。

就说这么多吧,上面那些只是基础,要跟地图做交互还要考虑摄像机的Size,位置,防止地图边缘漏出来,尤其是地图可以拖动缩放的情况。


  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值