「Unity」2DTileMap —— 能在运行中切换某位置的瓦片图片的规则瓦片(二)

大家好,这里是秋野
先叠个甲
我自己是零零散散自学的Unity和C#,只是出于兴趣编写了这个东西。
代码内容里面大概率出现各种不规范和弱智写法
如果发现
!!!可以尽情的指出,骂也无所谓!!!
(如果要骂,还是骂轻一点吧)
而且写这个专栏也是为自己理清楚自己做这个东西的逻辑
接下来就是正题了

四·功能实现(二)——魔改RuleTile
如小标题所说的
我们在这里需要魔改RuleTile
为什么需要魔改,那么具体这里有两个原因
第一个原因
我们看看之前写的代码里面有一段是用于生成在BaseLayer的Tile
基本逻辑就是根据底下的RuleTile的sprite去生成一个Tile放上去
那么这里就会出现一个问题
每次刷新都要去生成要给新的Tile给覆盖上去
当我们「画」地图的数量很多的时候
在BaseLayer的Tilemap组件里面就会出现一堆Tile

就,很不优雅
第二个原因
我们需要有那么个东西去保存我们用来切换的Sprite或者Tile
虽说RuleTile本身储存每个规则的Sprite的方式就是用一个Sprite[]来存储的
但每次需要根据Sprite来获取规则,就得遍历两边来确认
一遍规则列表,一遍Sprite列表
还是突出一个,不优雅
那么我们就得出来两个需求了
「复用Tile,避免每次都要生成一个Tile浪费资源」
「优化获取规则的方法,方便以后切换Tile的步骤」
那么首先是复用Tile
既然要避免每次都生成一个新的出来
那就直接在editor界面的时候就预先制作好每个Tile
最简单的方法就是直接将分割好的Sprite拖到TilePalette里面
他让你选择的路径就是保存Tile的路径
那么我们就可以直接用程序直接在这路径去找对应的Tile使用了
但是,这样还是很麻烦很不优雅
所以咱们要开始「魔改」RuleTile了
首先创建一个脚本文件
using UnityEngine;
using UnityEngine.Tilemaps;
public class RuleTilePuls : RuleTile
{
//Tile列表
public Tile[] Tiles;
}
就很简单的在RuleTile的基础上加了一个Tile数组
选中我们的Ruletile


将代码换成我们自己写的Ruletile
即可看到我们的Tile数组出来了

但是这个只是解决了保存已有的Tile
没法精确的找到这个Tile的索引值
除非每次找个Tile都去foreach一下
也很不优雅
所以咱把Sprite的name作为key,索引值作为value用字典去快速找到咱们需要的tile
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class RuleTilePuls : RuleTile
{
//Tile列表
public List<Tile> Tiles;
/// <summary>
/// 获取字典
/// </summary>
/// <returns></returns>
public Dictionary<string, int> GetDic()
{
Dictionary<string, int> neighbors = new Dictionary<string, int>();
for (int i = 0; i < this.Tiles.Count; i++)
{
neighbors.Add(this.Tiles[i].name, i);
}
return neighbors;
}
}
然后咱们把之前生成好的Tile全放到这个Tile数组内

这样是可以做到了咱们的第一个需求
「复用Tile,避免每次都要生成一个Tile浪费资源」
但是咱们还没能完成第二个需求
「优化获取规则的方法,方便以后切换Tile的步骤」
那么我们需要保存Tile的同时保存他对应的规则
如果看过前一篇那个快速制作RuleTile的文章的话

会知道Unity保存规则的方法是用一个字典去保存
那我们是也要去保存他的字典吗?
当然不用
我们只需要保存一个索引值即可
就是RuleTile.m_TilingRules的索引值
因为一个TilingRule里面也就只会保存一个规则
那么保存他的索引值自然也就保存跟他对应规则的相关Sprite
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
using System;
public class RuleTilePuls : RuleTile
{
//平铺单元列表
public List<TilingUnit> TilingUnits;
/// <summary>
/// 获取字典
/// </summary>
/// <returns></returns>
public Dictionary<string, Vector2Int> GetDic()
{
Dictionary<string, Vector2Int> neighbors = new Dictionary<string, Vector2Int>();
for (int i = 0; i < this.m_TilingRules.Count; i++)
{
for (int j = 0; j < this.m_TilingRules[i].m_Sprites.Length; j++)
{
neighbors.Add(this.m_TilingRules[i].m_Sprites[j].name, new Vector2Int(i, j));
}
}
return neighbors;
}
//平铺单元
[System.Serializable]
public class TilingUnit
{
public List<Tile> Tiles;
}
}
用一个类去打包这两个数据
如果我们以后需要添加其他东西也能直接在这个类中添加

虽说这东西是写好了
但是要往里填数据的时候就麻烦了
需要根据下面的TilingRules来一个一个添加和填写
这就又很不优雅了
既然咱们可以搞快速的制作一个RuleTile
自然就可以快速填入这个列表是不
避免篇幅过长就单独一个专栏了
↓↓↓↓

假设我们这里已经搞定好TilingRules的写入
剩下的就是需要修改获取Tile的逻辑了
只需修改之前的UpdateAroundTileAtBaseTiles即可
/// <summary>
/// 刷新周围八格与自己位置的Tile
/// </summary>
/// <param name="pos">位置</param>
private void UpdateAroundTileAtBaseTiles(Vector3Int pos)
{
Vector2Int index;
foreach (Vector3Int tilePos in GetAllAroundTilePositionList(pos))
{
//判断ruleLayer是否为空,避免出现报错
if (ruleLayer.GetSprite(tilePos) == null)
{
baseLayer.SetTile(tilePos, null);
}
else
{
index = neighbors[ruleLayer.GetSprite(tilePos).name];
baseLayer.SetTile(tilePos, ruleTiles.TilingUnits[index.x].Tiles[index.y]);
}
}
}
经过测试是可以正常运行的
那么我就不再发一次测试的动图了
也省一点流量
接下来的下一篇就是实践切换Tile的功能了
如果感兴趣或者获得了帮助
请求来个一键三连(话说专栏能一键三连吗?)
如果内容有误或者建议也欢迎指出