Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / serialize / tileSet / TileSetTerrainInfo.cs
@小李xl 小李xl on 11 Jan 2024 20 KB 制作2x2地形

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

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

    //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格 (47块) type = 1
    /// </summary>
    [JsonInclude] public Dictionary<uint, int[]> T;

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

    public TileSetTerrainInfo Clone()
    {
        var terrainInfo = new TileSetTerrainInfo();
        terrainInfo.InitData();
        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] });
        }
        return terrainInfo;
    }
    
    /// <summary>
    /// 返回这个TileSet地形是否可以正常使用了
    /// </summary>
    /// <returns></returns>
    public bool CanUse()
    {
        return T != null && T.Count == 47 && 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 == 1)
        {
            return bitCoords.Y * GameConfig.TerrainBitSize1.X + bitCoords.X;
        }
        else if (type == 2)
        {
            return bitCoords.Y * GameConfig.TerrainBitSize2.X + bitCoords.X;
        }
        else if (type == 3)
        {
            return bitCoords.Y * GameConfig.TerrainBitSize3.X + bitCoords.X;
        }

        return -1;
    }

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

        return TerrainPeering.None;
    }
    
    /// <summary>
    /// 将地形掩码存入 TileSetTerrainInfo 中
    /// </summary>
    public void SetTerrainCell(int index, byte type, int[] cellData)
    {
        if (type == 1) //顶部墙壁
        {
            var terrainBit = IndexToTerrainBit(index, type);
            if (terrainBit != TerrainPeering.None)
            {
                T[terrainBit] = cellData;
            }
        }
        else if (type == 2) //侧方墙壁
        {
            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 == 3) //地板
        {
            F[0] = cellData;
        }
    }

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

        return null;
    }
}