Compare commits
2
Commits
a32a223881
...
130532c4c9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
130532c4c9 | ||
|
|
54d42dade9 |
+1
-1
@@ -12,7 +12,7 @@ config_version=5
|
||||
|
||||
config/name="alox_test_game"
|
||||
run/main_scene="res://scenes/menu.tscn"
|
||||
config/features=PackedStringArray("4.6", "GL Compatibility")
|
||||
config/features=PackedStringArray("4.7", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[display]
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/orientation_gizmo.gd" id="1_gizmo"]
|
||||
|
||||
[sub_resource type="CylinderMesh" id="CylinderMesh_body"]
|
||||
top_radius = 0.35
|
||||
bottom_radius = 0.35
|
||||
height = 1.1
|
||||
radial_segments = 24
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Mat_body"]
|
||||
albedo_color = Color(0.42, 0.48, 0.58, 1)
|
||||
roughness = 0.55
|
||||
|
||||
[sub_resource type="CylinderMesh" id="CylinderMesh_cap"]
|
||||
top_radius = 0.38
|
||||
bottom_radius = 0.38
|
||||
height = 0.08
|
||||
radial_segments = 24
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Mat_top"]
|
||||
albedo_color = Color(1, 0.55, 0.12, 1)
|
||||
roughness = 0.4
|
||||
emission_enabled = true
|
||||
emission = Color(0.85, 0.4, 0.05, 1)
|
||||
emission_energy_multiplier = 0.35
|
||||
|
||||
[node name="OrientationGizmo" type="SubViewportContainer"]
|
||||
custom_minimum_size = Vector2(220, 220)
|
||||
stretch = true
|
||||
script = ExtResource("1_gizmo")
|
||||
|
||||
[node name="SubViewport" type="SubViewport" parent="."]
|
||||
own_world_3d = true
|
||||
transparent_bg = true
|
||||
handle_input_locally = false
|
||||
size = Vector2i(220, 220)
|
||||
render_target_update_mode = 4
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="SubViewport"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3.2)
|
||||
projection = 1
|
||||
size = 2.6
|
||||
near = 0.05
|
||||
far = 50.0
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="SubViewport"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 4)
|
||||
light_energy = 1.2
|
||||
shadow_enabled = false
|
||||
|
||||
[node name="FillLight" type="DirectionalLight3D" parent="SubViewport"]
|
||||
transform = Transform3D(-0.866025, -0.353553, 0.353553, 0, 0.707107, 0.707107, -0.5, 0.612372, -0.612372, 0, 0, 0)
|
||||
light_energy = 0.4
|
||||
shadow_enabled = false
|
||||
|
||||
[node name="Pod" type="Node3D" parent="SubViewport"]
|
||||
|
||||
[node name="Body" type="MeshInstance3D" parent="SubViewport/Pod"]
|
||||
mesh = SubResource("CylinderMesh_body")
|
||||
surface_material_override/0 = SubResource("Mat_body")
|
||||
|
||||
[node name="TopCap" type="MeshInstance3D" parent="SubViewport/Pod"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.59, 0)
|
||||
mesh = SubResource("CylinderMesh_cap")
|
||||
surface_material_override/0 = SubResource("Mat_top")
|
||||
|
||||
[node name="TopLabel" type="Label3D" parent="SubViewport/Pod"]
|
||||
transform = Transform3D(1, 0, 0, 0, 0, -1, 0, 1, 0, 0, -0.66, 0)
|
||||
pixel_size = 0.01
|
||||
billboard = 0
|
||||
text = "TOP"
|
||||
font_size = 42
|
||||
outline_size = 8
|
||||
modulate = Color(1, 0.95, 0.85, 1)
|
||||
outline_modulate = Color(0.05, 0.05, 0.08, 1)
|
||||
@@ -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"
|
||||
|
||||
+23
-4
@@ -12,6 +12,7 @@ const PANEL_BORDER_FLASH := Color(1.0, 0.82, 0.15, 1.0)
|
||||
|
||||
const LED_MODES: PackedStringArray = ["color", "clear", "progress", "digit", "blink", "find-me"]
|
||||
const LED_MODES_COLOR_INTENSITY: PackedStringArray = ["color", "progress", "digit", "blink"]
|
||||
const ORIENTATION_GIZMO_SCENE := preload("res://scenes/orientation_gizmo.tscn")
|
||||
|
||||
@onready var status_label: Label = $UiLayer/TopBar/StatusLabel
|
||||
@onready var log_output: TextEdit = $UiLayer/MainSplit/LogPanel/LogOutput
|
||||
@@ -122,6 +123,7 @@ func _stop_stream() -> void:
|
||||
"triple": false,
|
||||
})
|
||||
ui["values_label"].text = "—"
|
||||
ui["orient_gizmo"].clear()
|
||||
|
||||
_streaming = false
|
||||
start_stream_btn.disabled = _client_ui.is_empty()
|
||||
@@ -328,14 +330,26 @@ func _populate_clients(clients: Array) -> void:
|
||||
_add_led_preset_btn(led_presets, "Blau", cid, available, func() -> void: _led_apply_preset(cid, "color", Color(0.2, 0.4, 1), 128))
|
||||
_add_led_preset_btn(led_presets, "Find", cid, available, func() -> void: _led_apply_preset(cid, "find-me"))
|
||||
|
||||
var accel_row := HBoxContainer.new()
|
||||
accel_row.add_theme_constant_override("separation", 12)
|
||||
accel_row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
vbox.add_child(accel_row)
|
||||
|
||||
var values_label := Label.new()
|
||||
values_label.text = "—"
|
||||
values_label.add_theme_font_size_override("font_size", 12)
|
||||
values_label.add_theme_color_override("font_color", Color(0.65, 0.85, 0.75))
|
||||
values_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
vbox.add_child(values_label)
|
||||
values_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
values_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
accel_row.add_child(values_label)
|
||||
|
||||
var orient_gizmo: OrientationGizmo = ORIENTATION_GIZMO_SCENE.instantiate()
|
||||
accel_row.add_child(orient_gizmo)
|
||||
|
||||
clients_list.add_child(panel)
|
||||
# clear() after enter_tree so @onready nodes exist; _ready also clears.
|
||||
orient_gizmo.clear()
|
||||
|
||||
_client_ui[cid] = {
|
||||
"available": available,
|
||||
@@ -360,6 +374,7 @@ func _populate_clients(clients: Array) -> void:
|
||||
"led_digit_row": led_digit_row,
|
||||
"led_blink_row": led_blink_row,
|
||||
"values_label": values_label,
|
||||
"orient_gizmo": orient_gizmo,
|
||||
}
|
||||
_update_led_fields(cid)
|
||||
|
||||
@@ -443,14 +458,18 @@ func _on_input(data: Dictionary) -> void:
|
||||
var ui: Dictionary = _client_ui[cid]
|
||||
var lines: PackedStringArray = []
|
||||
if client.get("valid", false):
|
||||
var ax := int(client.get("x", 0))
|
||||
var ay := int(client.get("y", 0))
|
||||
var az := int(client.get("z", 0))
|
||||
lines.append(
|
||||
"x=%d y=%d z=%d (age %sms)" % [
|
||||
int(client.get("x", 0)),
|
||||
int(client.get("y", 0)),
|
||||
int(client.get("z", 0)),
|
||||
ax, ay, az,
|
||||
str(client.get("accel_age_ms", "?")),
|
||||
]
|
||||
)
|
||||
ui["orient_gizmo"].set_accel(Vector3(float(ax), float(ay), float(az)))
|
||||
else:
|
||||
ui["orient_gizmo"].clear()
|
||||
|
||||
var tap_kind := str(client.get("tap_kind", "none"))
|
||||
if tap_kind != "none":
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
extends SubViewportContainer
|
||||
class_name OrientationGizmo
|
||||
|
||||
const MIN_ACCEL_LEN := 1000.0
|
||||
const SMOOTH := 0.25
|
||||
const VIEW_SIZE := Vector2(220, 220)
|
||||
const ACTIVE_MODULATE := Color(1, 1, 1, 1)
|
||||
const IDLE_MODULATE := Color(0.55, 0.58, 0.65, 0.85)
|
||||
|
||||
## Mesh TOP = local −Y.
|
||||
## Flat accel ≈ +Z → side view, TOP at top of screen
|
||||
## Facing accel ≈ −Y → TOP face toward camera
|
||||
## Steer accel ≈ −X → facing + roll left (steering wheel)
|
||||
var _basis_flat: Basis = Basis(Quaternion(Vector3.RIGHT, PI))
|
||||
var _basis_facing: Basis = Basis(Quaternion(Vector3.RIGHT, -PI * 0.5))
|
||||
|
||||
@onready var _viewport: SubViewport = $SubViewport
|
||||
@onready var _camera: Camera3D = $SubViewport/Camera3D
|
||||
@onready var _pod: Node3D = $SubViewport/Pod
|
||||
|
||||
var _has_sample := false
|
||||
var _target_basis := Basis.IDENTITY
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
custom_minimum_size = VIEW_SIZE
|
||||
stretch = true
|
||||
_viewport.own_world_3d = true
|
||||
_viewport.transparent_bg = true
|
||||
_viewport.size = Vector2i(VIEW_SIZE)
|
||||
_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||||
_camera.projection = Camera3D.PROJECTION_ORTHOGONAL
|
||||
_camera.size = 2.6
|
||||
_camera.near = 0.05
|
||||
_camera.far = 50.0
|
||||
_camera.position = Vector3(0.0, 0.0, 3.2)
|
||||
_camera.look_at(Vector3.ZERO, Vector3.UP)
|
||||
clear()
|
||||
|
||||
|
||||
func set_accel(v: Vector3) -> void:
|
||||
if v.length() < MIN_ACCEL_LEN:
|
||||
return
|
||||
_has_sample = true
|
||||
modulate = ACTIVE_MODULATE
|
||||
_target_basis = _basis_from_accel(v)
|
||||
|
||||
|
||||
func clear() -> void:
|
||||
_has_sample = false
|
||||
_target_basis = _basis_flat
|
||||
if _pod != null:
|
||||
_pod.basis = _basis_flat
|
||||
modulate = IDLE_MODULATE
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if not _has_sample:
|
||||
return
|
||||
_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)
|
||||
var roll := atan2(-n.x, -n.y)
|
||||
return Basis(Quaternion(Vector3.BACK, roll * face_t)) * b
|
||||
@@ -0,0 +1 @@
|
||||
uid://djoqip111hnbd
|
||||
+16
-93
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user