From 8df4ebb6d5efbed74f8aa44213436fd8c1489bdd Mon Sep 17 00:00:00 2001 From: hzhang Date: Wed, 26 Feb 2025 20:17:37 +0000 Subject: [PATCH] add: Selectable Tile Map Layer/Mouse Controlled Camera --- .../Nodes/Cameras/MouseControlledCamera.cs | 48 +++++++++++++++++++ .../GlobalClasses/Nodes/Scenes/CameraScene.cs | 19 +++++--- .../Scenes/MouseControlledCameraScene.cs | 24 ++++++++++ .../TileMapLayers/SelectableTileMapLayer.cs | 42 ++++++++++++++++ src/Extensions/LinqExtensions.cs | 12 +++++ src/Utils.cs | 8 +++- 6 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 Package/embedded/GlobalClasses/Nodes/Cameras/MouseControlledCamera.cs create mode 100644 Package/embedded/GlobalClasses/Nodes/Scenes/MouseControlledCameraScene.cs create mode 100644 Package/embedded/GlobalClasses/Nodes/TileMapLayers/SelectableTileMapLayer.cs create mode 100644 src/Extensions/LinqExtensions.cs diff --git a/Package/embedded/GlobalClasses/Nodes/Cameras/MouseControlledCamera.cs b/Package/embedded/GlobalClasses/Nodes/Cameras/MouseControlledCamera.cs new file mode 100644 index 0000000..5d47ea6 --- /dev/null +++ b/Package/embedded/GlobalClasses/Nodes/Cameras/MouseControlledCamera.cs @@ -0,0 +1,48 @@ + +using Godot; +using Polonium.Attributes; + +// ReSharper disable once CheckNamespace +namespace GlobalClasses; +[ProxyNode] +[GlobalClass] +[Tool] +public partial class MouseControlledCamera : Camera2D +{ + private Vector2 DragStartPosition { get; set; } + private bool IsDragging { get; set; } + [Signal] + public delegate void ZoomInEventHandler(); + [Signal] + public delegate void ZoomOutEventHandler(); + + [Export] + public MouseButton DragButton { get; set; } = MouseButton.Middle; + + public override void _UnhandledInput(InputEvent @event) + { + if (@event is InputEventMouseButton mouseButtonEvent) + { + if(mouseButtonEvent.ButtonIndex == MouseButton.WheelUp) + EmitSignalZoomIn(); + else if(mouseButtonEvent.ButtonIndex == MouseButton.WheelDown) + EmitSignalZoomOut(); + else if (mouseButtonEvent.ButtonIndex == DragButton) + { + IsDragging = mouseButtonEvent.Pressed; + if(IsDragging) + DragStartPosition = GetGlobalMousePosition(); + } + } + else if (@event is InputEventMouseMotion mouseMotionEvent && IsDragging) + { + Vector2 mousePos = GetGlobalMousePosition(); + Vector2 offset = DragStartPosition - mousePos; + Position += offset; + DragStartPosition = mousePos; + } + + + } + +} \ No newline at end of file diff --git a/Package/embedded/GlobalClasses/Nodes/Scenes/CameraScene.cs b/Package/embedded/GlobalClasses/Nodes/Scenes/CameraScene.cs index 6e0ad7a..639f329 100644 --- a/Package/embedded/GlobalClasses/Nodes/Scenes/CameraScene.cs +++ b/Package/embedded/GlobalClasses/Nodes/Scenes/CameraScene.cs @@ -7,12 +7,12 @@ namespace GlobalClasses; [Tool] public partial class CameraScene : Scene { - private Camera2D Camera { get; set; } - + protected Camera2D Camera { get; set; } + [Export] public float MaxZoom { get; set; } - + [Export] public float MinZoom { get; set; } - + [Export] public float ZoomRate { get; set; } private float Zoom @@ -26,13 +26,18 @@ public partial class CameraScene : Scene { } - public sealed override void _Ready() + protected virtual void _Ready_() { Camera = GetNode("Camera"); + } + + public sealed override void _Ready() + { + _Ready_(); __Ready(); base._Ready(); } - protected void ZoomIn() => Zoom = Mathf.Max(Zoom * (1 + ZoomRate), MaxZoom); - protected void ZoomOut() => Zoom = Mathf.Min(Zoom * (1 - ZoomRate), MinZoom); + protected void ZoomIn() => Zoom = Mathf.Min(Zoom * (1 + ZoomRate), MaxZoom); + protected void ZoomOut() => Zoom = Mathf.Max(Zoom * (1 - ZoomRate), MinZoom); protected void ZoomAt(Vector2 pos) => Camera.Position = pos; } diff --git a/Package/embedded/GlobalClasses/Nodes/Scenes/MouseControlledCameraScene.cs b/Package/embedded/GlobalClasses/Nodes/Scenes/MouseControlledCameraScene.cs new file mode 100644 index 0000000..323b7f4 --- /dev/null +++ b/Package/embedded/GlobalClasses/Nodes/Scenes/MouseControlledCameraScene.cs @@ -0,0 +1,24 @@ + +using Godot; +using Polonium.Attributes; +// ReSharper disable once CheckNamespace + +namespace GlobalClasses; +[ProxyNode] +[GlobalClass] +[Tool] +public partial class MouseControlledCameraScene : CameraScene +{ + protected new MouseControlledCamera Camera + { + get => base.Camera as MouseControlledCamera; + set => base.Camera = value; + } + + protected sealed override void _Ready_() + { + Camera = GetNode("Camera"); + Camera.ZoomIn += ZoomIn; + Camera.ZoomOut += ZoomOut; + } +} \ No newline at end of file diff --git a/Package/embedded/GlobalClasses/Nodes/TileMapLayers/SelectableTileMapLayer.cs b/Package/embedded/GlobalClasses/Nodes/TileMapLayers/SelectableTileMapLayer.cs new file mode 100644 index 0000000..3efa796 --- /dev/null +++ b/Package/embedded/GlobalClasses/Nodes/TileMapLayers/SelectableTileMapLayer.cs @@ -0,0 +1,42 @@ +using Godot; +using Polonium.Attributes; + +namespace GlobalClasses; +[ProxyNode] +[GlobalClass] +[Tool] +public partial class SelectableTileMapLayer : TileMapLayer +{ + [Signal] + public delegate void CellSelectedEventHandler(Vector2I pos); + + [Signal] + public delegate void CellEnteredEventHandler(Vector2I pos); + private Vector2I HoveredCell { get; set; } = new Vector2I(-1, -1); + + public sealed override void _Process(double delta) + { + + Vector2 mousePos = GetGlobalMousePosition(); + Vector2 localMousePos = ToLocal(mousePos); + Vector2I cell = LocalToMap(localMousePos); + if(cell != HoveredCell) + { + EmitSignalCellEntered(cell); + HoveredCell = cell; + } + __Process(delta); + base._Process(delta); + } + + public override void _UnhandledInput(InputEvent @event) + { + if (@event is InputEventMouseButton mouseEvent) + if (mouseEvent.ButtonIndex == MouseButton.Left && mouseEvent.Pressed) + EmitSignalCellSelected(HoveredCell); + } + [ProxyMethod] + public virtual void __Process(double delta) + { + } +} \ No newline at end of file diff --git a/src/Extensions/LinqExtensions.cs b/src/Extensions/LinqExtensions.cs new file mode 100644 index 0000000..453d701 --- /dev/null +++ b/src/Extensions/LinqExtensions.cs @@ -0,0 +1,12 @@ +using Godot; + +namespace Polonium.Extensions; + +public static class LinqExtensions +{ + public static T RandomSelect(this IEnumerable source) + { + T[] s = source.ToArray(); + return s[GD.Randi() % s.Length]; + } +} \ No newline at end of file diff --git a/src/Utils.cs b/src/Utils.cs index 24eab63..5c3b7bf 100644 --- a/src/Utils.cs +++ b/src/Utils.cs @@ -33,8 +33,13 @@ public static class Utils { if (!fname.EndsWith(".png")) continue; - AnimatedTextureCache[path].SetFrameTexture(f, ResourceLoader.Load(fname)); + AnimatedTextureCache[path].SetFrameTexture(f, ResourceLoader.Load($"{path}/{fname}")); + f += 1; } + + AnimatedTextureCache[path].SetFrames(f + 1); + AnimatedTextureCache[path].SetOneShot(false); + AnimatedTextureCache[path].SetSpeedScale(4); } return AnimatedTextureCache[path]; @@ -44,6 +49,7 @@ public static class Utils return null; } } + } #pragma warning restore CS0618 #pragma warning restore CS0168 \ No newline at end of file