发
This commit is contained in:
parent
e86575e80b
commit
ee29207d71
35
Objects/UI/Joystick.tscn
Normal file
35
Objects/UI/Joystick.tscn
Normal file
@ -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
|
@ -6,28 +6,6 @@
|
|||||||
[node name="TouchControls" type="CanvasLayer"]
|
[node name="TouchControls" type="CanvasLayer"]
|
||||||
script = ExtResource("1_42104")
|
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="."]
|
[node name="Buttons" type="Control" parent="."]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
anchors_preset = 0
|
anchors_preset = 0
|
||||||
@ -48,3 +26,26 @@ offset_bottom = 40.0
|
|||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_right = 40.0
|
offset_right = 40.0
|
||||||
offset_bottom = 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
|
||||||
|
@ -3,57 +3,57 @@ using System;
|
|||||||
|
|
||||||
public partial class Joystick : Control
|
public partial class Joystick : Control
|
||||||
{
|
{
|
||||||
private Vector2 touchStartPos = Vector2.Zero;
|
private Vector2 _startTouchPos = Vector2.Zero;
|
||||||
private Vector2 currentPos = Vector2.Zero;
|
private Vector2 _currentTouchPos = Vector2.Zero;
|
||||||
private int fingerId = -1;
|
private bool _touching = false;
|
||||||
|
|
||||||
[Export] public float DeadzoneRadius = 40f;
|
[Export] public float DeadzoneRadius = 30f;
|
||||||
[Export] public float MaxRadius = 120f;
|
[Export] public float MaxRadius = 90f;
|
||||||
|
|
||||||
public override void _Input(InputEvent @event)
|
public override void _GuiInput(InputEvent @event)
|
||||||
{
|
{
|
||||||
if (@event is InputEventScreenTouch touch)
|
if (@event is InputEventScreenTouch touch)
|
||||||
{
|
{
|
||||||
if (touch.Pressed && fingerId == -1 && GetGlobalRect().HasPoint(touch.Position))
|
if (touch.Pressed)
|
||||||
{
|
{
|
||||||
fingerId = touch.Index;
|
_touching = true;
|
||||||
touchStartPos = touch.Position;
|
_startTouchPos = touch.Position;
|
||||||
currentPos = touch.Position;
|
_currentTouchPos = touch.Position;
|
||||||
}
|
}
|
||||||
else if (!touch.Pressed && touch.Index == fingerId)
|
else
|
||||||
{
|
{
|
||||||
fingerId = -1;
|
_touching = false;
|
||||||
currentPos = touchStartPos;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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<TextureRect>("HandleCircle");
|
|
||||||
handle.Position = localOffset;
|
|
||||||
|
|
||||||
QueueRedraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2 GetDirection()
|
public Vector2 GetDirection()
|
||||||
{
|
{
|
||||||
if (fingerId == -1)
|
if (!_touching) return Vector2.Zero;
|
||||||
|
|
||||||
|
Vector2 offset = _currentTouchPos - _startTouchPos;
|
||||||
|
if (offset.Length() < DeadzoneRadius)
|
||||||
return Vector2.Zero;
|
return Vector2.Zero;
|
||||||
|
|
||||||
Vector2 delta = currentPos - touchStartPos;
|
return offset.Normalized() * Mathf.Min(offset.Length(), MaxRadius);
|
||||||
if (delta.Length() < DeadzoneRadius)
|
}
|
||||||
return Vector2.Zero;
|
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,110 +1,110 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
public partial class TouchControls : CanvasLayer
|
public partial class TouchControls : CanvasLayer
|
||||||
{
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
{
|
||||||
// 仅在 Android 平台启用
|
public override void _Ready()
|
||||||
//if (OS.GetName() != "Android")
|
|
||||||
//{
|
|
||||||
//QueueFree();
|
|
||||||
//return;
|
|
||||||
//}
|
|
||||||
SetButtonTextures();
|
|
||||||
SetupButtonBindings();
|
|
||||||
UpdateButtonPositions(); // 设置初始位置
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _Process(double delta)
|
|
||||||
{
|
|
||||||
Vector2 dir = GetNode<Joystick>("Joystick").GetDirection();
|
|
||||||
UpdateDirectionInput(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetButtonTextures()
|
|
||||||
{
|
|
||||||
string basePath = "res://Sprites/Menus/Mobile/";
|
|
||||||
GetNode<TextureButton>("Buttons/ButtonZ").TextureNormal = GD.Load<Texture2D>(basePath + "ButtonZ.png");
|
|
||||||
GetNode<TextureButton>("Buttons/ButtonX").TextureNormal = GD.Load<Texture2D>(basePath + "ButtonX.png");
|
|
||||||
GetNode<TextureButton>("Buttons/ButtonC").TextureNormal = GD.Load<Texture2D>(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<TextureButton>(path);
|
|
||||||
button.Modulate = new Color(1, 1, 1, 0.5f); // 初始透明度
|
|
||||||
|
|
||||||
button.Pressed += () =>
|
|
||||||
{
|
{
|
||||||
Input.ActionPress(actionName);
|
// 仅在 Android 平台启用
|
||||||
button.Modulate = new Color(1, 1, 1, 1); // 按下全不透明
|
if (OS.GetName() != "Android")
|
||||||
};
|
{
|
||||||
|
QueueFree();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetButtonTextures();
|
||||||
|
SetupButtonBindings();
|
||||||
|
UpdateButtonPositions(); // 设置初始位置
|
||||||
|
}
|
||||||
|
|
||||||
button.ButtonUp += () =>
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
Input.ActionRelease(actionName);
|
Vector2 dir = GetNode<Joystick>("Joystick").GetDirection();
|
||||||
button.Modulate = new Color(1, 1, 1, 0.5f); // 松开恢复
|
UpdateDirectionInput(dir);
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateButtonPositions()
|
private void SetButtonTextures()
|
||||||
{
|
|
||||||
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>("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<TextureButton>(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])));
|
string basePath = "res://Sprites/Menus/Mobile/";
|
||||||
if (dir.Length() > 0.1f && angle < thresholdAngle)
|
GetNode<TextureButton>("Buttons/ButtonZ").TextureNormal = GD.Load<Texture2D>(basePath + "ButtonZ.png");
|
||||||
Input.ActionPress(actions[i]);
|
GetNode<TextureButton>("Buttons/ButtonX").TextureNormal = GD.Load<Texture2D>(basePath + "ButtonX.png");
|
||||||
else
|
GetNode<TextureButton>("Buttons/ButtonC").TextureNormal = GD.Load<Texture2D>(basePath + "ButtonC.png");
|
||||||
Input.ActionRelease(actions[i]);
|
}
|
||||||
|
|
||||||
|
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<TextureButton>(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>("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<TextureButton>(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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user