using System; using System.Collections; using Godot; /// <summary> /// 迷雾遮罩 /// </summary> public partial class FogMask : 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 long _cid = -1; 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="position">起始位置, 单位: 格</param> /// <param name="size">大小, 单位: 格</param> /// <param name="alpha">透明度</param> public void InitFog(Vector2I position, Vector2I size, float alpha = 0) { if (_init) { return; } InitSprite(); GlobalPosition = new Vector2( (position.X + size.X / 2f) * GameConfig.TileCellSize, (position.Y + size.Y / 2f) * GameConfig.TileCellSize ); //创建光纹理 Width = (size.X + 2) * GameConfig.TileCellSize; Height = (size.Y + 2) * GameConfig.TileCellSize; var img = Image.Create(Width, Height, false, Image.Format.Rgba8); img.Fill(Colors.White); //处理边缘过渡 HandlerTransition(position, size, img); Texture = ImageTexture.CreateFromImage(img); var c = Color; c.A = alpha; Color = c; } /// <summary> /// 使颜色的 alpha 通道过渡到指定的值 /// </summary> /// <param name="targetAlpha">透明度值</param> /// <param name="time">过渡时间</param> public void TransitionAlpha(float targetAlpha, float time) { if (_cid >= 0) { World.Current.StopCoroutine(_cid); } _cid = World.Current.StartCoroutine(RunTransitionAlpha(targetAlpha, time)); } private IEnumerator RunTransitionAlpha(float targetAlpha, float time) { var originColor = Color; var a = originColor.A; var delta = Mathf.Abs(a - targetAlpha) / time; while (Math.Abs(a - targetAlpha) > 0.001f) { a = Mathf.MoveToward(a, targetAlpha, delta * (float)World.Current.GetProcessDeltaTime()); Color = new Color(1, 1, 1, a); yield return null; } _cid = -1; } public void Destroy() { if (IsDestroyed) { return; } IsDestroyed = true; QueueFree(); } private void HandlerTransition(Vector2I position, Vector2I size, Image image) { var tileMap = GameApplication.Instance.World.TileRoot; var autoConfig = GameApplication.Instance.DungeonManager.AutoTileConfig; var wallCoord = autoConfig.WALL_BLOCK.AutoTileCoord; var (x, y) = position; var (width, height) = 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) { var left = IsEmptyCell(tileMap, new Vector2I(pos.X - 1, pos.Y)); var right = IsEmptyCell(tileMap, new Vector2I(pos.X + 1, pos.Y)); var top = IsEmptyCell(tileMap, new Vector2I(pos.X, pos.Y - 1)); var down = IsEmptyCell(tileMap, new Vector2I(pos.X, pos.Y + 1)); var leftTop = IsEmptyCell(tileMap, new Vector2I(pos.X - 1, pos.Y - 1)); var leftDown = IsEmptyCell(tileMap, new Vector2I(pos.X - 1, pos.Y + 1)); var rightTop = IsEmptyCell(tileMap, new Vector2I(pos.X + 1, pos.Y - 1)); var rightDown = IsEmptyCell(tileMap, new Vector2I(pos.X + 1, pos.Y + 1)); if (!left && !right && !top && !down && !leftTop && !leftDown && !rightTop && !rightDown) { continue; } else if (leftTop && left && top) //外轮廓, 左上 { FillTransitionImage(i, j, image, _leftTopTransition); } else if (leftDown && left && down) //外轮廓, 左下 { FillTransitionImage(i, j, image, _leftDownTransition); } else if (rightTop && right && top) //外轮廓, 右上 { FillTransitionImage(i, j, image, _rightTopTransition); } else if (rightDown && right && down) //外轮廓, 右下 { FillTransitionImage(i, j, image, _rightDownTransition); } //------------------------- 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 (leftTop) //内轮廓, 左上 { FillTransitionImage(i, j, image, _inLeftTopTransition); } else if (leftDown) //内轮廓, 左下 { FillTransitionImage(i, j, image, _inLeftDownTransition); } else if (rightTop) //内轮廓, 右上 { FillTransitionImage(i, j, image, _inRightTopTransition); } else if (rightDown) //内轮廓, 右下 { FillTransitionImage(i, j, image, _inRightDownTransition); } //------------------------ 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 IsEmptyCell(TileMap tileMap, Vector2I pos) { return tileMap.GetCellSourceId(GameConfig.TopMapLayer, pos) == -1 && tileMap.GetCellSourceId(GameConfig.MiddleMapLayer, pos) == -1; } //判断是否是墙壁 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; } }