SOURCE / PINNED RELEASE
Made of little things.
Supersonic RC Revive
- Release
- 1ba42f1ca1d6…
- Author-recorded commit
- baecad10b1cd…
- License
- LICENSE
- Author’s source reference
- nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-143146b0d6f
Archive hash verified: 90d22b206672eba4…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
// Port of "ParentScript 7 - camera": a chase camera that eases towards a
// point 50 units behind the car and is pulled in front of occluders.
import { Vector3 } from 'three';
import type { RayWorld } from '../physics/rayWorld.js';
import type { Car } from './car.js';
export class ChaseCamera {
worldPosition = new Vector3(-2000, -584, 250);
readonly target = new Vector3();
readonly up = new Vector3(0, 0.01, 1);
fieldOfView = 70;
private pWannaBe = this.worldPosition.clone();
// The Lingo sets "pFolllowing = 1" (typo), so pFollowing starts VOID (0).
private pFollowing = 0;
private pOrbit = 0;
/** The black overlay added in new() until fadeIn(). */
blackedOut = true;
constructor(
private readonly car: Car,
private readonly rays: RayWorld,
private readonly milliseconds: () => number,
) {}
fadeIn(): void {
this.blackedOut = false;
}
carStoppedDriving(): void {
this.pOrbit = 1;
}
update(): void {
const rb = this.car.rb;
const carPos = rb.position;
if (this.pOrbit === 0) {
const tDontFollow = rb.linearVelocity.length() < 10 ? 1 : 0;
if (this.pFollowing && tDontFollow === 0) {
const tBehindDir = rb.linearVelocity.negate();
tBehindDir.z = 0;
tBehindDir.normalize();
this.pWannaBe = carPos.clone().addScaledVector(tBehindDir, 50);
} else {
const yAxis = new Vector3().setFromMatrixColumn(this.car.modelTransform(), 1);
this.pWannaBe = carPos.clone().addScaledVector(yAxis.negate(), 50);
if (carPos.distanceTo(this.worldPosition) > 300) this.pFollowing = 1;
}
this.pWannaBe.z = carPos.z + 10;
} else {
const tTime = this.milliseconds() / 1000;
this.pWannaBe = carPos.clone().add(new Vector3(Math.sin(tTime) * 150, Math.cos(tTime) * 150, 50));
}
this.worldPosition.add(this.pWannaBe.clone().sub(this.worldPosition).multiplyScalar(0.1));
this.target.copy(carPos).add(new Vector3(0, 0, 10));
const hit = this.rays.modelsUnderRay(this.target, this.worldPosition.clone().sub(this.target));
if (hit && hit.isectPosition.distanceTo(this.target) < this.worldPosition.distanceTo(this.target)) {
this.worldPosition.copy(hit.isectPosition);
}
}
}
