Unity提供全套的Tile工具来编辑2D地图。使用Tile编辑地图,可以极大地减少内存的占用。美术人员只需要小格式地图,并且保证可以相互拼接接口,策划人员最终将这些小格子元素编辑在一起。灵活的拼接可以生成很多不同的2D地图。使用Tile之前请确保安装Tilemap Editor包

创建Tile

创建tile之前,需要确认Tile的大小,一般是32和64。

首先要将需要使用的tile按照大小设置Pixel Per Unit,然后按照Multiple Sprite Mode切分,还要把Filter Mode改为Point,把Compression设为None

Tile编辑

在Hierarchy视图中创建TileMap游戏对象。选择Create——2D Object——TileMap命令。

此时场景中将出现一个Grid对象并且它下面套着TileMap对象。Grid就是Tile的画布,它可以设置画布每个单元的大小。由于前面Pixels Per Unit已经设置成32,所以这里默认填1就好了。Cell GAP可以设置每个单元之间的间距,一般都设置成0就好。最后的Cell Swizzle用于设置Grid布局的朝向,而XYZ表示斜角为45°的2D游戏?

Grid对象下面就是TIlemap了。它可以设置动画帧率(tilemap的动画需要配合tilemap extra package,这在Unity2020中是一个preview版本的package)、锚点和朝向等信息。Tilemap Renderer组件和Sprite Renderer很像,可以设置排序和遮罩等。

Tilemap和Tilemap Renderer

Tile Palette

接着,需要将可编辑的Sprite汇总在Tile Palette面板中,在Hierarchy窗口点击Grid,在Scene窗口直接点击“Open Tile Palette”。在Tile Palette窗口中,点击

Create New Palette可以创建多个调色板。根据不同风格需要创建多个调色板。

最后将需要编辑的sprite资源直接拖入相应的Palette就可以自动生成Tile了。

同一Grid中可能会有多个Tilemap,例如背景层和前景层,在Active Tilemap下拉框中选择当前grid下的对应tilemap,方便互相切换编辑

Palette也是可以编辑的,点击edit进入调色板编辑模式,修改后按Ctrl S保存退出Palette编辑

Tile Palette

编辑Tile

Tile Palette工具栏中,工具从左到右一次如下

  • 点选工具(S):可以选择某一个Tile。
  • 移动工具(M):当使用点选工具选择一个Tile时,可以使用此工具移动Tile的位置。
  • 画笔工具(B):选择一个TIle,在Scene视图中刷
  • 区域工具(U):按住左键框选刷多个区域
  • 吸图工具(I):吸取Scene中某个或某一些Tile的图,然后编辑
  • 橡皮工具(D):删除Scene中不需要的Tile。
  • 批量填充工具(G):大规模填充Tile。

Palette工具

多Tile编辑与排序

在普通的2D游戏场景中,至少需要2个Tile层,前景层和背景层。比如一棵树,上半部分是树叶(前景层),下半部分是树干(背景层),这样人物在树附近上下移动的时候,走到树下应该自己要挡住树干,走到树上面应该被树叶挡住自己。

在Tile Palette面板中切换当前需要编辑的Tilemap时,可以在Scene视图选择Focus On Tilemap,这样就可以突出显示正在编辑的Tilemap了。

Focus On

拓展Tile Palette

Unity提供了Tile Palette的拓展编辑功能,可以重写画笔的任意行为。

新添加的Tile 画笔要继承GridBrush,如果画笔需要复用,还支持可以添加配置参数的画笔。

首先在Editor文件夹下,新建CustomBrush脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using UnityEngine;
using UnityEditor;
using System;
using UnityEditor.Tilemaps;

[CustomGridBrush(false,true,false,"Custom Brush")]
public class CustomBrush : GridBrush
{
//序列化数据
public new string name;
public override void Paint(GridLayout gridLayout, GameObject brushTarget, Vector3Int position)
{
if (EditorUtility.DisplayDialog("重要提示",string.Format("确认笔刷:{0} {1}",gridLayout.name,position),"ok") ){
base.Paint(gridLayout, brushTarget, position);
}
}
[MenuItem("Assets/Create/2D/Tile Palette/CustomBrush")]
public static void CreateCustomBrush()
{
string path = EditorUtility.SaveFilePanelInProject("Save CustomBrush", "New CustomBrush", "Asset", "Save CustomBrush", "Assets");//弹出保存文件窗口
if (path == "")
return;
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<CustomBrush>(), path);
}
}

[CustomEditor(typeof(CustomBrush))]
public class CustomBrushEditor : GridBrushEditor
{
protected override void OnEnable()
{
base.OnEnable();
//获取序列化信息
Debug.Log((target as CustomBrush).name);
}
public override void OnPaintSceneGUI(GridLayout gridLayout, GameObject brushTarget, BoundsInt position, GridBrushBase.Tool tool, bool executing)
{
base.OnPaintSceneGUI(gridLayout, brushTarget, position, tool, executing);
Handles.color = Color.red;
GUIStyle style = new GUIStyle();
style.normal.textColor = Color.red;
style.fontSize = 20;
Handles.Label(gridLayout.CellToWorld(new Vector3Int(position.x, position.y, 0)), position.center.ToString(), style);
}

}

然后我们在“Assets/Create/2D/Tile Palette/CustomBrush”中点击,就会弹出保存自定义笔刷位置的窗口,我们选定好位置保存

然后在Project文件夹中点击,就会打出我们自定义的参数

自定义name

选中自定义笔刷然后在场景中会显示位置,点击绘制会弹出确定信息

信息

Handles类是UnityEditor提供的渲染辅助类,Handles.Label()表示在Scene窗口中渲染出一个文本信息

拓展Tile

TIle实际上就是一个序列化的asset资源文件,默认的Tile里面记录着它引用的sprite、颜色和碰撞类型等。

系统TIle

如果不满足默认的需求,我们还可以继承它并且重写Tile基类的一些重要回调方法。

首先在Editor文件夹下,新建CustomTile脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using UnityEngine;
using UnityEngine.Tilemaps;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class CustomTile : Tile
{
//需要刷新某个tile时调用
public override void RefreshTile(Vector3Int position, ITilemap tilemap)
{
base.RefreshTile(position, tilemap);
}
//需要获取某个TileData时调用
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
{
base.GetTileData(position, tilemap, ref tileData);
}
//获取Tile动画数据时调用
public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
{
return base.GetTileAnimationData(position, tilemap, ref tileAnimationData);
}
//启动首次调用
public override bool StartUp(Vector3Int position, ITilemap tilemap, GameObject go)
{
return base.StartUp(position, tilemap, go);
}
#if UNITY_EDITOR
[MenuItem("Assets/Create/2D/Tile Palette/CustomTile")]
public static void CreateRoadTile()
{
string path = EditorUtility.SaveFilePanelInProject("Save Custom Tile", "New CustomTile", "Asset", "Save Custom Tile", "Assets");
if (path == "")
return;
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<CustomTile>(), path);
}
#endif
}

自定义Tile

更新TIle

更新Tile就是调用tilemap.GetTile()tilemap.SetTile()方法。和2D精灵一样,TIle的坐标原点也是屏幕的正中心点。

我们控制人物在屏幕中移动来“吃豆豆”,代码如下所示(注意人物要使用上一节的移动代码)

新建TIlemapRefresh脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using UnityEngine;
using UnityEngine.Tilemaps;

public class TIleMapRefresh : MonoBehaviour
{
public SpriteRenderer spriteRenderer;
public Tilemap tilemap;

private void Update()
{
Vector3Int cellpos = tilemap.WorldToCell(spriteRenderer.transform.position);
if(tilemap.GetTile(cellpos) != null)
{
tilemap.SetTile(cellpos, null);
}
}

}

吃豆豆