194 lines
6.9 KiB
GDScript
194 lines
6.9 KiB
GDScript
@tool
|
|
class_name ControllerInputSymbolWheel
|
|
extends Control
|
|
|
|
@export() var wheel_characters : PackedStringArray = [] : set = __set_wheel_characters
|
|
@export_range(0.0, 10.0, 0.01) var unselected_radius : float = 1.5 : set = __set_unselected_radius
|
|
@export_range(0.0, 10.0, 0.01) var selected_radius : float = 1.5 : set = __set_selected_radius
|
|
@export_range(0.0, 1.0, 0.01) var font_scale : float = 0.45 : set = __set_font_scale
|
|
|
|
@export var unselected_scale : Vector2 = Vector2(0.5, 0.5) : set = __set_unselected_scale
|
|
@export var selected_scale : Vector2 = Vector2(1.0, 1.0) : set = __set_selected_scale
|
|
|
|
@export_range(0.0, 1.0, 0.01) var tween_speed : float = 0.15
|
|
|
|
@export_group("Inputs")
|
|
@export_subgroup("Joypad", "joypad_")
|
|
@export var joypad_symbol_up : InputEventJoypadMotion
|
|
@export var joypad_symbol_down : InputEventJoypadMotion
|
|
@export var joypad_symbol_left : InputEventJoypadMotion
|
|
@export var joypad_symbol_right : InputEventJoypadMotion
|
|
|
|
@onready var __joystick_flick_timer : Timer = $JoystickFlickTimer
|
|
|
|
signal new_character(char:String)
|
|
|
|
var __symbol_labels : Array = []
|
|
var __selected_label : int = -1
|
|
var __selected : bool = false
|
|
|
|
|
|
func _init() -> void:
|
|
if not resized.is_connected(__spin_labels_around_centre):
|
|
resized.connect(__spin_labels_around_centre)
|
|
|
|
func _enter_tree() -> void:
|
|
__regenerate_labels()
|
|
|
|
func _exit_tree() -> void:
|
|
if resized.is_connected(__spin_labels_around_centre):
|
|
resized.disconnect(__spin_labels_around_centre)
|
|
|
|
func _input(event:InputEvent) -> void:
|
|
if not __selected: return
|
|
|
|
var symbols_count : int = __symbol_labels.size()
|
|
var index : int = __selected_label
|
|
var right_stick_vector : Vector2 = Input.get_vector(&"select_symbol_left", &"select_symbol_right", &"select_symbol_up", &"select_symbol_down")
|
|
if right_stick_vector.length() >= 0.95:
|
|
var stick_angle : float = ((Vector2.UP).rotated(right_stick_vector.angle() + (TAU / (symbols_count + symbols_count))).angle() + PI) / TAU
|
|
index = clamp(int(floor(stick_angle * symbols_count)), 0, symbols_count - 1)
|
|
elif right_stick_vector.length() < 0.8:
|
|
index = -1
|
|
|
|
__new_symbol_selection(index)
|
|
|
|
|
|
func select() -> void:
|
|
if __selected: return
|
|
__selected = true
|
|
__spin_labels_around_centre()
|
|
__initialise_input()
|
|
|
|
func deselect() -> void:
|
|
if not __selected: return
|
|
__selected = false
|
|
|
|
if __selected_label >= 0:
|
|
__deselect_symbol(__selected_label)
|
|
__selected_label = -1
|
|
__uninitialise_input()
|
|
|
|
__spin_labels_around_centre()
|
|
|
|
|
|
func __new_symbol_selection(new_selection:int) -> void:
|
|
if __selected_label == new_selection: return
|
|
|
|
if new_selection < 0 and __joystick_flick_timer.is_stopped():
|
|
var send_char : String = wheel_characters[__selected_label]
|
|
if not send_char.is_empty():
|
|
if send_char == "␣":
|
|
new_character.emit(" ")
|
|
else:
|
|
new_character.emit(send_char)
|
|
__joystick_flick_timer.start()
|
|
|
|
if __selected_label >= 0:
|
|
__deselect_symbol(__selected_label)
|
|
|
|
__selected_label = new_selection
|
|
|
|
if __selected_label >= 0:
|
|
__select_symbol(__selected_label)
|
|
|
|
func __select_symbol(selection:int) -> void:
|
|
var label : Label = __symbol_labels[selection]
|
|
label.z_index = 1
|
|
|
|
var label_tween_activate : Tween = get_tree().create_tween()
|
|
label_tween_activate.bind_node(label)
|
|
label_tween_activate.tween_property(label, "scale", selected_scale, tween_speed)
|
|
|
|
var position : Vector2 = __calculate_label_position(label, selection, selected_radius)
|
|
var label_tween_radius : Tween = get_tree().create_tween()
|
|
label_tween_radius.bind_node(label)
|
|
label_tween_radius.tween_property(label, "position", position, tween_speed)
|
|
|
|
func __deselect_symbol(selection:int) -> void:
|
|
var label : Label = __symbol_labels[selection]
|
|
label.z_index = 0
|
|
|
|
var label_tween_deactivate : Tween = get_tree().create_tween()
|
|
label_tween_deactivate.bind_node(label)
|
|
label_tween_deactivate.tween_property(label, "scale", unselected_scale, tween_speed)
|
|
|
|
var position : Vector2 = __calculate_label_position(label, selection, unselected_radius)
|
|
var label_tween_radius : Tween = get_tree().create_tween()
|
|
label_tween_radius.bind_node(label)
|
|
label_tween_radius.tween_property(label, "position", position, tween_speed)
|
|
|
|
func __calculate_label_position(label:Label, label_index:int, radius:float) -> Vector2:
|
|
var angle_slice : float = PI / float(__symbol_labels.size()) * 2.0
|
|
var min_size : int = min(size.x, size.y)
|
|
var max_label_size : int = max(label.size.x, label.size.y)
|
|
label.pivot_offset = label.size / 2.0
|
|
var position : Vector2 = (size / 2.0) - label.size / 2.0
|
|
position += (-Vector2.UP * radius).rotated(angle_slice * label_index) * ((min_size - max_label_size) / 3.0)
|
|
return position
|
|
|
|
|
|
func __regenerate_labels() -> void:
|
|
for i:Label in __symbol_labels:
|
|
i.queue_free()
|
|
__symbol_labels = []
|
|
for char:String in wheel_characters:
|
|
var label : Label = Label.new()
|
|
add_child(label)
|
|
label.text = char
|
|
label.horizontal_alignment = HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER
|
|
label.vertical_alignment = VerticalAlignment.VERTICAL_ALIGNMENT_CENTER
|
|
label.size = Vector2(20.0, 20.0)
|
|
label.pivot_offset = label.size / 2.0
|
|
__symbol_labels.append(label)
|
|
__spin_labels_around_centre()
|
|
|
|
func __spin_labels_around_centre() -> void:
|
|
for i:int in range(__symbol_labels.size()):
|
|
var label : Label = __symbol_labels[i]
|
|
var max_label_size : int = max(label.size.x, label.size.y)
|
|
var radius : float = selected_radius if i == __selected_label else unselected_radius
|
|
label.scale = selected_scale if i == __selected_label else unselected_scale
|
|
label.position = __calculate_label_position(label, i, radius)
|
|
|
|
|
|
func __initialise_input() -> void:
|
|
InputMap.add_action(&"select_symbol_up", 0.0)
|
|
InputMap.action_add_event(&"select_symbol_up", joypad_symbol_up)
|
|
InputMap.add_action(&"select_symbol_down", 0.0)
|
|
InputMap.action_add_event(&"select_symbol_down", joypad_symbol_down)
|
|
InputMap.add_action(&"select_symbol_left", 0.0)
|
|
InputMap.action_add_event(&"select_symbol_left", joypad_symbol_left)
|
|
InputMap.add_action(&"select_symbol_right", 0.0)
|
|
InputMap.action_add_event(&"select_symbol_right", joypad_symbol_right)
|
|
|
|
func __uninitialise_input() -> void:
|
|
InputMap.action_erase_event(&"select_symbol_right", joypad_symbol_right)
|
|
InputMap.erase_action(&"select_symbol_right")
|
|
InputMap.action_erase_event(&"select_symbol_left", joypad_symbol_left)
|
|
InputMap.erase_action(&"select_symbol_left")
|
|
InputMap.action_erase_event(&"select_symbol_down", joypad_symbol_down)
|
|
InputMap.erase_action(&"select_symbol_down")
|
|
InputMap.action_erase_event(&"select_symbol_up", joypad_symbol_up)
|
|
InputMap.erase_action(&"select_symbol_up")
|
|
|
|
|
|
func __set_wheel_characters(characters:PackedStringArray) -> void:
|
|
wheel_characters = characters
|
|
__regenerate_labels()
|
|
|
|
func __set_selected_radius(r:float) -> void:
|
|
selected_radius = r
|
|
|
|
func __set_unselected_radius(r:float) -> void:
|
|
unselected_radius = r
|
|
|
|
func __set_font_scale(s:float) -> void:
|
|
font_scale = s
|
|
|
|
func __set_unselected_scale(s:Vector2) -> void:
|
|
unselected_scale = s
|
|
|
|
func __set_selected_scale(s:Vector2) -> void:
|
|
selected_scale = s
|