From 20bf3b9b0cf81a0eb42f92720046e739a79cf6ea Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Sat, 25 Apr 2026 04:14:46 +0200 Subject: [PATCH] auto-git: [change] src/runtime-three/third-person-navigation-controller.ts --- .../third-person-navigation-controller.ts | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/src/runtime-three/third-person-navigation-controller.ts b/src/runtime-three/third-person-navigation-controller.ts index ca3832fd..f5315522 100644 --- a/src/runtime-three/third-person-navigation-controller.ts +++ b/src/runtime-three/third-person-navigation-controller.ts @@ -36,6 +36,7 @@ const MIN_PITCH_RADIANS = -0.2; const MAX_PITCH_RADIANS = Math.PI * 0.45; export const THIRD_PERSON_CAMERA_COLLISION_RADIUS = 0.2; const CAMERA_PIVOT_EYE_HEIGHT_FACTOR = 0.85; +const TARGET_ASSIST_YAW_SPEED = 2.2; function clampPitch(pitchRadians: number): number { return Math.max( @@ -51,6 +52,24 @@ function clampCameraDistance(distance: number): number { ); } +function normalizeAngleRadians(angle: number): number { + return Math.atan2(Math.sin(angle), Math.cos(angle)); +} + +function dampAngleRadians( + current: number, + target: number, + strength: number, + dt: number +): number { + if (dt <= 0 || strength <= 0) { + return current; + } + + const alpha = 1 - Math.exp(-strength * dt); + return current + normalizeAngleRadians(target - current) * alpha; +} + function toEyePosition(feetPosition: Vec3, eyeHeight: number): Vec3 { return { x: feetPosition.x, @@ -278,18 +297,35 @@ export class ThirdPersonNavigationController implements NavigationController { runtimeScene.playerInputBindings ); - if ( - this.context.isCameraDrivenExternally() !== true && - (lookInput.horizontal !== 0 || lookInput.vertical !== 0) - ) { + const cameraDrivenExternally = this.context.isCameraDrivenExternally() === true; + + if (!cameraDrivenExternally && (lookInput.horizontal !== 0 || lookInput.vertical !== 0)) { this.cameraYawRadians -= lookInput.horizontal * GAMEPAD_LOOK_SPEED * dt; this.pitchRadians = clampPitch( this.pitchRadians - lookInput.vertical * GAMEPAD_LOOK_SPEED * dt ); } + if (!cameraDrivenExternally) { + const targetAssist = + this.context.resolveThirdPersonTargetAssist?.() ?? null; + + if (targetAssist !== null) { + const targetYaw = Math.atan2( + targetAssist.targetPosition.x - this.feetPosition.x, + targetAssist.targetPosition.z - this.feetPosition.z + ); + this.cameraYawRadians = dampAngleRadians( + this.cameraYawRadians, + targetYaw, + TARGET_ASSIST_YAW_SPEED * targetAssist.strength, + dt + ); + } + } + const movementYawRadians = - this.context.isCameraDrivenExternally() === true + cameraDrivenExternally ? this.context.getCameraYawRadians() : this.cameraYawRadians;