Skip to content

Instantly share code, notes, and snippets.

@MnkyArts
Last active August 3, 2024 15:30
Show Gist options
  • Save MnkyArts/f6cc526d46868720ac9f66f045f64f68 to your computer and use it in GitHub Desktop.
Save MnkyArts/f6cc526d46868720ac9f66f045f64f68 to your computer and use it in GitHub Desktop.
alt:V Camerapath Helper
class CameraPath {
waypoints: { position: alt.Vector3; rotation: alt.Vector3 }[];
totalDuration: number;
camera: number | null;
startTime: number;
isActive: boolean;
constructor(waypoints, totalDuration) {
if (waypoints.length < 2) {
throw new Error("At least two waypoints are required");
}
this.waypoints = waypoints;
this.totalDuration = totalDuration;
this.camera = null;
this.startTime = 0;
this.isActive = false;
}
start() {
if (this.isActive) {
return;
}
const start = this.waypoints[0];
this.camera = native.createCamWithParams(
"DEFAULT_SCRIPTED_CAMERA",
start.position.x,
start.position.y,
start.position.z,
start.rotation.x,
start.rotation.y,
start.rotation.z,
90, // FOV
true,
0
);
native.renderScriptCams(true, false, 0, true, false, 0);
this.startTime = Date.now();
this.isActive = true;
this.update();
}
update() {
if (!this.isActive) return;
const currentTime = Date.now();
const elapsedTime = currentTime - this.startTime;
const progress = Math.min(elapsedTime / this.totalDuration, 1);
if (progress >= 1) {
this.stop();
return;
}
const { position, rotation } = this.getInterpolatedState(progress);
native.setCamCoord(this.camera, position.x, position.y, position.z);
native.setCamRot(this.camera, rotation.x, rotation.y, rotation.z, 2);
alt.nextTick(() => this.update());
}
getInterpolatedState(progress) {
const totalDistance = this.getTotalDistance();
const targetDistance = totalDistance * progress;
let currentDistance = 0;
for (let i = 0; i < this.waypoints.length - 1; i++) {
const start = this.waypoints[i];
const end = this.waypoints[i + 1];
const segmentDistance = this.getDistance(start.position, end.position);
if (currentDistance + segmentDistance >= targetDistance) {
const segmentProgress = (targetDistance - currentDistance) / segmentDistance;
return {
position: this.interpolate(start.position, end.position, segmentProgress),
rotation: this.interpolateRotation(start.rotation, end.rotation, segmentProgress)
};
}
currentDistance += segmentDistance;
}
const lastWaypoint = this.waypoints[this.waypoints.length - 1];
return { position: lastWaypoint.position, rotation: lastWaypoint.rotation };
}
getTotalDistance() {
let distance = 0;
for (let i = 0; i < this.waypoints.length - 1; i++) {
distance += this.getDistance(this.waypoints[i].position, this.waypoints[i + 1].position);
}
return distance;
}
getDistance(point1, point2) {
const dx = point2.x - point1.x;
const dy = point2.y - point1.y;
const dz = point2.z - point1.z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
interpolate(start, end, progress) {
return {
x: start.x + (end.x - start.x) * progress,
y: start.y + (end.y - start.y) * progress,
z: start.z + (end.z - start.z) * progress
};
}
interpolateRotation(start, end, progress) {
return {
x: this.lerpAngle(start.x, end.x, progress),
y: this.lerpAngle(start.y, end.y, progress),
z: this.lerpAngle(start.z, end.z, progress)
};
}
lerpAngle(a, b, t) {
const diff = b - a;
const adjusted = ((diff + 180) % 360) - 180;
return a + adjusted * t;
}
stop() {
if (this.camera !== null) {
native.destroyAllCams(true);
native.renderScriptCams(false, false, 0, true, false, 0);
this.camera = null;
}
this.isActive = false;
}
}
// Usage example
const waypoints = [
{
position: { x: -279.37506103515625, y: -4014.04833984375, z: 283.5936279296875 },
rotation: { x: 0, y: 0, z: 0 }
},
{
position: { x: 0, y: 0, z: 500 },
rotation: { x: -30, y: 0, z: 45 }
},
{
position: { x: 496.1072692871094, y: 5524.7744140625, z: 811.158203125 },
rotation: { x: 15, y: 0, z: 180 }
}
];
const totalDuration = 10000; // 10 seconds for the entire path
const cameraPath = new CameraPath(waypoints, totalDuration);
cameraPath.start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment