extends Control signal calibration_finished(calibration: AccelCalibration) enum Phase { WAITING, RIGHT, LEFT, DONE } const TRAVEL_PX := 140.0 const PHASE_DURATION := 4.5 const CIRCLE_RADIUS := 44.0 const NEEDLE_LEN := 58.0 var _phase := Phase.WAITING var _phase_time := 0.0 var _guide_offset := Vector2.ZERO var _instruction := "" var _calibration := AccelCalibration.new() var _connection_notified := false @onready var _hint_label: Label = $HintLabel @onready var _start_button: Button = $StartButton func _ready() -> void: set_anchors_preset(Control.PRESET_FULL_RECT) mouse_filter = Control.MOUSE_FILTER_PASS _start_button.pressed.connect(_on_start_pressed) _show_waiting() func start() -> void: _calibration.reset() _connection_notified = false _phase = Phase.WAITING _phase_time = 0.0 _guide_offset = Vector2.ZERO visible = true _start_button.visible = true _show_waiting() queue_redraw() func is_active() -> bool: return _phase != Phase.DONE func feed_accel(accel: Vector3i) -> void: match _phase: Phase.RIGHT: _calibration.record_right(accel) Phase.LEFT: _calibration.record_left(accel) func notify_connected() -> void: if _phase != Phase.WAITING or _connection_notified: return _hint_label.text = "Verbunden – tippe „Kalibrierung starten“ oder warte…" # Automatisch starten sobald verbunden begin_calibration() func begin_calibration() -> void: if _phase == Phase.RIGHT or _phase == Phase.LEFT: return _connection_notified = true _start_button.visible = false _begin_phase(Phase.RIGHT) func _on_start_pressed() -> void: begin_calibration() func _process(delta: float) -> void: if _phase == Phase.WAITING or _phase == Phase.DONE: return _phase_time += delta var t := clampf(_phase_time / PHASE_DURATION, 0.0, 1.0) var ease := t * t * (3.0 - 2.0 * t) match _phase: Phase.RIGHT: _guide_offset.x = TRAVEL_PX * ease _instruction = "Neige das Gerät nach rechts – folge dem Kreis →" if _phase_time >= PHASE_DURATION: _begin_phase(Phase.LEFT) Phase.LEFT: _guide_offset.x = -TRAVEL_PX * ease _instruction = "Neige das Gerät nach links – folge dem Kreis ←" if _phase_time >= PHASE_DURATION: _finish() _hint_label.text = _instruction queue_redraw() func _begin_phase(phase: Phase) -> void: _phase = phase _phase_time = 0.0 _guide_offset = Vector2.ZERO match phase: Phase.RIGHT: _instruction = "Neige das Gerät nach rechts – folge dem Kreis →" Phase.LEFT: _instruction = "Neige das Gerät nach links – folge dem Kreis ←" _hint_label.text = _instruction queue_redraw() func _finish() -> void: _phase = Phase.DONE visible = false if _calibration.analyze(): calibration_finished.emit(_calibration) else: _hint_label.text = "Kalibrierung fehlgeschlagen – zu wenig Daten" visible = true _start_button.visible = true _show_waiting() func _show_waiting() -> void: _instruction = "Warte auf Verbindung zu localhost:9090…" _hint_label.text = _instruction + "\n(Oder „Kalibrierung starten“ ohne Verbindung)" func _screen_center() -> Vector2: return get_viewport_rect().size * 0.5 func _draw() -> void: if _phase == Phase.DONE: return var pos := _screen_center() + _guide_offset draw_circle(pos, CIRCLE_RADIUS, Color(0.25, 0.72, 0.95, 0.2)) draw_arc(pos, CIRCLE_RADIUS, 0.0, TAU, 64, Color(0.35, 0.82, 1.0), 2.5) var needle_tip := pos + Vector2(0.0, -NEEDLE_LEN) draw_line(pos, needle_tip, Color(1.0, 1.0, 1.0, 0.95), 3.0) draw_circle(needle_tip, 5.0, Color(1.0, 1.0, 1.0)) var center := _screen_center() if _phase == Phase.RIGHT: draw_line(center, center + Vector2(TRAVEL_PX, 0.0), Color(1.0, 1.0, 1.0, 0.12), 1.0) elif _phase == Phase.LEFT: draw_line(center, center + Vector2(-TRAVEL_PX, 0.0), Color(1.0, 1.0, 1.0, 0.12), 1.0)