Test: third-person camera smooth recovery after collision clears
This commit is contained in:
@@ -167,6 +167,77 @@ describe("ThirdPersonNavigationController", () => {
|
|||||||
controller.deactivate(context);
|
controller.deactivate(context);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("smooths the third-person camera back out when collision clears", () => {
|
||||||
|
const { context } = createRuntimeControllerContext();
|
||||||
|
const controller = new ThirdPersonNavigationController();
|
||||||
|
let collisionScale = 0.25;
|
||||||
|
let latestPivot: Vec3 | null = null;
|
||||||
|
let latestDesiredCameraPosition: Vec3 | null = null;
|
||||||
|
const distanceBetween = (left: Vec3, right: Vec3) =>
|
||||||
|
Math.hypot(left.x - right.x, left.y - right.y, left.z - right.z);
|
||||||
|
|
||||||
|
context.resolveThirdPersonCameraCollision = vi.fn(
|
||||||
|
(pivot: Vec3, desiredCameraPosition: Vec3) => {
|
||||||
|
latestPivot = { ...pivot };
|
||||||
|
latestDesiredCameraPosition = { ...desiredCameraPosition };
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: pivot.x + (desiredCameraPosition.x - pivot.x) * collisionScale,
|
||||||
|
y: pivot.y + (desiredCameraPosition.y - pivot.y) * collisionScale,
|
||||||
|
z: pivot.z + (desiredCameraPosition.z - pivot.z) * collisionScale
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
controller.activate(context);
|
||||||
|
|
||||||
|
const blockedDistance = distanceBetween(
|
||||||
|
{
|
||||||
|
x: context.camera.position.x,
|
||||||
|
y: context.camera.position.y,
|
||||||
|
z: context.camera.position.z
|
||||||
|
},
|
||||||
|
latestPivot ?? { x: 0, y: 0, z: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
collisionScale = 1;
|
||||||
|
controller.update(0.1);
|
||||||
|
|
||||||
|
const recoveringDistance = distanceBetween(
|
||||||
|
{
|
||||||
|
x: context.camera.position.x,
|
||||||
|
y: context.camera.position.y,
|
||||||
|
z: context.camera.position.z
|
||||||
|
},
|
||||||
|
latestPivot ?? { x: 0, y: 0, z: 0 }
|
||||||
|
);
|
||||||
|
const desiredDistance = distanceBetween(
|
||||||
|
latestDesiredCameraPosition ?? { x: 0, y: 0, z: 0 },
|
||||||
|
latestPivot ?? { x: 0, y: 0, z: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(recoveringDistance).toBeGreaterThan(blockedDistance);
|
||||||
|
expect(recoveringDistance).toBeLessThan(desiredDistance);
|
||||||
|
|
||||||
|
controller.update(1);
|
||||||
|
|
||||||
|
const finalDistance = distanceBetween(
|
||||||
|
{
|
||||||
|
x: context.camera.position.x,
|
||||||
|
y: context.camera.position.y,
|
||||||
|
z: context.camera.position.z
|
||||||
|
},
|
||||||
|
latestPivot ?? { x: 0, y: 0, z: 0 }
|
||||||
|
);
|
||||||
|
const finalDesiredDistance = distanceBetween(
|
||||||
|
latestDesiredCameraPosition ?? { x: 0, y: 0, z: 0 },
|
||||||
|
latestPivot ?? { x: 0, y: 0, z: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(finalDistance).toBeCloseTo(finalDesiredDistance);
|
||||||
|
controller.deactivate(context);
|
||||||
|
});
|
||||||
|
|
||||||
it("uses lock-on look input as a temporary offset that returns to center", () => {
|
it("uses lock-on look input as a temporary offset that returns to center", () => {
|
||||||
const { context } = createRuntimeControllerContext();
|
const { context } = createRuntimeControllerContext();
|
||||||
const controller = new ThirdPersonNavigationController();
|
const controller = new ThirdPersonNavigationController();
|
||||||
|
|||||||
Reference in New Issue
Block a user