diff --git a/DungeonShooting_Godot/project.godot b/DungeonShooting_Godot/project.godot index 3062ae5..5da264c 100644 --- a/DungeonShooting_Godot/project.godot +++ b/DungeonShooting_Godot/project.godot @@ -11,7 +11,7 @@ [application] config/name="DungeonShooting" -run/main_scene="res://scene/test/TestMask2.tscn" +run/main_scene="res://scene/Main.tscn" config/features=PackedStringArray("4.2", "C#") config/icon="res://icon.png" diff --git a/DungeonShooting_Godot/resource/test/Brush3.png b/DungeonShooting_Godot/resource/test/Brush3.png new file mode 100644 index 0000000..c77fef5 --- /dev/null +++ b/DungeonShooting_Godot/resource/test/Brush3.png Binary files differ diff --git a/DungeonShooting_Godot/resource/test/Brush3.png.import b/DungeonShooting_Godot/resource/test/Brush3.png.import new file mode 100644 index 0000000..5c25409 --- /dev/null +++ b/DungeonShooting_Godot/resource/test/Brush3.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://jnx4wfn5hu3u" +path="res://.godot/imported/Brush3.png-c626025ee33281acc6b1ad59b29276c7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://resource/test/Brush3.png" +dest_files=["res://.godot/imported/Brush3.png-c626025ee33281acc6b1ad59b29276c7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs index e4b4f57..092eaf0 100644 --- a/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs +++ b/DungeonShooting_Godot/src/framework/activity/ActivityObject.cs @@ -1669,7 +1669,7 @@ _processingBecomesStaticImage = true; EnableBehavior = false; var roomInfo = AffiliationArea.RoomInfo; - var position = roomInfo.ToImageCanvasPosition(GlobalPosition); + var position = roomInfo.ToCanvasPosition(GlobalPosition); roomInfo.StaticImageCanvas.DrawActivityObjectInCanvas(this, position.X, position.Y, () => { Destroy(); diff --git a/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs b/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs index 8f42f8b..3587e56 100644 --- a/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs +++ b/DungeonShooting_Godot/src/framework/map/liquid/LiquidCanvas.cs @@ -31,9 +31,14 @@ private int _executeIndex = -1; //用于记录补间操作下有变动的像素点 private List _tempList = new List(); + //记录是否有像素点发生变动 + private bool _changeFlag = false; + //所属房间 + private RoomInfo _roomInfo; - public void Init(int width, int height) + public LiquidCanvas(RoomInfo roomInfo, int width, int height) { + _roomInfo = roomInfo; Centered = false; Material = ResourceManager.Load(ResourcePath.resource_material_Sawtooth_tres); @@ -58,6 +63,8 @@ public override void _Process(double delta) { + //这里待优化, 应该每次绘制都将像素点放入 _tempList 中, 然后帧结束再统一提交 + //更新消除逻辑 if (_cacheImagePixels.Count > 0) { @@ -117,13 +124,26 @@ } } } - - _texture.Update(_image); + + if (_changeFlag) + { + _texture.Update(_image); + _changeFlag = false; + } + _runTime += (float)delta; } + + /// + /// 将画布外的坐标转为画布内的坐标 + /// + public Vector2I ToLiquidCanvasPosition(Vector2 position) + { + return (_roomInfo.ToCanvasPosition(position) / CanvasScale).AsVector2I(); + } /// - /// 根据画笔数据在画布上绘制液体 + /// 根据画笔数据在画布上绘制液体, 转换坐标请调用 ToLiquidCanvasPosition() 函数 /// /// 画笔数据 /// 上一帧坐标, 相对于画布坐标, 改参数用于两点距离较大时执行补间操作, 如果传 null, 则不会进行补间 @@ -189,6 +209,7 @@ foreach (var imagePixel in _tempList) { + _changeFlag = true; _image.SetPixel(imagePixel.X, imagePixel.Y, imagePixel.Color); imagePixel.TempFlag = false; } @@ -197,7 +218,7 @@ return; } } - + foreach (var brushPixel in brush.Pixels) { var brushPos = RotatePixels(brushPixel.X, brushPixel.Y, center.X, center.Y, rotation); @@ -205,6 +226,7 @@ var y = pos.Y + brushPos.Y; if (x >= 0 && x < canvasWidth && y >= 0 && y < canvasHeight) { + _changeFlag = true; var temp = SetPixelData(x, y, brushPixel); _image.SetPixel(x, y, temp.Color); } @@ -262,12 +284,14 @@ if (imagePixel.Color.A <= 0) //完全透明了 { + _changeFlag = true; _image.SetPixel(imagePixel.X, imagePixel.Y, new Color(0, 0, 0, 0)); imagePixel.IsRun = false; return true; } else { + _changeFlag = true; _image.SetPixel(imagePixel.X, imagePixel.Y, imagePixel.Color); imagePixel.TempTime = _runTime; } diff --git a/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs b/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs index 39bb1f9..7929376 100644 --- a/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs +++ b/DungeonShooting_Godot/src/framework/map/room/RoomInfo.cs @@ -86,9 +86,9 @@ public ImageCanvas StaticImageCanvas; /// - /// 房间坐标相对于画布坐标偏移量, 单位: 像素 + /// 液体画布 /// - public Vector2I RoomOffset; + public LiquidCanvas LiquidCanvas; /// /// 房间迷雾 @@ -96,9 +96,19 @@ public FogMask RoomFogMask; /// + /// 房间坐标相对于画布坐标偏移量, 单位: 像素 + /// + public Vector2I RoomOffset { get; private set; } + + /// /// 房间算上连接通道所占用的区域 /// - public Rect2I OuterRange { get; private set; } + public Rect2I OuterRect { get; private set; } + + /// + /// 画布占用区域 + /// + public Rect2I CanvasRect { get; private set; } /// /// 是否处于闭关状态, 也就是房间门没有主动打开 @@ -122,7 +132,7 @@ /// /// 重新计算占用的区域 /// - public void CalcOuterRange() + public void CalcRange() { var worldPos = GetWorldPosition(); var pos = new Vector2I(worldPos.X, worldPos.Y); @@ -205,8 +215,16 @@ break; } } + + OuterRect = new Rect2I(minX, minY, maxX - minX, maxY - minY); + + var cMinX = minX - GameConfig.TileCellSize; + var cMinY = minY - GameConfig.TileCellSize; + var cMaxX = maxX + GameConfig.TileCellSize; + var cMaxY = maxY + GameConfig.TileCellSize; + CanvasRect = new Rect2I(cMinX, cMinY, cMaxX - cMinX, cMaxY - cMinY); - OuterRange = new Rect2I(minX, minY, maxX - minX, maxY - minY); + RoomOffset = new Vector2I(worldPos.X - cMinX, worldPos.Y - cMinY); } /// @@ -289,9 +307,9 @@ /// /// 将世界坐标转为画布下的坐标 /// - public Vector2 ToImageCanvasPosition(Vector2 pos) + public Vector2 ToCanvasPosition(Vector2 pos) { - return pos - StaticImageCanvas.Position; + return pos - CanvasRect.Position; } public void Destroy() @@ -327,8 +345,14 @@ { StaticImageCanvas.Destroy(); } + + //销毁液体画布 + if (LiquidCanvas != null) + { + LiquidCanvas.Destroy(); + } - // + //销毁静态精灵节点 if (StaticSprite != null) { StaticSprite.Destroy(); diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs index 276b27d..c2014f7 100644 --- a/DungeonShooting_Godot/src/game/GameApplication.cs +++ b/DungeonShooting_Godot/src/game/GameApplication.cs @@ -106,7 +106,7 @@ //随机化种子 //GD.Randomize(); //固定帧率 - Engine.MaxFps = TargetFps; + //Engine.MaxFps = TargetFps; //调试绘制开关 ActivityObject.IsDebug = false; //Engine.TimeScale = 0.2f; diff --git a/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs b/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs index 065162f..c3285e5 100644 --- a/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs +++ b/DungeonShooting_Godot/src/game/activity/bullet/normal/BoomBullet.cs @@ -76,7 +76,7 @@ if (AffiliationArea != null) { var texture = ResourceManager.LoadTexture2D(ResourcePath.resource_sprite_effects_explode_Explode_pit0001_png); - var tempPos = AffiliationArea.RoomInfo.ToImageCanvasPosition(pos); + var tempPos = AffiliationArea.RoomInfo.ToCanvasPosition(pos); AffiliationArea.RoomInfo.StaticImageCanvas.DrawImageInCanvas( texture, null, tempPos.X, tempPos.Y, Utils.Random.RandomRangeInt(0, 360), texture.GetWidth() / 2, texture.GetHeight() / 2, false diff --git a/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs b/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs index 62352c2..e6fc35e 100644 --- a/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs +++ b/DungeonShooting_Godot/src/game/activity/role/enemy/NoWeaponEnemy.cs @@ -8,11 +8,28 @@ [Tool] public partial class NoWeaponEnemy : Enemy { + private Vector2I? _prevPosition = null; + private BrushImageData _brushData3; + public override void OnInit() { base.OnInit(); NoWeaponAttack = true; AnimationPlayer.AnimationFinished += OnAnimationFinished; + + _brushData3 = new BrushImageData(ResourceManager.LoadTexture2D(ResourcePath.resource_test_Brush3_png).GetImage(), 3, 0.7f, 4, 0.2f); + } + + protected override void Process(float delta) + { + base.Process(delta); + + if (AffiliationArea != null) + { + var pos = AffiliationArea.RoomInfo.LiquidCanvas.ToLiquidCanvasPosition(Position); + AffiliationArea.RoomInfo.LiquidCanvas.DrawBrush(_brushData3, _prevPosition, pos, 0); + _prevPosition = pos; + } } public override void Attack() diff --git a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs index 72c65e9..ee136b2 100644 --- a/DungeonShooting_Godot/src/game/activity/role/player/Player.cs +++ b/DungeonShooting_Godot/src/game/activity/role/player/Player.cs @@ -28,6 +28,9 @@ //翻滚冷却计时器 private float _rollCoolingTimer = 0; + private Vector2I? _prevPosition = null; + private BrushImageData _brushData2; + /// /// 设置当前操作的玩家对象 /// @@ -78,6 +81,8 @@ StateController.ChangeStateInstant(PlayerStateEnum.Idle); //InitSubLine(); + + _brushData2 = new BrushImageData(ResourceManager.LoadTexture2D(ResourcePath.resource_test_Brush2_png).GetImage(), 2, 0.5f, 5, 0.2f); } protected override RoleState OnCreateRoleState() @@ -226,6 +231,19 @@ { TipRoot.Scale = new Vector2(-1, 1); } + + if (AffiliationArea != null) + { + var pos = AffiliationArea.RoomInfo.LiquidCanvas.ToLiquidCanvasPosition(Position); + AffiliationArea.RoomInfo.LiquidCanvas.DrawBrush(_brushData2, _prevPosition, pos, 0); + _prevPosition = pos; + } + } + + protected override void OnAffiliationChange(AffiliationArea prevArea) + { + _prevPosition = null; + base.OnAffiliationChange(prevArea); } protected override void OnPickUpWeapon(Weapon weapon) diff --git a/DungeonShooting_Godot/src/game/manager/ResourcePath.cs b/DungeonShooting_Godot/src/game/manager/ResourcePath.cs index 1543b62..2cf7f97 100644 --- a/DungeonShooting_Godot/src/game/manager/ResourcePath.cs +++ b/DungeonShooting_Godot/src/game/manager/ResourcePath.cs @@ -372,6 +372,7 @@ public const string resource_spriteFrames_weapon_Weapon0009_tres = "res://resource/spriteFrames/weapon/Weapon0009.tres"; public const string resource_test_Brush1_png = "res://resource/test/Brush1.png"; public const string resource_test_Brush2_png = "res://resource/test/Brush2.png"; + public const string resource_test_Brush3_png = "res://resource/test/Brush3.png"; public const string resource_theme_mainTheme_tres = "res://resource/theme/mainTheme.tres"; public const string resource_theme_theme1_tres = "res://resource/theme/theme1.tres"; public const string scene_Main_tscn = "res://scene/Main.tscn"; diff --git a/DungeonShooting_Godot/src/game/room/DungeonManager.cs b/DungeonShooting_Godot/src/game/room/DungeonManager.cs index 7e70905..57b3363 100644 --- a/DungeonShooting_Godot/src/game/room/DungeonManager.cs +++ b/DungeonShooting_Godot/src/game/room/DungeonManager.cs @@ -316,7 +316,7 @@ // 初始化房间 private void InitRoom(RoomInfo roomInfo) { - roomInfo.CalcOuterRange(); + roomInfo.CalcRange(); //挂载房间导航区域 MountNavFromRoomInfo(roomInfo); //创建门 @@ -325,8 +325,10 @@ CreateRoomAffiliation(roomInfo); //创建 RoomStaticSprite CreateRoomStaticSprite(roomInfo); + //创建液体区域 + CreateRoomLiquidCanvas(roomInfo); //创建静态精灵画布 - CreateRoomStaticSpriteCanvas(roomInfo); + CreateRoomStaticImageCanvas(roomInfo); //创建迷雾遮罩 CreateRoomFogMask(roomInfo); } @@ -419,21 +421,26 @@ World.Current.StaticSpriteRoot.AddChild(spriteRoot); roomInfo.StaticSprite = spriteRoot; } - - //创建静态精灵画布 - private void CreateRoomStaticSpriteCanvas(RoomInfo roomInfo) + + + //创建液体画布 + private void CreateRoomLiquidCanvas(RoomInfo roomInfo) { - var worldPos = roomInfo.GetWorldPosition(); - var rect = roomInfo.OuterRange; + var rect = roomInfo.CanvasRect; - var minX = rect.Position.X - GameConfig.TileCellSize; - var minY = rect.Position.Y - GameConfig.TileCellSize; - var maxX = rect.End.X + GameConfig.TileCellSize; - var maxY = rect.End.Y + GameConfig.TileCellSize; + var liquidCanvas = new LiquidCanvas(roomInfo, rect.Size.X, rect.Size.Y); + liquidCanvas.Position = rect.Position; + roomInfo.LiquidCanvas = liquidCanvas; + roomInfo.StaticSprite.AddChild(liquidCanvas); + } - var canvasSprite = new ImageCanvas(maxX - minX, maxY - minY); - canvasSprite.Position = new Vector2I(minX, minY); - roomInfo.RoomOffset = new Vector2I(worldPos.X - minX, worldPos.Y - minY); + //创建静态图像画布 + private void CreateRoomStaticImageCanvas(RoomInfo roomInfo) + { + var rect = roomInfo.CanvasRect; + + var canvasSprite = new ImageCanvas(rect.Size.X, rect.Size.Y); + canvasSprite.Position = rect.Position; roomInfo.StaticImageCanvas = canvasSprite; roomInfo.StaticSprite.AddChild(canvasSprite); } diff --git a/DungeonShooting_Godot/src/test/TestMask2.cs b/DungeonShooting_Godot/src/test/TestMask2.cs index f9b6131..d3388b7 100644 --- a/DungeonShooting_Godot/src/test/TestMask2.cs +++ b/DungeonShooting_Godot/src/test/TestMask2.cs @@ -29,9 +29,8 @@ //Engine.MaxFps = 5; _brushData1 = new BrushImageData(Brush1.GetImage(), 1, 0.5f, 5, 0.1f); _brushData2 = new BrushImageData(Brush2.GetImage(), 2, 0.5f, 5, 0.2f); - _liquidCanvas = new LiquidCanvas(); + _liquidCanvas = new LiquidCanvas(null, (int)(Size.X / LiquidCanvas.CanvasScale), (int)(Size.X / LiquidCanvas.CanvasScale)); GetNode("SubViewport").AddChild(_liquidCanvas); - _liquidCanvas.Init((int)(Size.X / LiquidCanvas.CanvasScale), (int)(Size.X / LiquidCanvas.CanvasScale)); } public override void _Process(double delta)