From 130532c4c93a69d2183d94ad44553cb36cd308a7 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 26 Sep 2026 13:46:34 +0200 Subject: [PATCH] Use frontal steering-wheel roll for Space Shooter movement. Drop the interactive accel calibration and map left/right ship motion from absolute pod roll while held facing the player. Co-authored-by: Cursor --- scenes/space_shooter.tscn | 58 +------------------ scripts/orientation_gizmo.gd | 16 ++++- scripts/space_shooter.gd | 109 +++++------------------------------ 3 files changed, 32 insertions(+), 151 deletions(-) diff --git a/scenes/space_shooter.tscn b/scenes/space_shooter.tscn index c01a10d..5389dde 100644 --- a/scenes/space_shooter.tscn +++ b/scenes/space_shooter.tscn @@ -1,7 +1,6 @@ [gd_scene format=3 uid="uid://bwayhk38lpl3u"] [ext_resource type="Script" path="res://scripts/space_shooter.gd" id="1_shooter"] -[ext_resource type="Script" path="res://scripts/calibration_overlay.gd" id="2_calib"] [node name="SpaceShooter" type="Node2D"] script = ExtResource("1_shooter") @@ -63,18 +62,6 @@ theme_override_font_sizes/font_size = 18 horizontal_alignment = 2 text = "Rechts · —" -[node name="RecalibButton" type="Button" parent="UiLayer"] -visible = false -anchors_preset = 1 -anchor_left = 1.0 -anchor_right = 1.0 -offset_left = -240.0 -offset_top = 12.0 -offset_right = -130.0 -offset_bottom = 44.0 -grow_horizontal = 0 -text = "Neu kalibrieren" - [node name="SetupPanel" type="VBoxContainer" parent="UiLayer"] anchors_preset = 8 anchor_left = 0.5 @@ -102,7 +89,7 @@ layout_mode = 2 theme_override_colors/font_color = Color(0.6, 0.65, 0.75, 1) theme_override_font_sizes/font_size = 14 horizontal_alignment = 1 -text = "Split-Screen · Pod-Zuweisung" +text = "Split-Screen · Pod frontal halten, Lenkrad drehen" [node name="ClientGrid" type="GridContainer" parent="UiLayer/SetupPanel"] layout_mode = 2 @@ -145,45 +132,4 @@ layout_mode = 2 size_flags_horizontal = 4 disabled = true theme_override_font_sizes/font_size = 18 -text = "Kalibrierung starten" - -[node name="CalibrationOverlay" type="Control" parent="UiLayer"] -visible = false -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -mouse_filter = 0 -script = ExtResource("2_calib") - -[node name="HintLabel" type="Label" parent="UiLayer/CalibrationOverlay"] -layout_mode = 1 -anchors_preset = 5 -anchor_left = 0.5 -anchor_right = 0.5 -offset_left = -420.0 -offset_top = 80.0 -offset_right = 420.0 -offset_bottom = 180.0 -grow_horizontal = 2 -theme_override_colors/font_color = Color(0.9, 0.92, 0.98, 1) -theme_override_font_sizes/font_size = 20 -horizontal_alignment = 1 -autowrap_mode = 3 -text = "Kalibrierung" - -[node name="StartButton" type="Button" parent="UiLayer/CalibrationOverlay"] -layout_mode = 1 -anchors_preset = 7 -anchor_left = 0.5 -anchor_top = 1.0 -anchor_right = 0.5 -anchor_bottom = 1.0 -offset_left = -140.0 -offset_top = -120.0 -offset_right = 140.0 -offset_bottom = -72.0 -grow_horizontal = 2 -text = "Kalibrierung starten" +text = "Spiel starten" diff --git a/scripts/orientation_gizmo.gd b/scripts/orientation_gizmo.gd index 3fdf661..aa42ae1 100644 --- a/scripts/orientation_gizmo.gd +++ b/scripts/orientation_gizmo.gd @@ -60,12 +60,24 @@ func _process(_delta: float) -> void: _pod.basis = _pod.basis.slerp(_target_basis, SMOOTH) +## Lenkrad-Roll in Radiant (links positiv). 0 wenn liegend oder in der Deadzone. +static func steer_roll(accel: Vector3, deadzone_rad: float = deg_to_rad(12.0)) -> float: + if accel.length() < MIN_ACCEL_LEN: + return 0.0 + var n := accel.normalized() + var face_t := clampf(1.0 - maxf(n.z, 0.0), 0.0, 1.0) + if face_t < 0.25: + return 0.0 + var roll := atan2(-n.x, -n.y) + if absf(roll) <= deadzone_rad: + return 0.0 + return signf(roll) * (absf(roll) - deadzone_rad) * face_t + + func _basis_from_accel(accel: Vector3) -> Basis: var n := accel.normalized() # 0 = liegend (+Z), 1 = aufgerichtet / gedreht (wenig +Z) var face_t := clampf(1.0 - maxf(n.z, 0.0), 0.0, 1.0) var b := _basis_flat.slerp(_basis_facing, face_t) - # Lenkrad-Roll in der Sensor-XY-Ebene: - # facing (0,−1) → 0; links (−1,0) → +π/2; rechts (+1,0) → −π/2 var roll := atan2(-n.x, -n.y) return Basis(Quaternion(Vector3.BACK, roll * face_t)) * b diff --git a/scripts/space_shooter.gd b/scripts/space_shooter.gd index 0db57a3..bf19484 100644 --- a/scripts/space_shooter.gd +++ b/scripts/space_shooter.gd @@ -1,6 +1,6 @@ extends Node2D -enum GameState { SETUP, CALIBRATION, PLAYING } +enum GameState { SETUP, PLAYING } enum PlayerSide { LEFT, RIGHT } @@ -18,6 +18,8 @@ const MAX_SHIP_SPEED := 720.0 const SHIP_FRICTION := 0.88 const DEFAULT_SENSITIVITY := 12.0 const ACCEL_SMOOTH := 0.3 +## Maps steer-roll radians onto the old accel scale for ship velocity. +const STEER_GAIN := 10000.0 const BULLET_SPEED := 900.0 const FIRE_INTERVAL := 0.14 @@ -51,19 +53,14 @@ const LASER_SCALE := 1.4 @onready var right_client_option: OptionButton = $UiLayer/SetupPanel/ClientGrid/RightClientOption @onready var start_game_button: Button = $UiLayer/SetupPanel/StartGameButton @onready var setup_hint_label: Label = $UiLayer/SetupPanel/SetupHintLabel -@onready var calibration_overlay: Control = $UiLayer/CalibrationOverlay -@onready var recalib_button: Button = $UiLayer/RecalibButton var _socket := WebSocketPeer.new() var _state := GameState.SETUP var _available_clients: PackedInt32Array = PackedInt32Array() var _left_client_id := 0 var _right_client_id := 0 -var _calib_side := PlayerSide.LEFT var _stream_client_ids: PackedInt32Array = PackedInt32Array() -var _calibrations: Array[AccelCalibration] = [AccelCalibration.new(), AccelCalibration.new()] -var _thresholds: Array[float] = [3000.0, 3000.0] var _sensitivities: Array[float] = [DEFAULT_SENSITIVITY, DEFAULT_SENSITIVITY] var _accel_filtered: Array[Vector3] = [Vector3.ZERO, Vector3.ZERO] var _ship_x: Array[float] = [0.0, 0.0] @@ -89,12 +86,9 @@ func _ready() -> void: start_game_button.pressed.connect(_on_start_game_pressed) left_client_option.item_selected.connect(_on_client_selection_changed) right_client_option.item_selected.connect(_on_client_selection_changed) - recalib_button.pressed.connect(_restart_calibration) - calibration_overlay.calibration_finished.connect(_on_calibration_finished) _hide_gameplay() setup_panel.visible = true - recalib_button.visible = false _state = GameState.SETUP _init_visuals() @@ -165,10 +159,6 @@ func _physics_process(delta: float) -> void: match _state: GameState.SETUP: return - GameState.CALIBRATION: - if calibration_overlay.is_active(): - calibration_overlay.feed_accel(_accel_for_side(_calib_side)) - return GameState.PLAYING: _update_boost_state(delta) _update_stars(delta) @@ -259,44 +249,17 @@ func _on_client_selection_changed(_idx: int) -> void: elif _left_client_id == _right_client_id: setup_hint_label.text = "Links und rechts müssen verschiedene Pods sein." else: - setup_hint_label.text = "Pod #%d spielt links · Pod #%d spielt rechts" % [_left_client_id, _right_client_id] + setup_hint_label.text = ( + "Pod #%d links · Pod #%d rechts · frontal halten, Lenkrad drehen" + % [_left_client_id, _right_client_id] + ) func _on_start_game_pressed() -> void: if _left_client_id <= 0 or _right_client_id <= 0 or _left_client_id == _right_client_id: return setup_panel.visible = false - _start_calibration(PlayerSide.LEFT) - - -func _start_calibration(side: PlayerSide) -> void: - _state = GameState.CALIBRATION - _calib_side = side - _hide_gameplay() - recalib_button.visible = false - - var cid := _client_id_for_side(side) - calibration_overlay.set_context_label( - "Kalibrierung %s · Pod #%d\nZylinder senkrecht halten, dann links/rechts schwanken" % [ - _side_name(side), cid - ] - ) - calibration_overlay.start() - _set_stream_for_calibration(cid) - - if _socket.get_ready_state() == WebSocketPeer.STATE_OPEN: - calibration_overlay.notify_connected() - - -func _on_calibration_finished(calibration: AccelCalibration) -> void: - _calibrations[_calib_side] = calibration - _thresholds[_calib_side] = calibration.suggested_threshold - _sensitivities[_calib_side] = DEFAULT_SENSITIVITY - - if _calib_side == PlayerSide.LEFT: - _start_calibration(PlayerSide.RIGHT) - else: - _begin_playing() + _begin_playing() func _begin_playing() -> void: @@ -312,33 +275,20 @@ func _begin_playing() -> void: _boost_cooldown_left = [0.0, 0.0] _boost_led_active = [false, false] _led_update_timer = 0.0 + _sensitivities = [DEFAULT_SENSITIVITY, DEFAULT_SENSITIVITY] for side in [PlayerSide.LEFT, PlayerSide.RIGHT]: _ship_x[side] = _side_play_rect(side).get_center().x _show_gameplay() - recalib_button.visible = true _enable_both_streams() _update_score_labels() status_label.text = ( - "Pod #%d · %s · Schwelle %.0f | Pod #%d · %s · Schwelle %.0f" - % [ - _left_client_id, - _calibrations[PlayerSide.LEFT].axis_name(), - _thresholds[PlayerSide.LEFT], - _right_client_id, - _calibrations[PlayerSide.RIGHT].axis_name(), - _thresholds[PlayerSide.RIGHT], - ] + "Pod frontal halten · wie Lenkrad drehen · Tap = Boost (%ds)" + % int(BOOST_DURATION_SEC) ) -func _restart_calibration() -> void: - _clear_entities() - _hide_gameplay() - _start_calibration(PlayerSide.LEFT) - - func _show_gameplay() -> void: for ship in _ships: ship.visible = true @@ -359,14 +309,6 @@ func _clear_entities() -> void: _bullets.clear() -func _set_stream_for_calibration(client_id: int) -> void: - _disable_all_streams() - _stream_client_ids = PackedInt32Array([client_id]) - _send({"type": "set_input_stream", "client_id": client_id, "enable": true}) - _send({"type": "set_tap_notify", "client_id": client_id, "single": false, "double_tap": false, "triple": false}) - _send({"type": "set_stream", "enable": true, "interval_ms": STREAM_INTERVAL_MS}) - - func _enable_both_streams() -> void: _disable_all_streams() _stream_client_ids = PackedInt32Array([_left_client_id, _right_client_id]) @@ -752,14 +694,10 @@ func _update_stars(delta: float) -> void: func _effective_accel(side: int) -> float: - var cal: AccelCalibration = _calibrations[side] - var raw := cal.project(_accel_for_side(side)) - var centered := raw - cal.center - var threshold := _thresholds[side] - var abs_v := absf(centered) - if abs_v <= threshold: - return 0.0 - return signf(centered) * (abs_v - threshold) + # Frontal halten, Lenkrad-Roll: links positiv → Schiff nach links (negativ). + var a := _accel_for_side(side) + var roll := OrientationGizmo.steer_roll(Vector3(a)) + return -roll * STEER_GAIN func _velocity_scale(side: int) -> float: @@ -782,10 +720,6 @@ func _client_id_for_side(side: PlayerSide) -> int: return _left_client_id if side == PlayerSide.LEFT else _right_client_id -func _side_name(side: PlayerSide) -> String: - return "links" if side == PlayerSide.LEFT else "rechts" - - func _update_connection_status() -> void: match _state: GameState.SETUP: @@ -796,22 +730,11 @@ func _update_connection_status() -> void: status_label.text = "Verbinde…" _: status_label.text = "Getrennt – erneuter Verbindungsversuch…" - GameState.CALIBRATION: - match _socket.get_ready_state(): - WebSocketPeer.STATE_OPEN: - status_label.text = "Kalibrierung %s · Pod #%d" % [ - _side_name(_calib_side), _client_id_for_side(_calib_side) - ] - calibration_overlay.notify_connected() - WebSocketPeer.STATE_CONNECTING: - status_label.text = "Kalibrierung – verbinde…" - _: - status_label.text = "Kalibrierung – keine Verbindung" GameState.PLAYING: match _socket.get_ready_state(): WebSocketPeer.STATE_OPEN: status_label.text = ( - "Tap/Doppel-Tap = Boost (%ds) · x2 Schaden · ♥×%d · Cooldown %ds" + "Frontal halten · Lenkrad drehen · Tap = Boost (%ds) · ♥×%d · CD %ds" % [int(BOOST_DURATION_SEC), MAX_LIVES, int(BOOST_COOLDOWN_SEC)] ) WebSocketPeer.STATE_CONNECTING: