Add volume state tracking and locomotion state management in FirstPersonNavigationController
This commit is contained in:
@@ -3,7 +3,7 @@ import { Euler, Vector3 } from "three";
|
|||||||
import type { Vec3 } from "../core/vector";
|
import type { Vec3 } from "../core/vector";
|
||||||
|
|
||||||
import { getFirstPersonPlayerEyeHeight } from "./player-collision";
|
import { getFirstPersonPlayerEyeHeight } from "./player-collision";
|
||||||
import type { NavigationController, RuntimeControllerContext } from "./navigation-controller";
|
import type { NavigationController, RuntimeControllerContext, RuntimeLocomotionState } from "./navigation-controller";
|
||||||
|
|
||||||
const LOOK_SENSITIVITY = 0.0022;
|
const LOOK_SENSITIVITY = 0.0022;
|
||||||
const MOVE_SPEED = 4.5;
|
const MOVE_SPEED = 4.5;
|
||||||
@@ -39,6 +39,9 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
private pitchRadians = 0;
|
private pitchRadians = 0;
|
||||||
private verticalVelocity = 0;
|
private verticalVelocity = 0;
|
||||||
private grounded = false;
|
private grounded = false;
|
||||||
|
private locomotionState: RuntimeLocomotionState = "flying";
|
||||||
|
private inWaterVolume = false;
|
||||||
|
private inFogVolume = false;
|
||||||
private pointerLocked = false;
|
private pointerLocked = false;
|
||||||
private initializedFromSpawn = false;
|
private initializedFromSpawn = false;
|
||||||
|
|
||||||
@@ -54,6 +57,9 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
this.pitchRadians = 0;
|
this.pitchRadians = 0;
|
||||||
this.verticalVelocity = 0;
|
this.verticalVelocity = 0;
|
||||||
this.grounded = false;
|
this.grounded = false;
|
||||||
|
this.locomotionState = "flying";
|
||||||
|
this.inWaterVolume = false;
|
||||||
|
this.inFogVolume = false;
|
||||||
this.initializedFromSpawn = true;
|
this.initializedFromSpawn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +102,7 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const playerShape = this.context.getRuntimeScene().playerCollider;
|
const playerShape = this.context.getRuntimeScene().playerCollider;
|
||||||
|
const currentVolumeState = this.context.resolvePlayerVolumeState(this.feetPosition);
|
||||||
const inputX = (this.pressedKeys.has("KeyD") ? 1 : 0) - (this.pressedKeys.has("KeyA") ? 1 : 0);
|
const inputX = (this.pressedKeys.has("KeyD") ? 1 : 0) - (this.pressedKeys.has("KeyA") ? 1 : 0);
|
||||||
const inputZ = (this.pressedKeys.has("KeyW") ? 1 : 0) - (this.pressedKeys.has("KeyS") ? 1 : 0);
|
const inputZ = (this.pressedKeys.has("KeyW") ? 1 : 0) - (this.pressedKeys.has("KeyS") ? 1 : 0);
|
||||||
const inputLength = Math.hypot(inputX, inputZ);
|
const inputLength = Math.hypot(inputX, inputZ);
|
||||||
@@ -117,6 +124,8 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
|
|
||||||
if (playerShape.mode === "none") {
|
if (playerShape.mode === "none") {
|
||||||
this.verticalVelocity = 0;
|
this.verticalVelocity = 0;
|
||||||
|
} else if (currentVolumeState.inWater) {
|
||||||
|
this.verticalVelocity = 0;
|
||||||
} else {
|
} else {
|
||||||
this.verticalVelocity -= GRAVITY * dt;
|
this.verticalVelocity -= GRAVITY * dt;
|
||||||
}
|
}
|
||||||
@@ -125,7 +134,7 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
this.feetPosition,
|
this.feetPosition,
|
||||||
{
|
{
|
||||||
x: horizontalX,
|
x: horizontalX,
|
||||||
y: playerShape.mode === "none" ? 0 : this.verticalVelocity * dt,
|
y: playerShape.mode === "none" || currentVolumeState.inWater ? 0 : this.verticalVelocity * dt,
|
||||||
z: horizontalZ
|
z: horizontalZ
|
||||||
},
|
},
|
||||||
playerShape
|
playerShape
|
||||||
@@ -138,10 +147,25 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.feetPosition = resolvedMotion.feetPosition;
|
this.feetPosition = resolvedMotion.feetPosition;
|
||||||
this.grounded = resolvedMotion.grounded;
|
const nextVolumeState = this.context.resolvePlayerVolumeState(this.feetPosition);
|
||||||
|
this.inWaterVolume = nextVolumeState.inWater;
|
||||||
|
this.inFogVolume = nextVolumeState.inFog;
|
||||||
|
this.grounded = nextVolumeState.inWater ? false : resolvedMotion.grounded;
|
||||||
|
|
||||||
|
if (playerShape.mode === "none") {
|
||||||
|
this.locomotionState = "flying";
|
||||||
|
} else if (this.inWaterVolume) {
|
||||||
|
this.locomotionState = "swimming";
|
||||||
|
} else if (this.grounded) {
|
||||||
|
this.locomotionState = "grounded";
|
||||||
|
} else {
|
||||||
|
this.locomotionState = "flying";
|
||||||
|
}
|
||||||
|
|
||||||
if (this.grounded && this.verticalVelocity < 0) {
|
if (this.grounded && this.verticalVelocity < 0) {
|
||||||
this.verticalVelocity = 0;
|
this.verticalVelocity = 0;
|
||||||
|
} else if (this.inWaterVolume) {
|
||||||
|
this.verticalVelocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateCameraTransform();
|
this.updateCameraTransform();
|
||||||
@@ -156,6 +180,9 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
this.pitchRadians = 0;
|
this.pitchRadians = 0;
|
||||||
this.verticalVelocity = 0;
|
this.verticalVelocity = 0;
|
||||||
this.grounded = false;
|
this.grounded = false;
|
||||||
|
this.locomotionState = "flying";
|
||||||
|
this.inWaterVolume = false;
|
||||||
|
this.inFogVolume = false;
|
||||||
this.updateCameraTransform();
|
this.updateCameraTransform();
|
||||||
this.publishTelemetry();
|
this.publishTelemetry();
|
||||||
}
|
}
|
||||||
@@ -188,6 +215,9 @@ export class FirstPersonNavigationController implements NavigationController {
|
|||||||
},
|
},
|
||||||
eyePosition: toEyePosition(this.feetPosition, getFirstPersonPlayerEyeHeight(this.context.getRuntimeScene().playerCollider)),
|
eyePosition: toEyePosition(this.feetPosition, getFirstPersonPlayerEyeHeight(this.context.getRuntimeScene().playerCollider)),
|
||||||
grounded: this.grounded,
|
grounded: this.grounded,
|
||||||
|
locomotionState: this.locomotionState,
|
||||||
|
inWaterVolume: this.inWaterVolume,
|
||||||
|
inFogVolume: this.inFogVolume,
|
||||||
pointerLocked: this.pointerLocked,
|
pointerLocked: this.pointerLocked,
|
||||||
spawn: this.context.getRuntimeScene().spawn
|
spawn: this.context.getRuntimeScene().spawn
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user