欢迎光临散文网 会员登陆 & 注册

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

2023-04-25 03:44 作者:秋野Akino_EL  | 我要投稿

大家好,这里是秋野

先叠个甲

我自己是零零散散自学的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的功能了

如果感兴趣或者获得了帮助

请求来个一键三连(话说专栏能一键三连吗?)

如果内容有误或者建议也欢迎指出 

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

分享到微博请遵守国家法律