Implement manual pointer look input handling and update target assist logic
This commit is contained in:
@@ -179,6 +179,7 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
private inWaterVolume = false;
|
private inWaterVolume = false;
|
||||||
private inFogVolume = false;
|
private inFogVolume = false;
|
||||||
private dragging = false;
|
private dragging = false;
|
||||||
|
private pointerLookInputPending = false;
|
||||||
private lastPointerClientX = 0;
|
private lastPointerClientX = 0;
|
||||||
private lastPointerClientY = 0;
|
private lastPointerClientY = 0;
|
||||||
private initializedFromSpawn = false;
|
private initializedFromSpawn = false;
|
||||||
@@ -276,6 +277,7 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
this.jumpHoldRemainingMs = 0;
|
this.jumpHoldRemainingMs = 0;
|
||||||
this.previousTelemetry = null;
|
this.previousTelemetry = null;
|
||||||
this.smoothedCameraCollisionDistance = null;
|
this.smoothedCameraCollisionDistance = null;
|
||||||
|
this.pointerLookInputPending = false;
|
||||||
ctx.setRuntimeMessage(null);
|
ctx.setRuntimeMessage(null);
|
||||||
ctx.setPlayerControllerTelemetry(null);
|
ctx.setPlayerControllerTelemetry(null);
|
||||||
this.context = null;
|
this.context = null;
|
||||||
@@ -310,6 +312,7 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
this.inWaterVolume = false;
|
this.inWaterVolume = false;
|
||||||
this.inFogVolume = false;
|
this.inFogVolume = false;
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
|
this.pointerLookInputPending = false;
|
||||||
this.lastPointerClientX = 0;
|
this.lastPointerClientX = 0;
|
||||||
this.lastPointerClientY = 0;
|
this.lastPointerClientY = 0;
|
||||||
this.initializedFromSpawn = false;
|
this.initializedFromSpawn = false;
|
||||||
@@ -346,6 +349,9 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
|
|
||||||
const cameraDrivenExternally = this.context.isCameraDrivenExternally() === true;
|
const cameraDrivenExternally = this.context.isCameraDrivenExternally() === true;
|
||||||
const lookInputActive = lookInput.horizontal !== 0 || lookInput.vertical !== 0;
|
const lookInputActive = lookInput.horizontal !== 0 || lookInput.vertical !== 0;
|
||||||
|
const manualLookInputActive =
|
||||||
|
lookInputActive || this.pointerLookInputPending;
|
||||||
|
this.pointerLookInputPending = false;
|
||||||
let targetLookResult: RuntimeTargetLookInputResult | null = null;
|
let targetLookResult: RuntimeTargetLookInputResult | null = null;
|
||||||
|
|
||||||
if (!cameraDrivenExternally && lookInputActive) {
|
if (!cameraDrivenExternally && lookInputActive) {
|
||||||
@@ -385,7 +391,7 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
cameraDrivenExternally ||
|
cameraDrivenExternally ||
|
||||||
!lookInputActive ||
|
!manualLookInputActive ||
|
||||||
targetLookResult?.activeTargetLocked !== true ||
|
targetLookResult?.activeTargetLocked !== true ||
|
||||||
targetLookResult.switchedTarget === true ||
|
targetLookResult.switchedTarget === true ||
|
||||||
targetLookResult.switchInputHeld === true
|
targetLookResult.switchInputHeld === true
|
||||||
@@ -404,7 +410,7 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cameraDrivenExternally) {
|
if (!cameraDrivenExternally && !manualLookInputActive) {
|
||||||
const targetAssist =
|
const targetAssist =
|
||||||
this.context.resolveThirdPersonTargetAssist?.() ?? null;
|
this.context.resolveThirdPersonTargetAssist?.() ?? null;
|
||||||
|
|
||||||
@@ -449,7 +455,7 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
dt
|
dt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (cameraDrivenExternally) {
|
||||||
this.targetAssistLookOffsetY = dampScalar(
|
this.targetAssistLookOffsetY = dampScalar(
|
||||||
this.targetAssistLookOffsetY,
|
this.targetAssistLookOffsetY,
|
||||||
0,
|
0,
|
||||||
@@ -817,6 +823,12 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
this.lastPointerClientX = event.clientX;
|
this.lastPointerClientX = event.clientX;
|
||||||
this.lastPointerClientY = event.clientY;
|
this.lastPointerClientY = event.clientY;
|
||||||
|
|
||||||
|
if (deltaX === 0 && deltaY === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pointerLookInputPending = true;
|
||||||
|
|
||||||
const targetLookResult =
|
const targetLookResult =
|
||||||
this.context?.handleRuntimeTargetLookInput?.({
|
this.context?.handleRuntimeTargetLookInput?.({
|
||||||
horizontal: deltaX * POINTER_TARGET_LOOK_INPUT_SCALE,
|
horizontal: deltaX * POINTER_TARGET_LOOK_INPUT_SCALE,
|
||||||
|
|||||||
@@ -454,6 +454,60 @@ describe("ThirdPersonNavigationController", () => {
|
|||||||
controller.deactivate(targetContext);
|
controller.deactivate(targetContext);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("pauses third-person target assist while the camera is actively moved with pointer drag", () => {
|
||||||
|
const { context } = createRuntimeControllerContext();
|
||||||
|
const controller = new ThirdPersonNavigationController();
|
||||||
|
const controllerInternals = controller as unknown as {
|
||||||
|
cameraYawRadians: number;
|
||||||
|
pitchRadians: number;
|
||||||
|
targetAssistLookOffsetY: number;
|
||||||
|
};
|
||||||
|
const targetContext = {
|
||||||
|
...context,
|
||||||
|
resolveThirdPersonTargetAssist: () => ({
|
||||||
|
targetPosition: {
|
||||||
|
x: 0,
|
||||||
|
y: 4,
|
||||||
|
z: 5
|
||||||
|
},
|
||||||
|
strength: 1
|
||||||
|
}),
|
||||||
|
handleRuntimeTargetLookInput: vi.fn(() => ({
|
||||||
|
activeTargetLocked: true,
|
||||||
|
switchedTarget: false,
|
||||||
|
switchInputHeld: false
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.activate(targetContext);
|
||||||
|
controllerInternals.cameraYawRadians = 1.1;
|
||||||
|
controllerInternals.pitchRadians = 1.1;
|
||||||
|
controllerInternals.targetAssistLookOffsetY = 0;
|
||||||
|
|
||||||
|
targetContext.domElement.dispatchEvent(
|
||||||
|
new PointerEvent("pointerdown", {
|
||||||
|
button: 0,
|
||||||
|
clientX: 0,
|
||||||
|
clientY: 0
|
||||||
|
})
|
||||||
|
);
|
||||||
|
window.dispatchEvent(
|
||||||
|
new PointerEvent("pointermove", {
|
||||||
|
clientX: 30,
|
||||||
|
clientY: 12
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
controller.update(0.016);
|
||||||
|
|
||||||
|
expect(controllerInternals.cameraYawRadians).toBeCloseTo(1.1, 5);
|
||||||
|
expect(controllerInternals.pitchRadians).toBeCloseTo(1.1, 5);
|
||||||
|
expect(controllerInternals.targetAssistLookOffsetY).toBeCloseTo(0, 5);
|
||||||
|
|
||||||
|
window.dispatchEvent(new PointerEvent("pointerup"));
|
||||||
|
controller.deactivate(targetContext);
|
||||||
|
});
|
||||||
|
|
||||||
it("fades vertical target assist when camera collision pushes the camera close", () => {
|
it("fades vertical target assist when camera collision pushes the camera close", () => {
|
||||||
const { context } = createRuntimeControllerContext();
|
const { context } = createRuntimeControllerContext();
|
||||||
const controller = new ThirdPersonNavigationController();
|
const controller = new ThirdPersonNavigationController();
|
||||||
|
|||||||
Reference in New Issue
Block a user