Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / fog / RoomFogMask.cs

using Godot;

/// <summary>
/// 迷雾遮罩
/// </summary>
public partial class RoomFogMask : PointLight2D, IDestroy
{
    public int Width { get; private set; }
    public int Height { get; private set; }
    
    public bool IsDestroyed { get; private set; }
    private bool _init = false;

    private static Image _leftTransition;
    private static Image _rightTransition;
    private static Image _topTransition;
    private static Image _downTransition;
    
    private static Image _leftTopTransition;
    private static Image _rightTopTransition;
    private static Image _leftDownTransition;
    private static Image _rightDownTransition;
    
    private static Image _inLeftTopTransition;
    private static Image _inRightTopTransition;
    private static Image _inLeftDownTransition;
    private static Image _inRightDownTransition;
    
    private static bool _initSprite = false;

    private static void InitSprite()
    {
        if (_initSprite)
        {
            return;
        }
        _initSprite = false;

        var temp = ResourceManager.Load<Texture2D>(ResourcePath.resource_sprite_map_WallTransition1_png, false);
        _leftTransition = temp.GetImage();
        _rightTransition = temp.GetImage();
        _rightTransition.Rotate180();
        _topTransition = temp.GetImage();
        _topTransition.Rotate90(ClockDirection.Clockwise);
        _downTransition = temp.GetImage();
        _downTransition.Rotate90(ClockDirection.Counterclockwise);
        
        var temp2 = ResourceManager.Load<Texture2D>(ResourcePath.resource_sprite_map_WallTransition2_png, false);
        _leftDownTransition = temp2.GetImage();
        _leftTopTransition = temp2.GetImage();
        _leftTopTransition.Rotate90(ClockDirection.Clockwise);
        _rightDownTransition = temp2.GetImage();
        _rightDownTransition.Rotate90(ClockDirection.Counterclockwise);
        _rightTopTransition = temp2.GetImage();
        _rightTopTransition.Rotate180();
        
        var temp3 = ResourceManager.Load<Texture2D>(ResourcePath.resource_sprite_map_WallTransition3_png, false);
        _inLeftDownTransition = temp3.GetImage();
        _inLeftTopTransition = temp3.GetImage();
        _inLeftTopTransition.Rotate90(ClockDirection.Clockwise);
        _inRightDownTransition = temp3.GetImage();
        _inRightDownTransition.Rotate90(ClockDirection.Counterclockwise);
        _inRightTopTransition = temp3.GetImage();
        _inRightTopTransition.Rotate180();
    }
    
    /// <summary>
    /// 初始化贩房间迷雾遮罩
    /// </summary>
    /// <param name="roomInfo">房间对象</param>
    /// <param name="rect2">迷雾所占区域</param>
    public void Init(RoomInfo roomInfo, Rect2I rect2)
    {
        if (_init)
        {
            return;
        }
        InitSprite();
        GlobalPosition = rect2.Position + rect2.Size / 2;
        
        //创建光纹理
        Width = rect2.Size.X;
        Height = rect2.Size.Y;
        var img = Image.Create(Width, Height, false, Image.Format.Rgba8);
        img.Fill(Colors.White);
        
        //处理边缘过渡
        HandlerTransition(roomInfo, img);
        
        Texture = ImageTexture.CreateFromImage(img);
    }
    
    public void Destroy()
    {
        if (IsDestroyed)
        {
            return;
        }

        IsDestroyed = true;
        QueueFree();
    }

    private void HandlerTransition(RoomInfo roomInfo, Image image)
    {
        var tileMap = GameApplication.Instance.World.TileRoot;
        var autoConfig = GameApplication.Instance.DungeonManager.AutoTileConfig;
        var wallCoord = autoConfig.WALL_BLOCK.AutoTileCoord;
        var (x, y) = roomInfo.Position;
        var (width, height) = roomInfo.Size;
        x -= 1;
        y -= 1;
        width += 2;
        height += 2;
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                var pos = new Vector2I(i + x, j + y);
                //说明是外层墙壁
                if (tileMap.GetCellAtlasCoords(GameConfig.TopMapLayer, pos) == wallCoord)
                {
                    //FillBlock(i, j, image);
                    var left = IsNotWallCell(tileMap, new Vector2I(pos.X + 1, pos.Y), wallCoord);
                    var right = IsNotWallCell(tileMap, new Vector2I(pos.X - 1, pos.Y), wallCoord);
                    var top = IsNotWallCell(tileMap, new Vector2I(pos.X, pos.Y + 1), wallCoord);
                    var down = IsNotWallCell(tileMap, new Vector2I(pos.X, pos.Y - 1), wallCoord);
                    var c = 0;
                    if (left) c++;
                    if (right) c++;
                    if (top) c++;
                    if (down) c++;
                    //判断方向
                    if ((left && right) || (top && down) || c > 2)
                    {
                        continue;
                    }
                    else if (left && top) //内轮廓左上
                    {
                        FillTransitionImage(i, j, image, _inLeftTopTransition);
                    }
                    else if (left && down) //内轮廓左下
                    {
                        FillTransitionImage(i, j, image, _inLeftDownTransition);
                    }
                    else if (right && top) //内轮廓右上
                    {
                        FillTransitionImage(i, j, image, _inRightTopTransition);
                    }
                    else if (right && down) //内轮廓右下
                    {
                        FillTransitionImage(i, j, image, _inRightDownTransition);
                    }
                    else if (left) //左
                    {
                        FillTransitionImage(i, j, image, _leftTransition);
                    }
                    else if (right) //右
                    {
                        FillTransitionImage(i, j, image, _rightTransition);
                    }
                    else if (top) //上
                    {
                        FillTransitionImage(i, j, image, _topTransition);
                    }
                    else if (down) //下
                    {
                        FillTransitionImage(i, j, image, _downTransition);
                    }
                    else if (IsNotWallCell(tileMap, new Vector2I(pos.X + 1, pos.Y + 1), wallCoord)) //外轮廓左上
                    {
                        FillTransitionImage(i, j, image, _leftTopTransition);
                    }
                    else if (IsNotWallCell(tileMap, new Vector2I(pos.X + 1, pos.Y - 1), wallCoord)) //外轮廓左下
                    {
                        FillTransitionImage(i, j, image, _leftDownTransition);
                    }
                    else if (IsNotWallCell(tileMap, new Vector2I(pos.X - 1, pos.Y + 1), wallCoord)) //外轮廓右上
                    {
                        FillTransitionImage(i, j, image, _rightTopTransition);
                    }
                    else if (IsNotWallCell(tileMap, new Vector2I(pos.X - 1, pos.Y - 1), wallCoord)) //外轮廓右下
                    {
                        FillTransitionImage(i, j, image, _rightDownTransition);
                    }
                    else //全黑
                    {
                        FillBlock(i, j, image);
                    }
                }
            }
        }
    }

    //填充一个16*16像素的区域
    private void FillBlock(int x, int y, Image image)
    {
        var endX = (x + 1) * GameConfig.TileCellSize;
        var endY = (y + 1) * GameConfig.TileCellSize;
        for (int i = x * GameConfig.TileCellSize; i < endX; i++)
        {
            for (int j = y * GameConfig.TileCellSize; j < endY; j++)
            {
                image.SetPixel(i, j, new Color(1, 1, 1, 0));
            }
        }
    }

    private void FillTransitionImage(int x, int y, Image image, Image transitionImage)
    {
        image.BlitRect(transitionImage,
            new Rect2I(Vector2I.Zero, 16, 16),
            new Vector2I(x * GameConfig.TileCellSize, y * GameConfig.TileCellSize)
        );
    }

    //判断是否是墙壁
    private bool IsNotWallCell(TileMap tileMap, Vector2I pos, Vector2I wallCoord)
    {
        return tileMap.GetCellAtlasCoords(GameConfig.TopMapLayer, pos) != wallCoord &&
               tileMap.GetCellAtlasCoords(GameConfig.MiddleMapLayer, pos) != wallCoord &&
               (tileMap.GetCellSourceId(GameConfig.TopMapLayer, pos) != -1 ||
                tileMap.GetCellSourceId(GameConfig.MiddleMapLayer, pos) != -1);
    }

    //判断是否是任意类型的图块
    private bool IsAnyCell(TileMap tileMap, Vector2I pos)
    {
        return tileMap.GetCellSourceId(GameConfig.FloorMapLayer, pos) != -1 ||
               tileMap.GetCellSourceId(GameConfig.MiddleMapLayer, pos) != -1 ||
               tileMap.GetCellSourceId(GameConfig.TopMapLayer, pos) != -1 ||
               tileMap.GetCellSourceId(GameConfig.AisleFloorMapLayer, pos) != -1;
    }
}