Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / room / RoomDoorInfo.cs
@小李xl 小李xl on 20 Feb 2024 8 KB 弓箭功能开发中

using System;
using System.Collections.Generic;
using Godot;

/// <summary>
/// 房间的门
/// </summary>
public class RoomDoorInfo : IDestroy
{
    public bool IsDestroyed { get; private set; }

    /// <summary>
    /// 所在墙面方向
    /// </summary>
    public DoorDirection Direction;

    /// <summary>
    /// 是否是正向的门
    /// </summary>
    public bool IsForward;

    /// <summary>
    /// 所在的房间
    /// </summary>
    public RoomInfo RoomInfo;

    /// <summary>
    /// 连接的门
    /// </summary>
    public RoomDoorInfo ConnectDoor;

    /// <summary>
    /// 连接的房间
    /// </summary>
    public RoomInfo ConnectRoom;

    /// <summary>
    /// 原点坐标, 单位: 格
    /// </summary>
    public Vector2I OriginPosition;

    /// <summary>
    /// 地板所占的地板格子, 单位: 格, 使用时不需要加上 OriginPosition
    /// </summary>
    public HashSet<Vector2I> AisleFloorCell;
    
    /// <summary>
    /// 地板所占的矩形, 单位: 格, 使用时不需要加上 OriginPosition
    /// </summary>
    public Rect2I AisleFloorRect;

    /// <summary>
    /// 与下一道门是否有交叉点
    /// </summary>
    public bool HasCross;

    /// <summary>
    /// 与下一道门的交叉点, 单位: 格
    /// </summary>
    public Vector2I Cross;

    /// <summary>
    /// 连接过道使用预览纹理, 用于小地图
    /// </summary>
    public ImageTexture AislePreviewTexture;

    /// <summary>
    /// 连接过道使用预览图, 用于小地图
    /// </summary>
    public TextureRect AislePreviewSprite;

    /// <summary>
    /// 门实例
    /// </summary>
    public RoomDoor Door;

    /// <summary>
    /// 过道的迷雾
    /// </summary>
    public FogMask AisleFogMask;

    /// <summary>
    /// 过道迷雾区域
    /// </summary>
    public AisleFogArea AisleFogArea;

    /// <summary>
    /// 门区域预览房间迷雾
    /// </summary>
    public PreviewFogMask PreviewRoomFogMask;
    
    /// <summary>
    /// 门区域预览过道迷雾
    /// </summary>
    public PreviewFogMask PreviewAisleFogMask;

    /// <summary>
    /// 未探索的区域显示的问号
    /// </summary>
    public Sprite2D UnknownSprite;

    /// <summary>
    /// 世界坐标下的原点坐标, 单位: 像素
    /// </summary>
    public Vector2I GetWorldOriginPosition()
    {
        return new Vector2I(
            OriginPosition.X * GameConfig.TileCellSize,
            OriginPosition.Y * GameConfig.TileCellSize
        );
    }

    /// <summary>
    /// 终点坐标, 单位: 格
    /// </summary>
    public Vector2I GetEndPosition()
    {
        if (Direction == DoorDirection.E || Direction == DoorDirection.W)
        {
            return OriginPosition + new Vector2I(0, 4);
        }
        else if (Direction == DoorDirection.N || Direction == DoorDirection.S)
        {
            return OriginPosition + new Vector2I(4, 0);
        }

        return default;
    }
    
    /// <summary>
    /// 世界坐标下的终点坐标, 单位: 像素
    /// </summary>
    public Vector2I GetWorldEndPosition()
    {
        if (Direction == DoorDirection.E || Direction == DoorDirection.W)
        {
            return GetWorldOriginPosition() + new Vector2I(0, 4 * GameConfig.TileCellSize);
        }
        else if (Direction == DoorDirection.N || Direction == DoorDirection.S)
        {
            return GetWorldOriginPosition() + new Vector2I(4 * GameConfig.TileCellSize, 0);
        }

        return default;
    }

    /// <summary>
    /// 获取直连门过道区域数据, 单位: 格, 如果当前门连接区域带交叉点, 则报错
    /// </summary>
    public Rect2I GetAisleRect()
    {
        if (HasCross)
        {
            throw new Exception("当前门连接的过道包含交叉点, 请改用 GetCrossAisleRect() 函数!");
        }
        
        var rect = Utils.CalcRect(
            OriginPosition.X,
            OriginPosition.Y,
            ConnectDoor.OriginPosition.X,
            ConnectDoor.OriginPosition.Y
        );
    
        switch (Direction)
        {
            case DoorDirection.E:
                rect.Size = new Vector2I(rect.Size.X, GameConfig.CorridorWidth);
                break;
            case DoorDirection.W:
                rect.Size = new Vector2I(rect.Size.X, GameConfig.CorridorWidth);
                break;
                    
            case DoorDirection.S:
                rect.Size = new Vector2I(GameConfig.CorridorWidth, rect.Size.Y);
                break;
            case DoorDirection.N:
                rect.Size = new Vector2I(GameConfig.CorridorWidth, rect.Size.Y);
                break;
        }

        return rect;
    }

    /// <summary>
    /// 获取交叉门过道区域数据, 单位: 格, 如果当前门连接区域不带交叉点, 则报错
    /// </summary>
    public CrossAisleRectData GetCrossAisleRect()
    {
        if (!HasCross)
        {
            throw new Exception("当前门连接的过道不包含交叉点, 请改用 GetAisleRect() 函数!");
        }

        Rect2I rect;
        Rect2I rect2;

        //计算范围
        switch (Direction)
        {
            case DoorDirection.E: //→
                rect = new Rect2I(
                    OriginPosition.X,
                    OriginPosition.Y,
                    Cross.X - OriginPosition.X,
                    GameConfig.CorridorWidth
                );
                break;
            case DoorDirection.W: //←
                rect = new Rect2I(
                    Cross.X + GameConfig.CorridorWidth,
                    Cross.Y,
                    OriginPosition.X - (Cross.X + GameConfig.CorridorWidth),
                    GameConfig.CorridorWidth
                );
                break;
            case DoorDirection.S: //↓
                rect = new Rect2I(
                    OriginPosition.X,
                    OriginPosition.Y,
                    GameConfig.CorridorWidth,
                    Cross.Y - OriginPosition.Y
                );
                break;
            case DoorDirection.N: //↑
                rect = new Rect2I(
                    Cross.X,
                    Cross.Y + GameConfig.CorridorWidth,
                    GameConfig.CorridorWidth,
                    OriginPosition.Y - (Cross.Y + GameConfig.CorridorWidth)
                );
                break;
            default:
                rect = new Rect2I();
                break;
        }

        switch (ConnectDoor.Direction)
        {
            case DoorDirection.E: //→
                rect2 = new Rect2I(
                    ConnectDoor.OriginPosition.X,
                    ConnectDoor.OriginPosition.Y,
                    Cross.X - ConnectDoor.OriginPosition.X,
                    GameConfig.CorridorWidth
                );
                break;
            case DoorDirection.W: //←
                rect2 = new Rect2I(
                    Cross.X + GameConfig.CorridorWidth,
                    Cross.Y,
                    ConnectDoor.OriginPosition.X -
                    (Cross.X + GameConfig.CorridorWidth),
                    GameConfig.CorridorWidth
                );
                break;
            case DoorDirection.S: //↓
                rect2 = new Rect2I(
                    ConnectDoor.OriginPosition.X,
                    ConnectDoor.OriginPosition.Y,
                    GameConfig.CorridorWidth,
                    Cross.Y - ConnectDoor.OriginPosition.Y
                );
                break;
            case DoorDirection.N: //↑
                rect2 = new Rect2I(
                    Cross.X,
                    Cross.Y + GameConfig.CorridorWidth,
                    GameConfig.CorridorWidth,
                    ConnectDoor.OriginPosition.Y -
                    (Cross.Y + GameConfig.CorridorWidth)
                );
                break;
            default:
                rect2 = new Rect2I();
                break;
        }

        return new CrossAisleRectData()
        {
            Rect1 = rect,
            Rect2 = rect2,
            Cross = new Rect2I(Cross + Vector2I.One, new Vector2I(GameConfig.CorridorWidth - 2, GameConfig.CorridorWidth - 2))
        };
    }
    
    public void Destroy()
    {
        if (IsDestroyed)
        {
            return;
        }

        IsDestroyed = true;
        if (AisleFogMask != null)
        {
            AisleFogMask.Destroy();
        }

        if (AisleFogArea != null)
        {
            AisleFogArea.Destroy();
        }

        if (PreviewRoomFogMask != null)
        {
            PreviewRoomFogMask.Destroy();
        }
        
        if (PreviewAisleFogMask != null)
        {
            PreviewAisleFogMask.Destroy();
        }

        if (AislePreviewTexture != null)
        {
            AislePreviewTexture.Dispose();
        }

        if (AislePreviewSprite != null)
        {
            AislePreviewSprite.QueueFree();
        }
    }
}