100 lines
2.8 KiB
GDScript
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
|