Files
whale-town/scripts/VirtualJoystick.gd
2025-12-05 19:00:14 +08:00

100 lines
2.8 KiB
GDScript

extends Control
class_name VirtualJoystick
## 虚拟摇杆控件
## 用于移动端触摸输入
# 摇杆参数
@export var joystick_radius: float = 50.0
@export var stick_radius: float = 20.0
@export var dead_zone: float = 0.2
# 摇杆状态
var is_pressed: bool = false
var touch_index: int = -1
var stick_position: Vector2 = Vector2.ZERO
var output_direction: Vector2 = Vector2.ZERO
# 视觉元素
var base_circle: ColorRect
var stick_circle: ColorRect
func _ready():
"""初始化虚拟摇杆"""
_create_visual_elements()
# 设置大小
custom_minimum_size = Vector2(joystick_radius * 2, joystick_radius * 2)
size = custom_minimum_size
func _create_visual_elements():
"""创建摇杆的视觉元素"""
# 创建底座
base_circle = ColorRect.new()
base_circle.color = Color(0.3, 0.3, 0.3, 0.5)
base_circle.size = Vector2(joystick_radius * 2, joystick_radius * 2)
base_circle.position = Vector2.ZERO
add_child(base_circle)
# 创建摇杆
stick_circle = ColorRect.new()
stick_circle.color = Color(0.8, 0.8, 0.8, 0.8)
stick_circle.size = Vector2(stick_radius * 2, stick_radius * 2)
stick_circle.position = Vector2(joystick_radius - stick_radius, joystick_radius - stick_radius)
add_child(stick_circle)
func _gui_input(event: InputEvent):
"""处理触摸输入"""
if event is InputEventScreenTouch:
if event.pressed:
# 触摸开始
is_pressed = true
touch_index = event.index
_update_stick_position(event.position)
elif event.index == touch_index:
# 触摸结束
is_pressed = false
touch_index = -1
_reset_stick()
elif event is InputEventScreenDrag and event.index == touch_index:
# 触摸拖动
_update_stick_position(event.position)
func _update_stick_position(touch_pos: Vector2):
"""更新摇杆位置"""
var center = Vector2(joystick_radius, joystick_radius)
var offset = touch_pos - center
# 限制在摇杆范围内
var max_distance = joystick_radius - stick_radius
if offset.length() > max_distance:
offset = offset.normalized() * max_distance
stick_position = offset
# 更新视觉位置
stick_circle.position = center + offset - Vector2(stick_radius, stick_radius)
# 计算输出方向
var normalized_offset = offset / max_distance
if normalized_offset.length() < dead_zone:
output_direction = Vector2.ZERO
else:
output_direction = normalized_offset.normalized() * ((normalized_offset.length() - dead_zone) / (1.0 - dead_zone))
func _reset_stick():
"""重置摇杆到中心"""
stick_position = Vector2.ZERO
output_direction = Vector2.ZERO
var center = Vector2(joystick_radius, joystick_radius)
stick_circle.position = center - Vector2(stick_radius, stick_radius)
## 获取当前方向
func get_direction() -> Vector2:
"""
获取摇杆当前方向
@return: 归一化的方向向量
"""
return output_direction