Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / serialize / tileSet / TileSetTerrainInfo.cs

using System.Collections.Generic;
using System.Text.Json.Serialization;
using Godot;
using static TerrainPeering;

/// <summary>
/// 地形配置数据, 数据都为 int 数组, 下标0和1分别代表x和y, 单位: 像素
/// </summary>
public class TileSetTerrainInfo : IClone<TileSetTerrainInfo>
{
    public const byte TerrainLayerType = 1;
    public const byte MiddleLayerType = 2;
    public const byte FloorLayerType = 3;

    /// <summary>
    /// 地形名称
    /// </summary>
    [JsonInclude]
    public string Name;
    
    //type = 3
    /// <summary>
    /// 地板 (1块) type = 3
    /// </summary>
    [JsonInclude] public Dictionary<uint, int[]> F;

    /// <summary>
    /// 侧方墙壁 (4块) type = 2
    /// </summary>
    [JsonInclude] public Dictionary<uint, int[]> M;
    
    /// <summary>
    /// 自动平铺地形 (47块/13块) type = 1
    /// </summary>
    [JsonInclude] public Dictionary<uint, int[]> T;

    /// <summary>
    /// 地形类型, 0: 3x3地形, 1: 2x2地形
    /// </summary>
    [JsonInclude]
    public byte TerrainType;

    public void InitData()
    {
        TerrainType = 0;
        F = new Dictionary<uint, int[]>();
        M = new Dictionary<uint, int[]>();
        T = new Dictionary<uint, int[]>();
    }

    public TileSetTerrainInfo Clone()
    {
        var terrainInfo = new TileSetTerrainInfo();
        terrainInfo.InitData();
        terrainInfo.Name = Name;
        foreach (var pair in T)
        {
            terrainInfo.T.Add(pair.Key, new []{ pair.Value[0], pair.Value[1] });
        }
        foreach (var pair in M)
        {
            terrainInfo.M.Add(pair.Key, new []{ pair.Value[0], pair.Value[1] });
        }
        foreach (var pair in F)
        {
            terrainInfo.F.Add(pair.Key, new []{ pair.Value[0], pair.Value[1] });
        }
        terrainInfo.TerrainType = TerrainType;
        return terrainInfo;
    }

    /// <summary>
    /// 返回这个TileSet地形是否可以正常使用了
    /// </summary>
    /// <returns></returns>
    public bool CanUse()
    {
        if (TerrainType == 0)
        {
            if (T == null || T.Count != 47)
            {
                return false;
            }
        }
        else
        {
            if (T == null || T.Count != 13)
            {
                return false;
            }
        }

        return M != null && M.Count == 4 && F != null && F.Count == 1;
    }

    /// <summary>
    /// 将存储的坐标数据转换成 Vector2I 对象, 返回的 Vector2I 单位: 格
    /// </summary>
    public Vector2I GetPosition(int[] ints)
    {
        return new Vector2I(ints[0] / GameConfig.TileCellSize, ints[1] / GameConfig.TileCellSize);
    }
    
    /// <summary>
    /// 将地形掩码中的坐标转换为索引。
    /// </summary>
    /// <param name="bitCoords">地形坐标</param>
    /// <param name="type">地形类型</param>
    public int TerrainCoordsToIndex(Vector2I bitCoords, byte type)
    {
        if (type == TerrainLayerType)
        {
            return bitCoords.Y * GameConfig.TerrainBit3x3.X + bitCoords.X;
        }
        else if (type == MiddleLayerType)
        {
            return bitCoords.Y * GameConfig.TerrainBitMiddle.X + bitCoords.X;
        }
        else if (type == FloorLayerType)
        {
            return bitCoords.Y * GameConfig.TerrainBitFloor.X + bitCoords.X;
        }
        return -1;
    }

    /// <summary>
    /// 将地掩码值转换为索引值
    /// </summary>
    /// <param name="bit">地形掩码值</param>
    /// <param name="type">地形类型</param>
    public int TerrainBitToIndex(uint bit, byte type)
    {
        if (type == TerrainLayerType) //顶部墙壁
        {
            if (TerrainType == 0) //47格
            {
                switch (bit)
                {
                    case Center | Bottom: return 0;
                    case Center | Right | Bottom: return 1;
                    case Left | Center | Right | Bottom: return 2;
                    case Left | Center | Bottom: return 3;
                    case LeftTop | Top | Left | Center | Right | Bottom: return 4; 
                    case Left | Center | Right | Bottom | RightBottom: return 5;
                    case Left | Center | Right | LeftBottom | Bottom: return 6;
                    case Top | RightTop | Left | Center | Right | Bottom: return 7;
                    case Center | Right | Bottom | RightBottom: return 8;
                    case Top | Left | Center | Right | LeftBottom | Bottom | RightBottom: return 9;
                    case Left | Center | Right | LeftBottom | Bottom | RightBottom: return 10;
                    case Left | Center | LeftBottom | Bottom: return 11;
                    case Top | Center | Bottom: return 12;
                    case Top | Center | Right | Bottom: return 13;
                    case Top | Left | Center | Right | Bottom: return 14;
                    case Top | Left | Center | Bottom: return 15;
                    case Top | Center | Right | Bottom | RightBottom: return 16;
                    case Top | RightTop | Left | Center | Right | LeftBottom | Bottom | RightBottom: return 17;
                    case LeftTop | Top | Left | Center | Right | LeftBottom | Bottom | RightBottom: return 18;
                    case Top | Left | Center | LeftBottom | Bottom: return 19;
                    case Top | RightTop | Center | Right | Bottom | RightBottom: return 20;
                    case Top | RightTop | Left | Center | Right | LeftBottom | Bottom: return 21;
                    case LeftTop | Top | Left | Center | Right | LeftBottom | Bottom: return 23;
                    case Top | Center: return 24;
                    case Top | Center | Right: return 25;
                    case Top | Left | Center | Right: return 26;
                    case Top | Left | Center: return 27;
                    case Top | RightTop | Center | Right | Bottom: return 28;
                    case LeftTop | Top | RightTop | Left | Center | Right | Bottom | RightBottom: return 29;
                    case LeftTop | Top | RightTop | Left | Center | Right | LeftBottom | Bottom: return 30;
                    case LeftTop | Top | Left | Center | Bottom: return 31;
                    case Top | RightTop | Left | Center | Right | Bottom | RightBottom: return 32;
                    case LeftTop | Top | RightTop | Left | Center | Right | LeftBottom | Bottom | RightBottom: return 33;
                    case LeftTop | Top | Left | Center | Right | Bottom | RightBottom: return 34;
                    case LeftTop | Top | Left | Center | LeftBottom | Bottom: return 35; 
                    case Center: return 36;
                    case Center | Right: return 37;
                    case Left | Center | Right: return 38;
                    case Left | Center: return 39;
                    case Top | Left | Center | Right | LeftBottom | Bottom: return 40;   
                    case Top | RightTop | Left | Center | Right: return 41;
                    case LeftTop | Top | Left | Center | Right: return 42;
                    case Top | Left | Center | Right | Bottom | RightBottom: return 43;  
                    case Top | RightTop | Center | Right: return 44;
                    case LeftTop | Top | RightTop | Left | Center | Right: return 45;    
                    case LeftTop | Top | RightTop | Left | Center | Right | Bottom: return 46;
                    case LeftTop | Top | Left | Center: return 47;
                }
            }
            else if (TerrainType == 1) //13格
            {
                switch (bit)
                {
                    //第一排
                    case Center | RightBottom: return 0;
                    case Center | RightBottom | LeftBottom: return 1;
                    case Center | LeftBottom: return 2;
                    case Center | LeftTop | RightTop | LeftBottom: return 3;
                    case Center | LeftTop | RightTop | RightBottom: return 4;
                    //第二排
                    case Center | RightTop | RightBottom: return 5;
                    case Center | LeftTop | LeftBottom | RightTop | RightBottom: return 6;
                    case Center | LeftTop | LeftBottom: return 7;
                    case Center | LeftTop | LeftBottom | RightBottom: return 8;
                    case Center | RightTop | LeftBottom | RightBottom: return 9;
                    //第三排
                    case Center | RightTop: return 10;
                    case Center | LeftTop | RightTop: return 11;
                    case Center | LeftTop: return 12;
                }
            }
        }
        else if (type == MiddleLayerType)
        {
            if (bit < 4)
            {
                return (int)bit;
            }
        }
        else if (type == FloorLayerType)
        {
            if (bit == 0)
            {
                return 0;
            }
        }

        return -1;
    }

    /// <summary>
    /// 根据给定的索引和类型计算地形掩码值。
    /// </summary>
    /// <param name="index">用于确定地形掩码的索引。</param>
    /// <param name="type">要计算地形位值的图层类型。</param>
    /// <returns></returns>
    public uint IndexToTerrainBit(int index, byte type)
    {
        if (type == TerrainLayerType) //顶部墙壁
        {
            if (TerrainType == 0) //47格
            {
                switch (index)
                {
                    case 0: return Center | Bottom;
                    case 1: return Center | Right | Bottom;
                    case 2: return Left | Center | Right | Bottom;
                    case 3: return Left | Center | Bottom;
                    case 4: return LeftTop | Top | Left | Center | Right | Bottom; 
                    case 5: return Left | Center | Right | Bottom | RightBottom;
                    case 6: return Left | Center | Right | LeftBottom | Bottom;
                    case 7: return Top | RightTop | Left | Center | Right | Bottom;
                    case 8: return Center | Right | Bottom | RightBottom;
                    case 9: return Top | Left | Center | Right | LeftBottom | Bottom | RightBottom;
                    case 10: return Left | Center | Right | LeftBottom | Bottom | RightBottom;
                    case 11: return Left | Center | LeftBottom | Bottom;
                    case 12: return Top | Center | Bottom;
                    case 13: return Top | Center | Right | Bottom;
                    case 14: return Top | Left | Center | Right | Bottom;
                    case 15: return Top | Left | Center | Bottom;
                    case 16: return Top | Center | Right | Bottom | RightBottom;
                    case 17: return Top | RightTop | Left | Center | Right | LeftBottom | Bottom | RightBottom;
                    case 18: return LeftTop | Top | Left | Center | Right | LeftBottom | Bottom | RightBottom;
                    case 19: return Top | Left | Center | LeftBottom | Bottom;
                    case 20: return Top | RightTop | Center | Right | Bottom | RightBottom;
                    case 21: return Top | RightTop | Left | Center | Right | LeftBottom | Bottom;
                    case 23: return LeftTop | Top | Left | Center | Right | LeftBottom | Bottom;
                    case 24: return Top | Center;
                    case 25: return Top | Center | Right;
                    case 26: return Top | Left | Center | Right;
                    case 27: return Top | Left | Center;
                    case 28: return Top | RightTop | Center | Right | Bottom;
                    case 29: return LeftTop | Top | RightTop | Left | Center | Right | Bottom | RightBottom;
                    case 30: return LeftTop | Top | RightTop | Left | Center | Right | LeftBottom | Bottom;
                    case 31: return LeftTop | Top | Left | Center | Bottom;
                    case 32: return Top | RightTop | Left | Center | Right | Bottom | RightBottom;
                    case 33: return LeftTop | Top | RightTop | Left | Center | Right | LeftBottom | Bottom | RightBottom;
                    case 34: return LeftTop | Top | Left | Center | Right | Bottom | RightBottom;
                    case 35: return LeftTop | Top | Left | Center | LeftBottom | Bottom;   
                    case 36: return Center;
                    case 37: return Center | Right;
                    case 38: return Left | Center | Right;
                    case 39: return Left | Center;
                    case 40: return Top | Left | Center | Right | LeftBottom | Bottom;     
                    case 41: return Top | RightTop | Left | Center | Right;
                    case 42: return LeftTop | Top | Left | Center | Right;
                    case 43: return Top | Left | Center | Right | Bottom | RightBottom;    
                    case 44: return Top | RightTop | Center | Right;
                    case 45: return LeftTop | Top | RightTop | Left | Center | Right;      
                    case 46: return LeftTop | Top | RightTop | Left | Center | Right | Bottom;
                    case 47: return LeftTop | Top | Left | Center;
                }
            }
            else if (TerrainType == 1) //13格
            {
                switch (index)
                {
                    //第一排
                    case 0: return Center | RightBottom;
                    case 1: return Center | RightBottom | LeftBottom;
                    case 2: return Center | LeftBottom;
                    case 3: return Center | LeftTop | RightTop | LeftBottom;
                    case 4: return Center | LeftTop | RightTop | RightBottom;
                    //第二排
                    case 5: return Center | RightTop | RightBottom;
                    case 6: return Center | LeftTop | LeftBottom | RightTop | RightBottom;
                    case 7: return Center | LeftTop | LeftBottom;
                    case 8: return Center | LeftTop | LeftBottom | RightBottom;
                    case 9: return Center | RightTop | LeftBottom | RightBottom;
                    //第三排
                    case 10: return Center | RightTop;
                    case 11: return Center | LeftTop | RightTop;
                    case 12: return Center | LeftTop;
                }
            }
        }
        else if (type == MiddleLayerType)
        {
            if (index >= 0 && index < 4)
            {
                return (uint)index;
            }
        }

        return None;
    }
    
    /// <summary>
    /// 将地形掩码存入 TileSetTerrainInfo 中
    /// </summary>
    public void SetTerrainCell(int index, byte type, int[] cellData)
    {
        if (type == TerrainLayerType) //顶部墙壁
        {
            var terrainBit = IndexToTerrainBit(index, type);
            if (terrainBit != None)
            {
                T[terrainBit] = cellData;
            }
        }
        else if (type == MiddleLayerType) //侧方墙壁
        {
            switch (index)
            {
                case 0: M[0] = cellData; break;
                case 1: M[1] = cellData; break;
                case 2: M[2] = cellData; break;
                case 3: M[3] = cellData; break;
            }
        }
        else if (type == FloorLayerType) //地板
        {
            F[0] = cellData;
        }
    }

    /// <summary>
    /// 移除地形掩码
    /// </summary>
    public void RemoveTerrainCell(int index, byte type)
    {
        if (type == TerrainLayerType) //顶部墙壁
        {
            var terrainBit = IndexToTerrainBit(index, type);
            if (terrainBit != None)
            {
                T.Remove(terrainBit);
            }
        }
        else if (type == MiddleLayerType) //侧方墙壁
        {
            switch (index)
            {
                case 0: M.Remove(0); break;
                case 1: M.Remove(1); break;
                case 2: M.Remove(2); break;
                case 3: M.Remove(3); break;
            }
        }
        else if (type == FloorLayerType) //地板
        {
            F.Remove(0);
        }
    }
    
    /// <summary>
    /// 获取指定索引的地形掩码存储的数据
    /// </summary>
    public int[] GetTerrainCell(int index, byte type)
    {
        if (type == TerrainLayerType) //顶部墙壁
        {
            var terrainBit = IndexToTerrainBit(index, type);
            if (terrainBit != None)
            {
                if (T.TryGetValue(terrainBit, out var cellData))
                {
                    return cellData;
                }
            }
        }
        else if (type == MiddleLayerType) //侧方墙壁
        {
            switch (index)
            {
                case 0:
                {
                    if (M.TryGetValue(0, out var cellData)) return cellData;
                }
                    break;
                case 1:
                {
                    if (M.TryGetValue(1, out var cellData)) return cellData;
                }
                    break;
                case 2:
                {
                    if (M.TryGetValue(2, out var cellData)) return cellData;
                }
                    break;
                case 3:
                {
                    if (M.TryGetValue(3, out var cellData)) return cellData;
                }
                    break;
            }
        }
        else if (type == FloorLayerType) //地板
        {
            if (F.TryGetValue(0, out var cellData)) return cellData;
        }

        return null;
    }
}