From ee29207d71709cfa831d65160b4c833a8c047e1c Mon Sep 17 00:00:00 2001 From: WS-3917 Date: Sat, 3 May 2025 22:31:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Objects/UI/Joystick.tscn | 35 ++++++ Objects/UI/TouchControls.tscn | 45 ++++---- Scripts/UI/Joystick.cs | 66 +++++------ Scripts/UI/TouchControls.cs | 202 +++++++++++++++++----------------- 4 files changed, 192 insertions(+), 156 deletions(-) create mode 100644 Objects/UI/Joystick.tscn diff --git a/Objects/UI/Joystick.tscn b/Objects/UI/Joystick.tscn new file mode 100644 index 0000000..61da19a --- /dev/null +++ b/Objects/UI/Joystick.tscn @@ -0,0 +1,35 @@ +[gd_scene load_steps=3 format=3 uid="uid://joystick"] + +[ext_resource type="Texture2D" path="res://Sprites/Menus/Mobile/JoystickBase.png" id=1] +[ext_resource type="Texture2D" path="res://Sprites/Menus/Mobile/JoystickHandle.png" id=2] + +[node name="Joystick" type="Control" script="res://Scripts/UI/Joystick.cs"] +anchor_right = 0 +anchor_bottom = 0 +offset_right = 200 +offset_bottom = 200 +mouse_filter = 2 # Ignore mouse input + +[node name="BaseCircle" type="TextureRect" parent="."] +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -100 +offset_top = -100 +offset_right = 100 +offset_bottom = 100 +texture = ExtResource(1) +stretch_mode = 6 # Keep aspect centered + +[node name="HandleCircle" type="TextureRect" parent="."] +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -40 +offset_top = -40 +offset_right = 40 +offset_bottom = 40 +texture = ExtResource(2) +stretch_mode = 6 # Keep aspect centered diff --git a/Objects/UI/TouchControls.tscn b/Objects/UI/TouchControls.tscn index 1574fcb..8b50625 100644 --- a/Objects/UI/TouchControls.tscn +++ b/Objects/UI/TouchControls.tscn @@ -6,28 +6,6 @@ [node name="TouchControls" type="CanvasLayer"] script = ExtResource("1_42104") -[node name="Joystick" type="Control" parent="."] -layout_mode = 3 -anchors_preset = 0 -offset_right = 40.0 -offset_bottom = 40.0 -script = ExtResource("2_fufkg") - -[node name="OuterCircle" type="TextureRect" parent="Joystick"] -layout_mode = 0 -offset_right = 40.0 -offset_bottom = 40.0 - -[node name="DeadzoneCircle" type="TextureRect" parent="Joystick"] -layout_mode = 0 -offset_right = 40.0 -offset_bottom = 40.0 - -[node name="HandleCircle" type="TextureRect" parent="Joystick"] -layout_mode = 0 -offset_right = 40.0 -offset_bottom = 40.0 - [node name="Buttons" type="Control" parent="."] layout_mode = 3 anchors_preset = 0 @@ -48,3 +26,26 @@ offset_bottom = 40.0 layout_mode = 0 offset_right = 40.0 offset_bottom = 40.0 + +[node name="Joystick" type="Control" parent="."] +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 +script = ExtResource("2_fufkg") + +[node name="OuterCircle" type="TextureRect" parent="Joystick"] +layout_mode = 0 +offset_top = -1.0 +offset_right = 40.0 +offset_bottom = 39.0 + +[node name="DeadzoneCircle" type="TextureRect" parent="Joystick"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 + +[node name="HandleCircle" type="TextureRect" parent="Joystick"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 diff --git a/Scripts/UI/Joystick.cs b/Scripts/UI/Joystick.cs index ed325f1..61027a7 100644 --- a/Scripts/UI/Joystick.cs +++ b/Scripts/UI/Joystick.cs @@ -3,57 +3,57 @@ using System; public partial class Joystick : Control { - private Vector2 touchStartPos = Vector2.Zero; - private Vector2 currentPos = Vector2.Zero; - private int fingerId = -1; + private Vector2 _startTouchPos = Vector2.Zero; + private Vector2 _currentTouchPos = Vector2.Zero; + private bool _touching = false; - [Export] public float DeadzoneRadius = 40f; - [Export] public float MaxRadius = 120f; + [Export] public float DeadzoneRadius = 30f; + [Export] public float MaxRadius = 90f; - public override void _Input(InputEvent @event) + public override void _GuiInput(InputEvent @event) { if (@event is InputEventScreenTouch touch) { - if (touch.Pressed && fingerId == -1 && GetGlobalRect().HasPoint(touch.Position)) + if (touch.Pressed) { - fingerId = touch.Index; - touchStartPos = touch.Position; - currentPos = touch.Position; + _touching = true; + _startTouchPos = touch.Position; + _currentTouchPos = touch.Position; } - else if (!touch.Pressed && touch.Index == fingerId) + else { - fingerId = -1; - currentPos = touchStartPos; + _touching = false; } } - else if (@event is InputEventScreenDrag drag && drag.Index == fingerId) + else if (@event is InputEventScreenDrag drag && _touching) { - currentPos = drag.Position; + _currentTouchPos = drag.Position; } } - public override void _Process(double delta) - { - Vector2 localOffset = currentPos - touchStartPos; - if (localOffset.Length() > MaxRadius) - localOffset = localOffset.Normalized() * MaxRadius; - - // 更新手柄图形位置 - var handle = GetNode("HandleCircle"); - handle.Position = localOffset; - - QueueRedraw(); - } - public Vector2 GetDirection() { - if (fingerId == -1) + if (!_touching) return Vector2.Zero; + + Vector2 offset = _currentTouchPos - _startTouchPos; + if (offset.Length() < DeadzoneRadius) return Vector2.Zero; - Vector2 delta = currentPos - touchStartPos; - if (delta.Length() < DeadzoneRadius) - return Vector2.Zero; + return offset.Normalized() * Mathf.Min(offset.Length(), MaxRadius); + } - return delta.Normalized(); + public override void _Draw() + { + Vector2 center = new Vector2(0, 0); + Vector2 handleOffset = _touching ? (_currentTouchPos - _startTouchPos).Normalized() * Mathf.Min((_currentTouchPos - _startTouchPos).Length(), MaxRadius) : Vector2.Zero; + + DrawCircle(center, MaxRadius, new Color(1, 1, 1, 1), false); + DrawCircle(center, DeadzoneRadius, new Color(1, 1, 0, 1), false); + DrawCircle(center + handleOffset, DeadzoneRadius, new Color(1, 1, 1, 0.3f), false); // 当前触点 + } + + public override void _Process(double delta) + { + QueueRedraw(); } } diff --git a/Scripts/UI/TouchControls.cs b/Scripts/UI/TouchControls.cs index 848b5a4..e84e57c 100644 --- a/Scripts/UI/TouchControls.cs +++ b/Scripts/UI/TouchControls.cs @@ -1,110 +1,110 @@ -using Godot; -using System; + using Godot; + using System; -public partial class TouchControls : CanvasLayer -{ - public override void _Ready() + public partial class TouchControls : CanvasLayer { - // 仅在 Android 平台启用 - //if (OS.GetName() != "Android") - //{ - //QueueFree(); - //return; - //} - SetButtonTextures(); - SetupButtonBindings(); - UpdateButtonPositions(); // 设置初始位置 - } - - public override void _Process(double delta) - { - Vector2 dir = GetNode("Joystick").GetDirection(); - UpdateDirectionInput(dir); - } - - private void SetButtonTextures() - { - string basePath = "res://Sprites/Menus/Mobile/"; - GetNode("Buttons/ButtonZ").TextureNormal = GD.Load(basePath + "ButtonZ.png"); - GetNode("Buttons/ButtonX").TextureNormal = GD.Load(basePath + "ButtonX.png"); - GetNode("Buttons/ButtonC").TextureNormal = GD.Load(basePath + "ButtonC.png"); - } - - private void SetupButtonBindings() - { - BindButton("Buttons/ButtonZ", "Confirm"); - BindButton("Buttons/ButtonX", "Cancel"); - BindButton("Buttons/ButtonC", "Menu"); - } - - private void BindButton(string path, string actionName) - { - var button = GetNode(path); - button.Modulate = new Color(1, 1, 1, 0.5f); // 初始透明度 - - button.Pressed += () => + public override void _Ready() { - Input.ActionPress(actionName); - button.Modulate = new Color(1, 1, 1, 1); // 按下全不透明 - }; + // 仅在 Android 平台启用 + if (OS.GetName() != "Android") + { + QueueFree(); + return; + } + SetButtonTextures(); + SetupButtonBindings(); + UpdateButtonPositions(); // 设置初始位置 + } - button.ButtonUp += () => + public override void _Process(double delta) { - Input.ActionRelease(actionName); - button.Modulate = new Color(1, 1, 1, 0.5f); // 松开恢复 - }; - } + Vector2 dir = GetNode("Joystick").GetDirection(); + UpdateDirectionInput(dir); + } - private void UpdateButtonPositions() - { - Vector2 viewportSize = GetViewport().GetVisibleRect().Size; - - SetButtonPosition("Buttons/ButtonZ", viewportSize, new Vector2(0.35f, 0.20f)); - SetButtonPosition("Buttons/ButtonX", viewportSize, new Vector2(0.25f, 0.35f)); - SetButtonPosition("Buttons/ButtonC", viewportSize, new Vector2(0.15f, 0.50f)); - - var joystick = GetNode("Joystick"); - Vector2 joyPos = new Vector2( - viewportSize.X * 0.05f, // 距左5% - viewportSize.Y * 0.85f // 距底15% - ); - - joystick.AnchorLeft = 0; - joystick.AnchorTop = 0; - joystick.AnchorRight = 0; - joystick.AnchorBottom = 0; - joystick.Position = joyPos; - GD.Print(joystick.Position); - } - - private void SetButtonPosition(string path, Vector2 viewportSize, Vector2 offsetPercent) - { - var button = GetNode(path); - Vector2 finalPosition = new Vector2( - viewportSize.X * (1 - offsetPercent.X), - viewportSize.Y * (1 - offsetPercent.Y) - ); - - button.AnchorRight = 1; - button.AnchorBottom = 1; - button.AnchorLeft = 1; - button.AnchorTop = 1; - button.Position = finalPosition; // 从右下角反向偏移 - } - - private void UpdateDirectionInput(Vector2 dir) - { - string[] actions = { "Left", "Right", "Up", "Down" }; - Vector2[] vectors = { Vector2.Left, Vector2.Right, Vector2.Up, Vector2.Down }; - const float thresholdAngle = 57f; - - for (int i = 0; i < actions.Length; i++) + private void SetButtonTextures() { - float angle = Mathf.RadToDeg(Mathf.Abs(dir.AngleTo(vectors[i]))); - if (dir.Length() > 0.1f && angle < thresholdAngle) - Input.ActionPress(actions[i]); - else - Input.ActionRelease(actions[i]); + string basePath = "res://Sprites/Menus/Mobile/"; + GetNode("Buttons/ButtonZ").TextureNormal = GD.Load(basePath + "ButtonZ.png"); + GetNode("Buttons/ButtonX").TextureNormal = GD.Load(basePath + "ButtonX.png"); + GetNode("Buttons/ButtonC").TextureNormal = GD.Load(basePath + "ButtonC.png"); + } + + private void SetupButtonBindings() + { + BindButton("Buttons/ButtonZ", "Confirm"); + BindButton("Buttons/ButtonX", "Cancel"); + BindButton("Buttons/ButtonC", "Menu"); + } + + private void BindButton(string path, string actionName) + { + var button = GetNode(path); + button.Modulate = new Color(1, 1, 1, 0.5f); // 初始透明度 + + button.Pressed += () => + { + Input.ActionPress(actionName); + button.Modulate = new Color(1, 1, 1, 1); // 按下全不透明 + }; + + button.ButtonUp += () => + { + Input.ActionRelease(actionName); + button.Modulate = new Color(1, 1, 1, 0.5f); // 松开恢复 + }; + } + + private void UpdateButtonPositions() + { + Vector2 viewportSize = GetViewport().GetVisibleRect().Size; + + SetButtonPosition("Buttons/ButtonZ", viewportSize, new Vector2(0.35f, 0.20f)); + SetButtonPosition("Buttons/ButtonX", viewportSize, new Vector2(0.25f, 0.35f)); + SetButtonPosition("Buttons/ButtonC", viewportSize, new Vector2(0.15f, 0.50f)); + + var joystick = GetNode("Joystick"); + Vector2 joyPos = new Vector2( + viewportSize.X * 0.20f, + viewportSize.Y * 0.75f + ); + + joystick.AnchorLeft = 0; + joystick.AnchorTop = 0; + joystick.AnchorRight = 0; + joystick.AnchorBottom = 0; + joystick.Position = joyPos; + GD.Print(joystick.Position); + } + + private void SetButtonPosition(string path, Vector2 viewportSize, Vector2 offsetPercent) + { + var button = GetNode(path); + Vector2 finalPosition = new Vector2( + viewportSize.X * (1 - offsetPercent.X), + viewportSize.Y * (1 - offsetPercent.Y) + ); + + button.AnchorRight = 1; + button.AnchorBottom = 1; + button.AnchorLeft = 1; + button.AnchorTop = 1; + button.Position = finalPosition; // 从右下角反向偏移 + } + + private void UpdateDirectionInput(Vector2 dir) + { + string[] actions = { "Left", "Right", "Up", "Down" }; + Vector2[] vectors = { Vector2.Left, Vector2.Right, Vector2.Up, Vector2.Down }; + const float thresholdAngle = 57f; + + for (int i = 0; i < actions.Length; i++) + { + float angle = Mathf.RadToDeg(Mathf.Abs(dir.AngleTo(vectors[i]))); + if (dir.Length() > 0.1f && angle < thresholdAngle) + Input.ActionPress(actions[i]); + else + Input.ActionRelease(actions[i]); + } } } -}