Add air direction only setting for player movement
This commit is contained in:
@@ -65,6 +65,7 @@ function cloneRuntimePlayerMovement(
|
||||
maxHoldMs: movement.jump.maxHoldMs,
|
||||
moveWhileJumping: movement.jump.moveWhileJumping,
|
||||
moveWhileFalling: movement.jump.moveWhileFalling,
|
||||
directionOnly: movement.jump.directionOnly,
|
||||
bunnyHop: movement.jump.bunnyHop,
|
||||
bunnyHopBoost: movement.jump.bunnyHopBoost
|
||||
},
|
||||
@@ -313,6 +314,7 @@ export class FirstPersonNavigationController implements NavigationController {
|
||||
dt,
|
||||
feetPosition: this.feetPosition,
|
||||
movementYawRadians: this.yawRadians,
|
||||
airDirectionYawRadians: this.yawRadians,
|
||||
standingShape: this.standingPlayerShape,
|
||||
verticalVelocity: this.verticalVelocity,
|
||||
previousLocomotionState: this.locomotionState,
|
||||
|
||||
@@ -74,6 +74,7 @@ export interface StepPlayerLocomotionOptions {
|
||||
dt: number;
|
||||
feetPosition: Vec3;
|
||||
movementYawRadians: number;
|
||||
airDirectionYawRadians?: number;
|
||||
standingShape: FirstPersonPlayerShape;
|
||||
verticalVelocity: number;
|
||||
previousLocomotionState?: RuntimeLocomotionState;
|
||||
@@ -190,18 +191,50 @@ function computePlanarMotion(
|
||||
requestedPlanarSpeed: number,
|
||||
dt: number
|
||||
): { motion: Vec3; inputMagnitude: number } {
|
||||
const inputX = input.moveRight - input.moveLeft;
|
||||
const inputZ = input.moveForward - input.moveBackward;
|
||||
const rawMagnitude = Math.hypot(inputX, inputZ);
|
||||
const inputMagnitude = clampUnitInterval(rawMagnitude);
|
||||
const directionResult = computePlanarInputDirection(
|
||||
movementYawRadians,
|
||||
input
|
||||
);
|
||||
|
||||
if (rawMagnitude <= 0 || requestedPlanarSpeed <= 0 || dt <= 0) {
|
||||
if (
|
||||
directionResult.direction === null ||
|
||||
requestedPlanarSpeed <= 0 ||
|
||||
dt <= 0
|
||||
) {
|
||||
return {
|
||||
motion: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
inputMagnitude: directionResult.inputMagnitude
|
||||
};
|
||||
}
|
||||
|
||||
const planarDistance = requestedPlanarSpeed * dt;
|
||||
|
||||
return {
|
||||
motion: {
|
||||
x: directionResult.direction.x * planarDistance,
|
||||
y: 0,
|
||||
z: directionResult.direction.z * planarDistance
|
||||
},
|
||||
inputMagnitude: directionResult.inputMagnitude
|
||||
};
|
||||
}
|
||||
|
||||
function computePlanarInputDirection(
|
||||
movementYawRadians: number,
|
||||
input: PlayerStartActionInputState
|
||||
): { direction: Vec3 | null; inputMagnitude: number } {
|
||||
const inputX = input.moveRight - input.moveLeft;
|
||||
const inputZ = input.moveForward - input.moveBackward;
|
||||
const rawMagnitude = Math.hypot(inputX, inputZ);
|
||||
const inputMagnitude = clampUnitInterval(rawMagnitude);
|
||||
|
||||
if (rawMagnitude <= 0) {
|
||||
return {
|
||||
direction: null,
|
||||
inputMagnitude
|
||||
};
|
||||
}
|
||||
@@ -212,17 +245,24 @@ function computePlanarMotion(
|
||||
const forwardZ = Math.cos(movementYawRadians);
|
||||
const rightX = -Math.cos(movementYawRadians);
|
||||
const rightZ = Math.sin(movementYawRadians);
|
||||
const planarDistance = requestedPlanarSpeed * dt;
|
||||
const directionX =
|
||||
forwardX * normalizedInputZ + rightX * normalizedInputX;
|
||||
const directionZ =
|
||||
forwardZ * normalizedInputZ + rightZ * normalizedInputX;
|
||||
const directionMagnitude = Math.hypot(directionX, directionZ);
|
||||
|
||||
if (directionMagnitude <= 0) {
|
||||
return {
|
||||
direction: null,
|
||||
inputMagnitude
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
motion: {
|
||||
x:
|
||||
(forwardX * normalizedInputZ + rightX * normalizedInputX) *
|
||||
planarDistance,
|
||||
direction: {
|
||||
x: directionX / directionMagnitude,
|
||||
y: 0,
|
||||
z:
|
||||
(forwardZ * normalizedInputZ + rightZ * normalizedInputX) *
|
||||
planarDistance
|
||||
z: directionZ / directionMagnitude
|
||||
},
|
||||
inputMagnitude
|
||||
};
|
||||
@@ -251,6 +291,48 @@ function clearPlanarMovementInput(
|
||||
};
|
||||
}
|
||||
|
||||
function computeDirectionalAirMotion(options: {
|
||||
directionYawRadians: number;
|
||||
input: PlayerStartActionInputState;
|
||||
previousPlanarDisplacement: Vec3;
|
||||
dt: number;
|
||||
}): { motion: Vec3; inputMagnitude: number } {
|
||||
const directionResult = computePlanarInputDirection(
|
||||
options.directionYawRadians,
|
||||
options.input
|
||||
);
|
||||
const planarSpeed = computePlanarSpeedFromDisplacement(
|
||||
options.previousPlanarDisplacement,
|
||||
options.dt
|
||||
);
|
||||
|
||||
if (
|
||||
directionResult.direction === null ||
|
||||
planarSpeed <= 0 ||
|
||||
options.dt <= 0
|
||||
) {
|
||||
return {
|
||||
motion: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
inputMagnitude: directionResult.inputMagnitude
|
||||
};
|
||||
}
|
||||
|
||||
const planarDistance = planarSpeed * options.dt;
|
||||
|
||||
return {
|
||||
motion: {
|
||||
x: directionResult.direction.x * planarDistance,
|
||||
y: 0,
|
||||
z: directionResult.direction.z * planarDistance
|
||||
},
|
||||
inputMagnitude: directionResult.inputMagnitude
|
||||
};
|
||||
}
|
||||
|
||||
function isWaterLocomotionMode(
|
||||
locomotionMode: RuntimeLocomotionMode | null | undefined
|
||||
): boolean {
|
||||
@@ -502,6 +584,16 @@ export function stepPlayerLocomotion(
|
||||
const planarInput = airMovementAllowed
|
||||
? options.input
|
||||
: clearPlanarMovementInput(options.input);
|
||||
const directionalAirControlActive =
|
||||
!currentlyGrounded &&
|
||||
!jumpTriggered &&
|
||||
!currentSwimmableWater &&
|
||||
airMovementAllowed &&
|
||||
options.movement.jump.directionOnly;
|
||||
const previousPlanarSpeed = computePlanarSpeedFromDisplacement(
|
||||
options.previousPlanarDisplacement,
|
||||
options.dt
|
||||
);
|
||||
|
||||
const requestedPlanarSpeed =
|
||||
activeShape.mode !== "none" && !currentSwimmableWater
|
||||
@@ -511,12 +603,20 @@ export function stepPlayerLocomotion(
|
||||
? groundedRequestedPlanarSpeed
|
||||
: airborneRequestedPlanarSpeed
|
||||
: groundedRequestedPlanarSpeed;
|
||||
const planarMotionFromInput = computePlanarMotion(
|
||||
options.movementYawRadians,
|
||||
planarInput,
|
||||
requestedPlanarSpeed,
|
||||
options.dt
|
||||
);
|
||||
const planarMotionFromInput = directionalAirControlActive
|
||||
? computeDirectionalAirMotion({
|
||||
directionYawRadians:
|
||||
options.airDirectionYawRadians ?? options.movementYawRadians,
|
||||
input: planarInput,
|
||||
previousPlanarDisplacement: options.previousPlanarDisplacement,
|
||||
dt: options.dt
|
||||
})
|
||||
: computePlanarMotion(
|
||||
options.movementYawRadians,
|
||||
planarInput,
|
||||
requestedPlanarSpeed,
|
||||
options.dt
|
||||
);
|
||||
const preserveAirborneMomentum =
|
||||
activeShape.mode !== "none" &&
|
||||
!currentSwimmableWater &&
|
||||
@@ -710,11 +810,10 @@ export function stepPlayerLocomotion(
|
||||
sprinting,
|
||||
inputMagnitude: planarMotion.inputMagnitude,
|
||||
requestedPlanarSpeed: preserveAirborneMomentum
|
||||
? computePlanarSpeedFromDisplacement(
|
||||
options.previousPlanarDisplacement,
|
||||
options.dt
|
||||
)
|
||||
: requestedPlanarSpeed * planarMotion.inputMagnitude,
|
||||
? previousPlanarSpeed
|
||||
: (directionalAirControlActive
|
||||
? previousPlanarSpeed
|
||||
: requestedPlanarSpeed) * planarMotion.inputMagnitude,
|
||||
planarSpeed: actualPlanarSpeed,
|
||||
verticalVelocity,
|
||||
contact: resolveContactState(resolvedMotion, groundProbe, grounded)
|
||||
|
||||
@@ -287,6 +287,7 @@ function clonePlayerStartJumpSettings(
|
||||
maxHoldMs: jump.maxHoldMs,
|
||||
moveWhileJumping: jump.moveWhileJumping,
|
||||
moveWhileFalling: jump.moveWhileFalling,
|
||||
directionOnly: jump.directionOnly,
|
||||
bunnyHop: jump.bunnyHop,
|
||||
bunnyHopBoost: jump.bunnyHopBoost
|
||||
};
|
||||
|
||||
@@ -79,6 +79,7 @@ function cloneRuntimePlayerMovement(
|
||||
maxHoldMs: movement.jump.maxHoldMs,
|
||||
moveWhileJumping: movement.jump.moveWhileJumping,
|
||||
moveWhileFalling: movement.jump.moveWhileFalling,
|
||||
directionOnly: movement.jump.directionOnly,
|
||||
bunnyHop: movement.jump.bunnyHop,
|
||||
bunnyHopBoost: movement.jump.bunnyHopBoost
|
||||
},
|
||||
@@ -285,6 +286,7 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
dt,
|
||||
feetPosition: this.feetPosition,
|
||||
movementYawRadians: this.cameraYawRadians,
|
||||
airDirectionYawRadians: this.yawRadians,
|
||||
standingShape: this.standingPlayerShape,
|
||||
verticalVelocity: this.verticalVelocity,
|
||||
previousLocomotionState: this.locomotionState,
|
||||
|
||||
Reference in New Issue
Block a user