发
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"]
|
||||
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
|
||||
|
@ -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<TextureRect>("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();
|
||||
}
|
||||
}
|
||||
|
@ -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>("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 += () =>
|
||||
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>("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>("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++)
|
||||
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<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);
|
||||
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