最近在学习使用Tiledmap,用于制作地图确实很方便快捷,但总不能一个关卡就做一个prefab?还是必须将其保存为文本文件才行啊,于是有了以下的尝试:
先定义一个Tiledmap类,用于存储单个Tiledmap信息
[System.Serializable]
public class SimpleTile
{
[SerializeField]
public string name;
[SerializeField]
public Dictionary<string, string> tiles = new Dictionary<string, string>();
}
tiles是保存的所有tile块。key为坐标值,value为使用的tilemap的名称。
然后需要一个管理同一个Grid下所有Tiledmap的类:
[System.Serializable]
public class SimpleGrid
{
[SerializeField]
public Dictionary<string, SimpleTile> tiles = new Dictionary<string, SimpleTile>();
}
tiles 的key是tiledMap在Hierarchy中的名称。
之后当然是先保存当前Grid下的所有Tiledmap:
public void SaveLevel()
{
Tilemap[] tilemaps = grid.GetComponentsInChildren<Tilemap>();
SimpleGrid simpleGrid = new SimpleGrid();
for (int i = 0; i < tilemaps.Length; i++)
{
//循环读取每一个Tiledmap
ExportMap(tilemaps[i]);
}
Debug.LogWarning(simpleGrid.tiles.Count);
//将赋值完成的数据转换为json字符串。方便文件存储
//JsonConvert 是使用的Newtonsoft.Json 的第三方插件,
//unity自带的JsonUtility可能无法将类正确转换成string。我刚开始就是用的它,发现simpleGrid.tiles.Count一直为0
mtempJson = JsonConvert.SerializeObject(simpleGrid);
//获取到字符串,就可以存储到本地啦,关于存储的环节可以使用File类,或者第三方插件完成
Debug.LogWarning(mtempJson);
}
public void ExportMap(Tilemap tilemap)
{
//获取到tiledmap的格子信息
BoundsInt area = tilemap.cellBounds;
Dictionary<string, string> data = new Dictionary<string, string>();
simpleGrid.tiles[tilemap.name] = new SimpleTile();
simpleGrid.tiles[tilemap.name].name = tilemap.name;
simpleGrid.tiles[tilemap.name].tiles = new Dictionary<string, string>();
for (int i = area.xMin; i < area.xMax; i++)
{
for (int j = area.yMin; j < area.yMax; j++)
{
if(tilemap.GetTile(new Vector3Int(i, j, 0)) == null)
{
//空白的地方就无需保存
continue;
}
//将已有的tile根据自身坐标存储。
//之前想直接存储tilemap.cellBounds ,但是在转json时会报错,所以还是这样一个个存吧
simpleGrid.tiles[tilemap.name].tiles[i+","+j] = tilemap.GetTile(new Vector3Int(i,j,0)).name;
//---------------这个只是为了测试方便------
//Tiles存储了地图上用到的瓦片信息。正常使用时应该在初始化时就将其赋值。
//public Dictionary<string, TileBase> Tiles = new Dictionary<string, TileBase>(); key为瓦片的名称,value为使用的瓦片
if(!Tiles.ContainsKey(tilemap.GetTile(new Vector3Int(i, j, 0)).name))
{
Tiles[tilemap.GetTile(new Vector3Int(i, j, 0)).name] = tilemap.GetTile(new Vector3Int(i, j, 0));
}
}
}
}
之后是读取文件并将其重新绘制到界面。读取文件的方式依旧可以使用File类或者第三方插件,此处不做过多讲解。下面是解析字符串并绘制到界面:
public void CreateLevel(string json)
{
if (json == null)
{
Debug.LogWarning("传入字符串为null");
return;
}
//先将json字符串还原为SimpleGrid类
SimpleGrid simpleGrid = JsonConvert.DeserializeObject<SimpleGrid>(json);
if (simpleGrid == null)
{
Debug.LogWarning("传入的字符串不能正确解析");
return;
}
//先创建一个Grid
GameObject grid = new GameObject("Grid");
grid.AddComponent<Grid>();
Debug.LogWarning("keys::"+simpleGrid.tiles.Count);
Debug.LogWarning("Tiles::" + Tiles.Count);
//循环创建每一个Tiledmap,如果想做渐进加载的效果,可以将这个方法修改为协程方式处理
foreach (var item in simpleGrid.tiles.Keys)
{
//创建Tiledmap并将父级设为刚才的Grid
GameObject tile = new GameObject(item);
tile.transform.SetParent(grid.transform);
//添加Tilemap 组件
Tilemap tilemap = tile.AddComponent<Tilemap>();
//一定要添加TilemapRenderer组件,之前忘了添加,一直没显示瓦片,还找了半天bug。。。
tile.AddComponent<TilemapRenderer>();
//将瓦片信息读取出来
SimpleTile simpleTile = simpleGrid.tiles[item];
foreach (var vec2 in simpleTile.tiles.Keys)
{
string[] pos = vec2.Split(",");
//在指定坐标下设置瓦片
tilemap.SetTile(new Vector3Int(int.Parse(pos[0]), int.Parse(pos[1]), 0), getTile(simpleTile.tiles[vec2]));
}
}
}
/// <summary>
/// 根据瓦片名称获取到瓦片的类
/// </summary>
/// <param name="tileName"></param>
/// <returns></returns>
public TileBase getTile(string tileName)
{
TileBase tile;
//这个Tiles 是刚才在存储时赋值的
if (Tiles.TryGetValue(tileName, out tile))
{
return tile;
}
else
{
return null;
}
}
It‘s Done!!文章来源:https://www.toymoban.com/news/detail-542501.html
注::刚才看到有些部分和制作的关卡内容有出入,仔细检查后发现是因为TilemapRenderer的层级没有处理,所以在保存的时候应该保存下TilemapRenderer的SortingLayer和Order in Layer并在创建时赋值。文章来源地址https://www.toymoban.com/news/detail-542501.html
到了这里,关于unity 简单实现tilemap的保存和读取(以便用于关卡编辑器)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!