class_name LilypadTrack extends Control signal lilypad_in_center(lilypad: Lilypad) const LILYPAD_SCENE_PATH: String = "res://sources/minigames/frog/lilypad.tscn" var _lilypad_scene: PackedScene var top_to_bottom: bool = false var is_stopped: bool = false var is_cleared: bool = false var is_enabled: bool = false: set = _set_enabled var is_highlighting: bool = false: set = _set_highlighting var difficulty_settings: FrogMinigame.DifficultySettings var gp: Dictionary = {}: set(value): gp = value if gp.Type == 2: top_to_bottom = true var distractors: Array[Dictionary] = [] var distractors_queue: Array[Dictionary] = [] var distractors_queue_size: int = 5 var lilypads: Array[Lilypad] = [] var lilypad_size: Vector2 @onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D @onready var spawn_timer: Timer = $SpawnTimer func _process(delta: float) -> void: if is_stopped: return for lilypad: Lilypad in lilypads: if top_to_bottom: lilypad.position.y += _get_velocity() * delta else: lilypad.position.y -= _get_velocity() * delta func _get_velocity() -> float: if is_enabled: return difficulty_settings.pads_speed return difficulty_settings.pads_speed_disabled func reset() -> void: is_enabled = false is_stopped = true for lilypad: Lilypad in lilypads: lilypad.disappear() await get_tree().create_timer(0.5).timeout func start() -> void: is_stopped = false func stop() -> void: is_stopped = true func right() -> void: for lilypad: Lilypad in lilypads: await lilypad.right() func pick_distractor() -> Dictionary: if distractors_queue.is_empty(): distractors_queue = distractors.duplicate() distractors_queue.shuffle() while distractors_queue.size() > distractors_queue_size: distractors_queue.pop_front() if distractors_queue: return distractors_queue.pop_front() return {} #region Lilypads func _spawn_lilypad() -> void: if not _lilypad_scene: _lilypad_scene = load(LILYPAD_SCENE_PATH) as PackedScene var lilypad: Lilypad = _lilypad_scene.instantiate() lilypads.append(lilypad) add_child(lilypad) lilypad.disabled = not is_enabled if top_to_bottom: lilypad.global_position = global_position + Vector2(size.x / 2.0, 0.0) else: lilypad.global_position = global_position + Vector2(size.x / 2.0, size.y) lilypad_size = lilypad.button.size + Vector2(0, lilypad.label.size.y) if size.x < lilypad_size.x: var lily_scale: float = size.x / lilypad_size.x lilypad.button.scale = Vector2(lily_scale, lily_scale) lilypad_size *= lily_scale var is_stimulus: bool = randf() < difficulty_settings.stimuli_ratio lilypad.is_distractor = !is_stimulus if is_stimulus: lilypad.stimulus = gp else: lilypad.stimulus = pick_distractor() if is_highlighting: lilypad.highlight() else: lilypad.stop_highlight() lilypad.top_to_bottom = top_to_bottom lilypad.pressed.connect(_on_lilypad_pressed.bind(lilypad)) lilypad.disappeared.connect(_on_lilypad_disappeared.bind(lilypad)) func _despawn_lilypad(lilypad: Lilypad) -> void: lilypads.erase(lilypad) lilypad.queue_free() #endregion #region Setters func _set_enabled(value: bool) -> void: is_enabled = value if not is_cleared: for lilypad: Lilypad in lilypads: lilypad.disabled = not is_enabled func _set_highlighting(value: bool) -> void: is_highlighting = is_enabled and value for lilypad: Lilypad in lilypads: if is_highlighting: lilypad.highlight() else: lilypad.stop_highlight() #endregion #region Connections func _on_lilypad_pressed(lilypad: Lilypad) -> void: if is_cleared or is_stopped: return audio_player.play() stop() for other_lilypad: Lilypad in lilypads: if other_lilypad != lilypad: other_lilypad.disappear() var center_tween: Tween = create_tween() center_tween.finished.connect(_on_center_tween_finished.bind(lilypad, center_tween)) center_tween.tween_property(lilypad, "global_position", global_position + size / 2.0, 0.5) func _on_lilypad_disappeared(lilypad: Lilypad) -> void: _despawn_lilypad(lilypad) func _on_center_tween_finished(lilypad: Lilypad, center_tween: Tween) -> void: lilypad_in_center.emit(lilypad) center_tween.kill() func _on_spawn_timer_timeout() -> void: if not is_stopped: _spawn_lilypad() # Makes sure the lilypads don't overlap if lilypad_size: spawn_timer.start(randf_range(lilypad_size.y / _get_velocity(), lilypad_size.y * 2 / _get_velocity())) else: spawn_timer.start(randf_range(0.75, 1.5)) #endregion