smolworld / src /js /camera.js
p3nGu1nZz's picture
✨ Refactor physics module; add math utilities and event handling classes; update state structure for 3D entities
7ffaa9e
import { Transform } from './transform.js';
import { Matrix } from './matrix.js';
import { lerp } from './math.js';
import { getConfig } from './config.js';
export class Camera {
constructor() {
this.transform = new Transform();
this.scale = 1;
this.targetScale = 1;
this.viewportWidth = 0; // Initialize to 0, will be set by setViewport
this.viewportHeight = 0; // Initialize to 0, will be set by setViewport
this.targetPosition = { x: 0, y: 0, z: 0 };
// Set default values in case config isn't ready
this.moveLerpFactor = 0.1;
this.zoomLerpFactor = 0.1;
// Try to get config
const config = getConfig();
if (config?.camera) {
this.moveLerpFactor = config.camera.moveLerpFactor;
this.zoomLerpFactor = config.camera.zoomLerpFactor;
}
}
setViewport(width, height) {
this.viewportWidth = width;
this.viewportHeight = height;
}
getViewMatrix() {
// First translate to center of viewport
const centerMatrix = Matrix.translation(
this.viewportWidth / 2,
this.viewportHeight / 2,
0
);
// Then apply camera transform
const cameraMatrix = Matrix.multiply(
Matrix.scaling(this.scale, this.scale, 1),
Matrix.translation(
-this.transform.position.x,
-this.transform.position.y,
0
)
);
return Matrix.multiply(cameraMatrix, centerMatrix);
}
update(deltaTime) {
// Store old position to calculate velocity
if (this._oldPos === undefined) {
this._oldPos = { x: this.transform.position.x, y: this.transform.position.y };
}
// Smooth position movement
const pos = this.transform.position;
pos.x = lerp(pos.x, this.targetPosition.x, this.moveLerpFactor);
pos.y = lerp(pos.y, this.targetPosition.y, this.moveLerpFactor);
// Calculate velocity in units/s
const dx = pos.x - this._oldPos.x;
const dy = pos.y - this._oldPos.y;
this.currentVelocity = {
x: dx / deltaTime,
y: dy / deltaTime
};
this._oldPos.x = pos.x;
this._oldPos.y = pos.y;
// Smooth scale/zoom
this.scale = lerp(this.scale, this.targetScale, this.zoomLerpFactor);
}
moveBy(dx, dy, dz = 0) {
// Invert dy for natural camera movement (up is negative, down is positive)
this.targetPosition.x += dx;
this.targetPosition.y -= dy; // Invert dy here
this.targetPosition.z += dz;
}
moveTo(x, y, z = 0) {
this.targetPosition.x = x;
this.targetPosition.y = y;
this.targetPosition.z = z;
this.transform.setPosition(x, y, z); // Immediate for reset
}
setZoom(scale) {
this.targetScale = scale;
this.scale = scale; // Immediate for reset
}
zoomBy(factor) {
this.targetScale *= factor;
}
}