Fix NPCs walking backwards

Avatars called Godot's look_at(), which points the node's -Z axis at the target,
but the rig's face (eyes/brows/mouth/focus disc, and the Blender successor) is on
+Z. Every walking NPC therefore faced away from its movement direction.

- add the pure yaw_towards(direction) helper (+Z forward) and use it in both
  movement paths and the reaction face-turn
- fix the head-turn offset to the same +Z convention (basis.z)
- test +Z/+X/-Z/arbitrary directions; recapture targeting screenshot
- TODO bug item moved to DONE, MEMORY records the convention

Headless 209/209.
This commit is contained in:
zwitschi committed 2026-11-01 12:30:41 +01:00
1 parent a7daae8a14
commit 0eb17e3bb4
6 files changed
+53 -9

No files matched your search

+13 -4
View File
@@ -252,6 +252,15 @@ static func queue_slot_for(index: int) -> Vector3:
]
return slots[clampi(index, 0, slots.size() - 1)]
## Yaw that makes the avatar's face (+Z, the procedural and Blender-front axis)
## point along `direction`. Godot's `look_at` aims -Z, which used to make every
## NPC walk backwards; keep the +Z convention in one tested helper.
static func yaw_towards(direction: Vector3) -> float:
var flat := Vector2(direction.x, direction.z)
if flat.length() < 0.001:
return 0.0
return atan2(flat.x, flat.y)
static func lod_tier_for_distance(distance: float) -> int:
if distance < LOD_TIERS[0]:
return 0
@@ -656,8 +665,8 @@ func _face_reaction_point(delta: float) -> void:
to_point.y = 0.0
if to_point.length() < 0.1:
return
var target_yaw := atan2(-to_point.x, -to_point.z)
rotation.y = lerp_angle(rotation.y, target_yaw, clampf(delta * 4.0, 0.0, 1.0))
rotation.y = lerp_angle(rotation.y, yaw_towards(to_point),
clampf(delta * 4.0, 0.0, 1.0))
func _physics_process(delta: float) -> void:
if npc == null or npc.fsm == null:
@@ -1021,7 +1030,7 @@ func _move_toward_target(delta: float) -> void:
return
dir = dir.normalized()
var speed := FLEE_SPEED if reaction_mode == "flee" else 1.3
look_at(global_position + Vector3(dir.x, 0, dir.z), Vector3.UP)
rotation.y = yaw_towards(dir)
if agent.avoidance_enabled:
# The navigation server returns the obstacle-aware velocity through
# velocity_computed; never dash straight at the point in the meantime.
@@ -1059,7 +1068,7 @@ func _move_direct(delta: float) -> void:
velocity.x = dir.x * speed
velocity.z = dir.z * speed
velocity.y -= 9.8 * delta
look_at(global_position + Vector3(dir.x, 0, dir.z), Vector3.UP)
rotation.y = yaw_towards(dir)
move_and_slide()
func _arrive() -> void: