Refactor rhythm action architecture
This commit is contained in:
108
scenes/components/combo_window.gd
Normal file
108
scenes/components/combo_window.gd
Normal file
@@ -0,0 +1,108 @@
|
||||
class_name ComboWindow
|
||||
extends Node
|
||||
|
||||
signal combo_updated(inputs: Array[StringName])
|
||||
signal combo_cleared(reason: StringName)
|
||||
|
||||
@export var size := 4
|
||||
@export var clear_display_time := 0.35
|
||||
|
||||
var slots: Array[StringName] = []
|
||||
var pending_clear_reason: StringName = &""
|
||||
var _timer: Timer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_timer = Timer.new()
|
||||
_timer.one_shot = true
|
||||
_timer.timeout.connect(flush_pending_clear)
|
||||
add_child(_timer)
|
||||
|
||||
|
||||
func record(input: StringName) -> void:
|
||||
if input.is_empty():
|
||||
return
|
||||
slots.append(input)
|
||||
combo_updated.emit(get_slots())
|
||||
_emit_bus_signal("combo_updated", [get_slots()])
|
||||
if slots.size() >= size:
|
||||
queue_clear(&"full")
|
||||
|
||||
|
||||
func get_slots() -> Array[StringName]:
|
||||
return slots.duplicate()
|
||||
|
||||
|
||||
func has_pending_clear() -> bool:
|
||||
return not pending_clear_reason.is_empty()
|
||||
|
||||
|
||||
func consume_pending_clear_reason() -> StringName:
|
||||
var reason := pending_clear_reason
|
||||
pending_clear_reason = &""
|
||||
return reason
|
||||
|
||||
|
||||
func get_pattern() -> String:
|
||||
var pattern := ""
|
||||
for slot: StringName in slots:
|
||||
if slot != &"Ø":
|
||||
pattern += str(slot)
|
||||
return pattern
|
||||
|
||||
|
||||
func get_contiguous_pattern() -> String:
|
||||
var pattern := ""
|
||||
for index: int in range(slots.size() - 1, -1, -1):
|
||||
var slot := slots[index]
|
||||
if slot == &"Ø":
|
||||
break
|
||||
pattern = str(slot) + pattern
|
||||
return pattern
|
||||
|
||||
|
||||
func queue_clear(reason: StringName, delay := -1.0) -> void:
|
||||
pending_clear_reason = reason
|
||||
if _timer == null:
|
||||
return
|
||||
_timer.stop()
|
||||
_timer.wait_time = clear_display_time if delay < 0.0 else delay
|
||||
_timer.start()
|
||||
|
||||
|
||||
func cancel_pending_clear() -> void:
|
||||
pending_clear_reason = &""
|
||||
if _timer != null:
|
||||
_timer.stop()
|
||||
|
||||
|
||||
func flush_pending_clear() -> void:
|
||||
var reason := consume_pending_clear_reason()
|
||||
if reason.is_empty():
|
||||
return
|
||||
if _timer != null:
|
||||
_timer.stop()
|
||||
clear(reason)
|
||||
|
||||
|
||||
func clear(reason: StringName = &"") -> void:
|
||||
slots.clear()
|
||||
pending_clear_reason = &""
|
||||
combo_cleared.emit(reason)
|
||||
_emit_bus_signal("combo_cleared", [reason])
|
||||
combo_updated.emit(get_slots())
|
||||
_emit_bus_signal("combo_updated", [get_slots()])
|
||||
|
||||
|
||||
func _emit_bus_signal(signal_name: StringName, args: Array) -> void:
|
||||
if not is_inside_tree():
|
||||
return
|
||||
var bus := _event_bus_or_null()
|
||||
if bus != null:
|
||||
bus.emit_signal(signal_name, args[0])
|
||||
|
||||
|
||||
func _event_bus_or_null() -> Node:
|
||||
if not is_inside_tree():
|
||||
return null
|
||||
return get_tree().root.get_node_or_null("EventBus")
|
||||
Reference in New Issue
Block a user