Refactor: Simplify third-person pointer lock and escape key handling
This commit is contained in:
@@ -298,7 +298,6 @@ import {
|
||||
DEFAULT_PLAYER_START_CAPSULE_RADIUS,
|
||||
DEFAULT_PLAYER_START_EYE_HEIGHT,
|
||||
DEFAULT_PLAYER_START_ALLOW_LOOK_INPUT_TARGET_SWITCH as DEFAULT_PLAYER_START_ALLOW_LOOK_INPUT_TARGET_SWITCH_VALUE,
|
||||
DEFAULT_PLAYER_START_INVERT_MOUSE_CAMERA_HORIZONTAL as DEFAULT_PLAYER_START_INVERT_MOUSE_CAMERA_HORIZONTAL_VALUE,
|
||||
DEFAULT_PLAYER_START_INTERACTION_ANGLE_DEGREES,
|
||||
DEFAULT_PLAYER_START_INTERACTION_REACH_METERS,
|
||||
DEFAULT_PLAYER_START_NAVIGATION_MODE,
|
||||
@@ -2769,10 +2768,6 @@ export function App({ store, initialStatusMessage }: AppProps) {
|
||||
playerStartTargetButtonCyclesActiveTargetDraft,
|
||||
setPlayerStartTargetButtonCyclesActiveTargetDraft
|
||||
] = useState(DEFAULT_PLAYER_START_TARGET_BUTTON_CYCLES_ACTIVE_TARGET_VALUE);
|
||||
const [
|
||||
playerStartInvertMouseCameraHorizontalDraft,
|
||||
setPlayerStartInvertMouseCameraHorizontalDraft
|
||||
] = useState(DEFAULT_PLAYER_START_INVERT_MOUSE_CAMERA_HORIZONTAL_VALUE);
|
||||
const [
|
||||
playerStartMovementTemplateDraft,
|
||||
setPlayerStartMovementTemplateDraft
|
||||
|
||||
@@ -166,7 +166,6 @@ export interface RuntimeControllerContext {
|
||||
input: RuntimeTargetLookInput
|
||||
): RuntimeTargetLookInputResult;
|
||||
handleRuntimeTargetLookBoundaryReached?(): boolean;
|
||||
handleThirdPersonPointerLockReleased?(): boolean;
|
||||
isCameraDrivenExternally(): boolean;
|
||||
getCameraYawRadians(): number;
|
||||
isInputSuspended(): boolean;
|
||||
|
||||
@@ -952,28 +952,6 @@ export class RuntimeHost {
|
||||
this.clearActiveRuntimeTarget();
|
||||
return false;
|
||||
},
|
||||
handleThirdPersonPointerLockReleased: () => {
|
||||
if (
|
||||
this.activeController !== this.thirdPersonController ||
|
||||
this.activeRuntimeTargetReference === null
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const clearTargetKeyboardBinding =
|
||||
this.resolveRuntimePlayerInputBindings().keyboard.clearTarget;
|
||||
|
||||
if (
|
||||
isPlayerStartMouseBindingCode(clearTargetKeyboardBinding) ||
|
||||
clearTargetKeyboardBinding !== "Escape"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.clearActiveRuntimeTarget();
|
||||
this.previousClearTargetInputActive = true;
|
||||
return true;
|
||||
},
|
||||
isCameraDrivenExternally: () =>
|
||||
this.resolveActiveRuntimeCameraRig() !== null ||
|
||||
this.resolveDialogueAttentionNpc() !== null,
|
||||
@@ -1093,8 +1071,8 @@ export class RuntimeHost {
|
||||
loadScene(runtimeScene: RuntimeSceneDefinition) {
|
||||
const requestId = ++this.collisionWorldRequestId;
|
||||
const preservePointerLockDuringLoad =
|
||||
this.activeController !== null &&
|
||||
this.activeController.id === this.desiredNavigationMode &&
|
||||
this.activeController === this.firstPersonController &&
|
||||
this.desiredNavigationMode === "firstPerson" &&
|
||||
document.pointerLockElement === this.domElement;
|
||||
|
||||
this.sceneReady = false;
|
||||
@@ -1548,13 +1526,7 @@ export class RuntimeHost {
|
||||
return;
|
||||
}
|
||||
|
||||
const preservePointerLockDuringControllerSwitch =
|
||||
this.activeController !== null &&
|
||||
document.pointerLockElement === this.domElement;
|
||||
|
||||
this.activeController?.deactivate(this.controllerContext, {
|
||||
releasePointerLock: !preservePointerLockDuringControllerSwitch
|
||||
});
|
||||
this.activeController?.deactivate(this.controllerContext);
|
||||
this.interactionSystem.reset();
|
||||
this.setInteractionPrompt(null);
|
||||
if (nextController === this.firstPersonController) {
|
||||
|
||||
@@ -181,7 +181,6 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
private inFogVolume = false;
|
||||
private pointerLocked = false;
|
||||
private suppressNextPointerLockError = false;
|
||||
private escapeLockedForTargeting = false;
|
||||
private dragging = false;
|
||||
private pointerLookInputPending = false;
|
||||
private lastPointerClientX = 0;
|
||||
@@ -308,7 +307,6 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
|
||||
this.pointerLocked = false;
|
||||
this.suppressNextPointerLockError = false;
|
||||
this.releaseEscapeKeyLock();
|
||||
this.dragging = false;
|
||||
this.jumpPressed = false;
|
||||
this.latestJumpStarted = false;
|
||||
@@ -359,7 +357,6 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
this.inFogVolume = false;
|
||||
this.pointerLocked = false;
|
||||
this.suppressNextPointerLockError = false;
|
||||
this.escapeLockedForTargeting = false;
|
||||
this.dragging = false;
|
||||
this.pointerLookInputPending = false;
|
||||
this.lastPointerClientX = 0;
|
||||
@@ -513,8 +510,6 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
);
|
||||
}
|
||||
|
||||
this.syncEscapeKeyLock();
|
||||
|
||||
const movementYawRadians =
|
||||
cameraDrivenExternally
|
||||
? this.context.getCameraYawRadians()
|
||||
@@ -795,11 +790,6 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
document.pointerLockElement === this.context.domElement;
|
||||
this.pointerLocked = pointerLocked;
|
||||
this.dragging = false;
|
||||
|
||||
if (!pointerLocked) {
|
||||
this.releaseEscapeKeyLock();
|
||||
}
|
||||
|
||||
this.context.setRuntimeMessage(
|
||||
pointerLocked
|
||||
? "Third Person mouse look active. Scroll to zoom, use the right stick for gamepad camera look, and press Escape to release the cursor."
|
||||
@@ -808,85 +798,6 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
this.publishTelemetry();
|
||||
}
|
||||
|
||||
private syncEscapeKeyLock() {
|
||||
if (typeof navigator === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
const keyboard = (
|
||||
navigator as Navigator & {
|
||||
keyboard?: {
|
||||
lock?: (keys?: string[]) => Promise<void>;
|
||||
unlock?: () => void;
|
||||
};
|
||||
}
|
||||
).keyboard;
|
||||
|
||||
const shouldLockEscape =
|
||||
this.pointerLocked &&
|
||||
this.context?.resolveThirdPersonTargetAssist?.() !== null &&
|
||||
typeof keyboard?.lock === "function";
|
||||
|
||||
if (!shouldLockEscape) {
|
||||
this.releaseEscapeKeyLock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.escapeLockedForTargeting) {
|
||||
return;
|
||||
}
|
||||
|
||||
void keyboard
|
||||
.lock?.(["Escape"])
|
||||
.then(() => {
|
||||
this.escapeLockedForTargeting = true;
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
private releaseEscapeKeyLock() {
|
||||
if (!this.escapeLockedForTargeting || typeof navigator === "undefined") {
|
||||
this.escapeLockedForTargeting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const keyboard = (
|
||||
navigator as Navigator & {
|
||||
keyboard?: {
|
||||
unlock?: () => void;
|
||||
};
|
||||
}
|
||||
).keyboard;
|
||||
|
||||
keyboard?.unlock?.();
|
||||
this.escapeLockedForTargeting = false;
|
||||
}
|
||||
|
||||
private requestPointerLock() {
|
||||
if (this.context === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pointerLockCapableElement = this.context
|
||||
.domElement as HTMLCanvasElement & {
|
||||
requestPointerLock?: () => void | Promise<void>;
|
||||
};
|
||||
|
||||
if (typeof pointerLockCapableElement.requestPointerLock !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
const pointerLockResult = pointerLockCapableElement.requestPointerLock();
|
||||
|
||||
if (pointerLockResult instanceof Promise) {
|
||||
pointerLockResult.catch(() => {
|
||||
this.context?.setRuntimeMessage(
|
||||
"Pointer lock request was denied. Drag orbit remains available in Third Person."
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private resolveHorizontalMouseLookSign() {
|
||||
return this.context?.getRuntimeScene().playerStart
|
||||
?.invertMouseCameraHorizontal === true
|
||||
@@ -966,7 +877,22 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
|
||||
if (document.pointerLockElement !== this.context.domElement) {
|
||||
this.suppressNextPointerLockError = false;
|
||||
this.requestPointerLock();
|
||||
const pointerLockCapableElement = this.context
|
||||
.domElement as HTMLCanvasElement & {
|
||||
requestPointerLock?: () => void | Promise<void>;
|
||||
};
|
||||
|
||||
if (typeof pointerLockCapableElement.requestPointerLock === "function") {
|
||||
const pointerLockResult = pointerLockCapableElement.requestPointerLock();
|
||||
|
||||
if (pointerLockResult instanceof Promise) {
|
||||
pointerLockResult.catch(() => {
|
||||
this.context?.setRuntimeMessage(
|
||||
"Pointer lock request was denied. Drag orbit remains available in Third Person."
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -1098,17 +1024,8 @@ export class ThirdPersonNavigationController implements NavigationController {
|
||||
};
|
||||
|
||||
private handlePointerLockChange = () => {
|
||||
const wasPointerLocked = this.pointerLocked;
|
||||
this.suppressNextPointerLockError = false;
|
||||
this.syncPointerLockState();
|
||||
|
||||
if (
|
||||
wasPointerLocked &&
|
||||
!this.pointerLocked &&
|
||||
this.context?.handleThirdPersonPointerLockReleased?.() === true
|
||||
) {
|
||||
this.requestPointerLock();
|
||||
}
|
||||
};
|
||||
|
||||
private handlePointerLockError = () => {
|
||||
|
||||
Reference in New Issue
Block a user