Improve third-person climbing logic and planar movement detection

This commit is contained in:
2026-04-30 00:35:42 +02:00
parent e88dd59a7a
commit f022dac380
2 changed files with 28 additions and 12 deletions

View File

@@ -15,6 +15,8 @@ import {
CLIMB_INPUT_ACTIVE_THRESHOLD,
CLIMB_SPEED_METERS_PER_SECOND,
computeClimbPlaneMovement,
isClimbMovementIntoSurface,
resolveClimbPlanarInputDirection,
shouldEnterClimbing,
shouldExitClimbing,
type RuntimePlayerClimbSurface
@@ -665,7 +667,10 @@ export class ThirdPersonNavigationController implements NavigationController {
this.publishTelemetry();
}
private resolveClimbProbeDirection(movementYawRadians: number): Vec3 {
private resolveClimbProbeDirection(
movementYawRadians: number,
inputState: ReturnType<typeof resolvePlayerStartActionInputs>
): Vec3 {
if (this.climbSurface !== null) {
return {
x: -this.climbSurface.normal.x,
@@ -674,6 +679,15 @@ export class ThirdPersonNavigationController implements NavigationController {
};
}
const inputDirection = resolveClimbPlanarInputDirection(
inputState,
movementYawRadians
);
if (inputDirection.direction !== null) {
return inputDirection.direction;
}
return {
x: Math.sin(movementYawRadians),
y: 0,
@@ -731,22 +745,27 @@ export class ThirdPersonNavigationController implements NavigationController {
const climbPressed = inputState.climb > CLIMB_INPUT_ACTIVE_THRESHOLD;
const jumpPressed = inputState.jump > CLIMB_INPUT_ACTIVE_THRESHOLD;
if (!climbPressed) {
this.climbLatchBlocked = false;
}
const climbSurface =
this.context.resolvePlayerClimbSurface?.(
this.feetPosition,
this.resolveClimbProbeDirection(movementYawRadians),
this.resolveClimbProbeDirection(movementYawRadians, inputState),
this.standingPlayerShape,
this.climbSurface
) ?? null;
const movementIntoSurface = isClimbMovementIntoSurface({
input: inputState,
movementYawRadians,
surface: climbSurface
});
const climbIntentActive = climbPressed || movementIntoSurface;
if (!climbIntentActive) {
this.climbLatchBlocked = false;
}
if (
this.climbSurface !== null &&
shouldExitClimbing({
climbInput: inputState.climb,
surface: climbSurface,
jumpPressed
})
@@ -812,10 +831,6 @@ export class ThirdPersonNavigationController implements NavigationController {
return true;
}
if (climbSurface === null && climbPressed) {
this.climbLatchBlocked = true;
}
return false;
}
@@ -824,6 +839,7 @@ export class ThirdPersonNavigationController implements NavigationController {
(this.climbLatchBlocked ||
!shouldEnterClimbing({
climbInput: inputState.climb,
movementIntoSurface,
surface: climbSurface,
jumpPressed
}))

View File

@@ -143,7 +143,7 @@ describe("player climbing helpers", () => {
isClimbMovementIntoSurface({
input: createInputState({ moveForward: 1 }),
movementYawRadians: 0,
surface,
surface
})
).toBe(true);
expect(