auto-git:

[change] src/runtime-three/first-person-navigation-controller.ts
This commit is contained in:
2026-05-01 16:46:05 +02:00
parent 6d57ead353
commit 9f4471a260

View File

@@ -22,8 +22,10 @@ import {
type RuntimePlayerClimbSurface
} from "./player-climbing";
import {
resolvePlayerLedgeGrabTarget,
resolvePlayerEdgeAssistTopOut,
shouldAttemptPlayerEdgeAssist
shouldAttemptPlayerEdgeAssist,
type RuntimePlayerLedgeGrabTarget
} from "./player-edge-assist";
import {
createIdleRuntimeLocomotionState,
@@ -60,6 +62,10 @@ function toEyePosition(feetPosition: Vec3, eyeHeight: number): Vec3 {
};
}
function dotPlanarVec3(left: Vec3, right: Vec3): number {
return left.x * right.x + left.z * right.z;
}
function cloneRuntimePlayerMovement(
movement: RuntimePlayerMovement
): RuntimePlayerMovement {
@@ -141,6 +147,7 @@ export class FirstPersonNavigationController implements NavigationController {
private jumpHoldRemainingMs = 0;
private climbSurface: RuntimePlayerClimbSurface | null = null;
private climbLatchBlocked = false;
private ledgeGrabTarget: RuntimePlayerLedgeGrabTarget | null = null;
activate(ctx: RuntimeControllerContext): void {
this.context = ctx;
@@ -247,6 +254,7 @@ export class FirstPersonNavigationController implements NavigationController {
this.jumpHoldRemainingMs = 0;
this.climbSurface = null;
this.climbLatchBlocked = false;
this.ledgeGrabTarget = null;
this.previousTelemetry = null;
ctx.setRuntimeMessage(null);
ctx.setPlayerControllerTelemetry(null);
@@ -291,6 +299,7 @@ export class FirstPersonNavigationController implements NavigationController {
this.jumpHoldRemainingMs = 0;
this.climbSurface = null;
this.climbLatchBlocked = false;
this.ledgeGrabTarget = null;
}
update(dt: number): void {
@@ -321,6 +330,12 @@ export class FirstPersonNavigationController implements NavigationController {
);
}
if (
this.stepLedgeGrab(dt, inputState, playerMovement, this.yawRadians)
) {
return;
}
if (
this.stepClimbing(dt, inputState, playerMovement, this.yawRadians)
) {
@@ -376,7 +391,7 @@ export class FirstPersonNavigationController implements NavigationController {
inputState,
this.yawRadians
);
const edgeAssist =
const shouldTryEdgeAssist =
edgeInputDirection.direction !== null &&
shouldAttemptPlayerEdgeAssist({
enabled: playerMovement.edgeAssist.enabled,
@@ -387,7 +402,9 @@ export class FirstPersonNavigationController implements NavigationController {
planarSpeed: locomotionStep.locomotionState.planarSpeed,
collisionCount: locomotionStep.locomotionState.contact.collisionCount,
airborne: locomotionStep.locomotionState.locomotionMode === "airborne"
})
});
const edgeAssist =
shouldTryEdgeAssist && edgeInputDirection.direction !== null
? resolvePlayerEdgeAssistTopOut({
feetPosition: locomotionStep.feetPosition,
shape: locomotionStep.activeShape,
@@ -409,6 +426,40 @@ export class FirstPersonNavigationController implements NavigationController {
}
})
: null;
if (
edgeAssist === null &&
shouldTryEdgeAssist &&
edgeInputDirection.direction !== null
) {
const ledgeGrabTarget = resolvePlayerLedgeGrabTarget({
feetPosition: locomotionStep.feetPosition,
shape: locomotionStep.activeShape,
direction: edgeInputDirection.direction,
pushToTopHeight: playerMovement.edgeAssist.pushToTopHeight,
canOccupyShape: (feetPosition, shape) =>
this.context?.canOccupyPlayerShape?.(feetPosition, shape) ?? true,
probeGround: (feetPosition, shape, maxDistance) =>
this.context?.probePlayerGround?.(
feetPosition,
shape,
maxDistance
) ?? {
grounded: false,
distance: null,
normal: null,
slopeDegrees: null
}
});
if (ledgeGrabTarget !== null) {
this.enterLedgeGrab(ledgeGrabTarget, edgeInputDirection.inputMagnitude);
this.updateCameraTransform();
this.publishTelemetry();
return;
}
}
const nextFeetPosition =
edgeAssist === null ? locomotionStep.feetPosition : edgeAssist.feetPosition;
const nextLocomotionState =
@@ -496,6 +547,7 @@ export class FirstPersonNavigationController implements NavigationController {
this.jumpHoldRemainingMs = 0;
this.climbSurface = null;
this.climbLatchBlocked = false;
this.ledgeGrabTarget = null;
this.inWaterVolume = false;
this.inFogVolume = false;
this.updateCameraTransform();