Playtest: WASD folgt der Blickrichtung (Sly-Befund 20.10.)

Bug: Die Laufrichtung kam aus transform.basis des Körperknotens — die
Kamera-Drehung steckt aber im look_cam-Kindknoten, der Körper rotiert
nicht → WASD lief stur in eine Himmelsrichtung. Auf der Quest rotiert
der ganze Origin mit dem Kopf, dort trat der Bug nicht auf.

Fix: forward/right aus yaw_deg bauen (identisch zu view_direction(),
identisch zum Kopf-Yaw des Clients). Regression in test_playtest:
yaw 0° + W → -Z, yaw 90° + W → -X. Suite 39/39 grün.
This commit is contained in:
Hermes (scopedvr-dev) 2026-10-20 21:10:09 +00:00
parent 0cdf68622c
commit 52919b36b4
2 changed files with 43 additions and 3 deletions

View file

@ -175,9 +175,15 @@ func _fahren(delta: float, input: Dictionary) -> void:
_apply_look() _apply_look()
return return
# Welt-Richtung aus dem Blickwinkel (y-only, wie Client). # Welt-Richtung aus dem Blickwinkel (y-only, wie Client). WICHTIG: aus
var forward := -transform.basis.z # yaw_deg bauen, NICHT aus transform.basis — die Kamera-Drehung steckt
var right := transform.basis.x # im look_cam-Kindknoten, der Körperknoten selbst rotiert nicht (Sly-
# Befund 20.10.: WASD lief sonst stur in eine Himmelsrichtung). Die
# Quest rotiert dagegen den ganzen Origin mit dem Kopf — hier
# entspricht yaw_deg diesem Kopf-Yaw. Identisch zu view_direction().
var yaw_rad := deg_to_rad(yaw_deg)
var forward := Vector3(-sin(yaw_rad), 0.0, -cos(yaw_rad))
var right := Vector3(cos(yaw_rad), 0.0, -sin(yaw_rad))
var dir := Vector3.ZERO var dir := Vector3.ZERO
var ad2: Variant = input.get("auto_dir", null) var ad2: Variant = input.get("auto_dir", null)
if ad2 is Vector3 and (ad2 as Vector3).length_squared() > 0.0: if ad2 is Vector3 and (ad2 as Vector3).length_squared() > 0.0:

View file

@ -63,6 +63,7 @@ func _run_all() -> void:
await _test_wall_blocks_player() await _test_wall_blocks_player()
await _test_step_up_semantics() await _test_step_up_semantics()
await _test_run_and_jump() await _test_run_and_jump()
await _test_yaw_relatives_laufen()
await _test_bauteile_treppe_tuer() await _test_bauteile_treppe_tuer()
_test_exit_restores_editor() _test_exit_restores_editor()
@ -332,6 +333,39 @@ func _test_run_and_jump() -> void:
_check(absf(body.fuss_hoehe() - feet0) < 0.05, "Landung wieder auf Terrainhöhe") _check(absf(body.fuss_hoehe() - feet0) < 0.05, "Landung wieder auf Terrainhöhe")
## --- Test 5b: Laufrichtung folgt der Blickrichtung (Sly-Befund 20.10.) ------
## Bug: WASD benutzte transform.basis des Körpers, aber die Kamera-Drehung
## steckt im look_cam-Kindknoten → WASD lief stur in eine Himmelsrichtung.
## Fix: Richtung aus yaw_deg bauen (wie view_direction(), wie Quest-Kopf-Yaw).
func _test_yaw_relatives_laufen() -> void:
print("Testgruppe: Laufrichtung folgt Blickrichtung (yaw)")
var body := _body()
if body == null:
_check(false, "Playtest-Body aktiv (Vorbedingung)")
return
var start := Vector3(body.position)
# Blick nach -Z (yaw 0): W muss nach -Z laufen.
body.set("yaw_deg", 0.0)
body.set("auto_input", {"fwd": true})
for i in 20:
await physics_frame
body.set("auto_input", {})
var d0 := Vector3(body.position) - start
_check(d0.z < -1.0 and absf(d0.x) < 0.6,
"yaw 0° + W → Bewegung nach -Z (d=%.1f, %.1f)" % [d0.x, d0.z])
# Blick um 90° gedreht (nach -X): W muss nach -X laufen, NICHT weiter -Z.
body.set("position", start)
body.set("velocity", Vector3.ZERO)
body.set("yaw_deg", 90.0)
await physics_frame
body.set("auto_input", {"fwd": true})
for i in 20:
await physics_frame
body.set("auto_input", {})
var d1 := Vector3(body.position) - start
_check(d1.x < -1.0 and absf(d1.z) < 0.6,
"yaw 90° + W → Bewegung folgt Blick nach -X (d=%.1f, %.1f)" % [d1.x, d1.z])
## --- Test 6: Rückkehr stellt den Editor-Zustand wieder her ------------------ ## --- Test 6: Rückkehr stellt den Editor-Zustand wieder her ------------------
func _test_exit_restores_editor() -> void: func _test_exit_restores_editor() -> void:
print("Testgruppe: Rückkehr in den Editor (Dokument + Undo unverändert)") print("Testgruppe: Rückkehr in den Editor (Dokument + Undo unverändert)")