创建 Isometric Tile Mesh用于Unity原生Navigation寻路

遇到的问题

Unity 无论自身的TileMap(2018版本),还是Asset Store中的插件,对于Isometric(斜45度)的地图支持的都不好.几乎都处于不可用的状态中.

唯一一个不错的且免费的插件是Tiled2Unity

插件的原理是使用Tiled对地图进行编辑,然后通过该插件导入到Unity中使用.

其地图导入部分做的很好,Isometric的地图完全没有问题. 但是其引入的是PolygonCollider2D作为物理碰撞.

对于纯2D的横版游戏完全没有问题.但是如果是俯视的大地图 比如 金庸群侠传,英雄无敌 等等 这种视角的游戏, 如果需要使用原生的寻路系统(NavMeshAgent). 就必须要自己想办法

其实工具内部可以自己写ICustomTiledImporter实现,然后在Tiled中使用AutoTile,编辑相应的规则.

最终实现的流程是就是

  • 编辑AutoTile,使得放置地表时候自动创建Tile Object(粉色的那个,在ObjectLayer).
  • 自己写ICustomTiledImporter读取相应的Property.然后生成相应的Unity中的GameObject

我的方案

使用AutoTile我觉得太麻烦,所以直接写个工具,将Map导出一份Json,读入Json中的Property信息即可以.
所以就剩下第二部分逻辑. 在相应的Tile部分生成GameObject用于NavMesh 的 Bake.

就是在Tiled中创建两个色块Tile(红色,绿色). 红色的色块是不能走的地方,绿色色块是可以走的地方

在Unity中读取对应的信息,找到红色和绿色色块.在对应的位置放置上红色的Prefab和绿色的Prefab.

这种两个Prefab就是一个空的3D物品,然后设置成Navigation Static,一个设置为Walkable,一个设置为NotWalkable

然后直接Bake NavMesh即可.

所以最终的问题 就是如何产生这个 红色或者绿色的Prefab.

代码

生成相应的Mesh代码如下.

我使用了OdinInspector制作界面.如果不是用则自定义CustomEditor放置两个按钮对应MakeTileSaveTile即可

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
using Sirenix.OdinInspector;
using UnityEditor;
using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class MeshTileMaker : MonoBehaviour
{
private const int A = 0;
private const int B = 1;
private const int C = 2;
private const int D = 3;

private const int AP = 4;
private const int BP = 5;
private const int CP = 6;
private const int DP = 7;

private float TILE_HEIGH;

[LabelText("Tile的宽度:")]
public float TILE_WIDTH = 0.64f;
[LabelText("3D模型的高度:")]
public float CUBE_HEIGH = 0.2f;


[Button(ButtonSizes.Large)]
[ButtonGroup("Function")]
private void MakeTile()
{
DoMakeTile();
}

[GUIColor(0, 1, 0)]
[ButtonGroup("Function")]
private void SaveTile()
{
string path = EditorUtility.SaveFilePanel("Save Mesh", "Assets/", name, "asset");
if (string.IsNullOrEmpty(path)) return;

path = FileUtil.GetProjectRelativePath(path);

var filter = GetComponent<MeshFilter>();
var meshToSave = filter.mesh;

MeshUtility.Optimize(meshToSave);

AssetDatabase.CreateAsset(meshToSave, path);
AssetDatabase.SaveAssets();
}


private void DoMakeTile()
{
TILE_HEIGH = TILE_WIDTH / 2;
var HALF_WIDHT = TILE_WIDTH / 2;
var HALF_HEIGH = TILE_HEIGH / 2;


var vertices = new Vector3[8];
vertices[A] = new Vector3(-HALF_WIDHT, 0, 0);
vertices[B] = new Vector3(0, 0, HALF_HEIGH);
vertices[C] = new Vector3(HALF_WIDHT, 0, 0);
vertices[D] = new Vector3(0, 0, -HALF_HEIGH);

vertices[AP] = new Vector3(-HALF_WIDHT, CUBE_HEIGH, 0);
vertices[BP] = new Vector3(0, CUBE_HEIGH, HALF_HEIGH);
vertices[CP] = new Vector3(HALF_WIDHT, CUBE_HEIGH, 0);
vertices[DP] = new Vector3(0, CUBE_HEIGH, -HALF_HEIGH);


var triangles = new int[12 * 3];
var startIndex = 0;
DoPushTriangles(ref triangles, ref startIndex, D, B, A);
DoPushTriangles(ref triangles, ref startIndex, C, B, D);

DoPushTriangles(ref triangles, ref startIndex, AP, BP, DP);
DoPushTriangles(ref triangles, ref startIndex, BP, CP, DP);

DoPushTriangles(ref triangles, ref startIndex, AP, DP, A);
DoPushTriangles(ref triangles, ref startIndex, A, DP, D);

DoPushTriangles(ref triangles, ref startIndex, D, DP, CP);
DoPushTriangles(ref triangles, ref startIndex, D, CP, C);

DoPushTriangles(ref triangles, ref startIndex, B, BP, AP);
DoPushTriangles(ref triangles, ref startIndex, B, AP, A);

DoPushTriangles(ref triangles, ref startIndex, C, CP, BP);
DoPushTriangles(ref triangles, ref startIndex, C, BP, B);

var mesh = new Mesh {name = "TileMesh"};
mesh.vertices = vertices;
mesh.triangles = triangles;
GetComponent<MeshFilter>().mesh = mesh;
}

private static void DoPushTriangles(ref int[] _triangles, ref int _startIndex, int _A, int _B, int _C)
{
_triangles[_startIndex] = _A;
_triangles[_startIndex + 1] = _B;
_triangles[_startIndex + 2] = _C;
_startIndex += 3;
}
}

效果

QQ20180221-230512

QQ20180221-230021 -1-

QQ20180221-230057

坚持原创技术分享,您的支持将鼓励我继续创作!