Skip to content

Commit

Permalink
feat(cameras): make bounds strict on fixed axis controller
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaisthorpe committed Sep 14, 2024
1 parent d0d5425 commit fb01f13
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 47 deletions.
5 changes: 5 additions & 0 deletions .changeset/soft-pumpkins-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tedengine/ted': minor
---

Ensure bounds are strictly kept for fixed axis camera controller
20 changes: 15 additions & 5 deletions packages/ted/src/cameras/base-camera-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,27 @@ export default class TBaseCameraController {

private targetPosition?: vec3;
private targetLookAt?: vec3;
private instantMove = false;
private instantLookAt = false;

/**
* Move the camera to the specified position using linear interpolation.
* @param position The target position to move the camera to.
* @param instant If true, move the camera instantly without interpolation.
*/
public moveTo(position: vec3) {
public moveTo(position: vec3, instant = false) {
this.targetPosition = vec3.clone(position);
this.instantMove = instant;
}

/**
* Adjust the camera to look at the specified target position using linear interpolation.
* @param target The target position to look at.
* @param instant If true, rotate the camera instantly without interpolation.
*/
public lookAt(target: vec3) {
public lookAt(target: vec3, instant = false) {
this.targetLookAt = vec3.clone(target);
this.instantLookAt = instant;
}

/**
Expand All @@ -53,11 +59,12 @@ export default class TBaseCameraController {
camera.cameraComponent.getWorldTransform().translation;

if (this.targetPosition) {
if (this.lerpFactor >= 1) {
if (this.instantMove || this.lerpFactor >= 1) {
camera.cameraComponent.transform.translation = vec3.clone(
this.targetPosition,
);
this.targetPosition = undefined;
this.instantMove = false;
} else {
camera.cameraComponent.transform.translation = this.lerpVector(
currentPosition,
Expand All @@ -78,9 +85,12 @@ export default class TBaseCameraController {

const desiredQuat = tempTransform.rotation;

if (this.lerpFactor >= 1) {
camera.cameraComponent.transform.rotation = quat.clone(desiredQuat);
if (this.instantLookAt || this.lerpFactor >= 1) {
camera.cameraComponent.transform.rotation = quat.clone(
tempTransform.rotation,
);
this.targetLookAt = undefined;
this.instantLookAt = false;
} else {
camera.cameraComponent.transform.rotation = this.lerpQuaternion(
camera.cameraComponent.transform.rotation,
Expand Down
33 changes: 0 additions & 33 deletions packages/ted/src/cameras/base-camera.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,37 +52,4 @@ describe('TBaseCamera', () => {
camera.lookAt(vec3.fromValues(-1, -2, -3));
expect([...camera.cameraComponent.transform.rotation]).toMatchSnapshot();
});

test('lerp = 1 should result in instant transition', async () => {
camera.lerp = 1;
camera.moveTo(vec3.fromValues(10, 10, 10));

await camera.onUpdate({} as any, 1);

expect(camera.cameraComponent.transform.translation).toEqual(
vec3.fromValues(10, 10, 10),
);
});

test('lerp = 0 should result in no movement', async () => {
camera.lerp = 0;
camera.moveTo(vec3.fromValues(10, 10, 10));

await camera.onUpdate({} as any, 1);

expect(camera.cameraComponent.transform.translation).toEqual(
vec3.fromValues(0, 0, 0),
);
});

test('lerp = 0.5 should result in partial movement', async () => {
camera.lerp = 0.5;
camera.moveTo(vec3.fromValues(10, 10, 10));

await camera.onUpdate({} as any, 1);

expect(camera.cameraComponent.transform.translation).toEqual(
vec3.fromValues(5, 5, 5),
);
});
});
8 changes: 4 additions & 4 deletions packages/ted/src/cameras/fixed-axis-camera-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ describe('onUpdate with deadzone', () => {

const translation = vec3.fromValues(6, 2, 3);

jest.spyOn(camera, 'moveTo');
jest.spyOn(controller, 'moveTo');

controller.onUpdate(camera, {} as any, 0);

expect(camera.moveTo).toHaveBeenCalledWith(translation);
expect(controller.moveTo).toHaveBeenCalledWith(translation, false);
});

test('should not move camera if linear distance is less than or equal to deadzone', () => {
Expand All @@ -106,10 +106,10 @@ describe('onUpdate with deadzone', () => {
});
controller.attachTo(comp);

jest.spyOn(camera, 'moveTo');
jest.spyOn(controller, 'moveTo');

controller.onUpdate(camera, {} as any, 0);

expect(camera.moveTo).not.toHaveBeenCalled();
expect(controller.moveTo).not.toHaveBeenCalled();
});
});
15 changes: 10 additions & 5 deletions packages/ted/src/cameras/fixed-axis-camera-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ export default class TFixedAxisCameraController
engine: TEngine,
delta: number,
): Promise<void> {
await super.onUpdate(camera, engine, delta);

if (!this.component || !this.axisConfig[this.axis]) return;

const currentPosition = this.component.getWorldTransform().translation;
Expand Down Expand Up @@ -140,10 +138,13 @@ export default class TFixedAxisCameraController

const targetPosition = vec3.add(vec3.create(), leadPosition, distance);

// Apply bounds
// Apply bounds to target position
let outOfBounds = false;
if (this.bounds) {
const originalTarget = vec3.clone(targetPosition);
vec3.max(targetPosition, targetPosition, this.bounds.min);
vec3.min(targetPosition, targetPosition, this.bounds.max);
outOfBounds = !vec3.equals(originalTarget, targetPosition);
}

// Apply deadzone
Expand All @@ -152,14 +153,18 @@ export default class TFixedAxisCameraController
currentCameraPosition,
targetPosition,
);
if (distanceToTarget > this.deadzone) {
this.moveTo(targetPosition);

if (distanceToTarget > this.deadzone || outOfBounds) {
// Move the camera using the base controller method
this.moveTo(targetPosition, outOfBounds);

const rotation = quat.fromEuler(
quat.create(),
...this.axisConfig[this.axis].rotation,
);
camera.cameraComponent.transform.rotation = rotation;
}

await super.onUpdate(camera, engine, delta);
}
}

0 comments on commit fb01f13

Please sign in to comment.