ridder
Version:
A straightforward game engine for simple data-driven games in JavaScript
122 lines (121 loc) • 3.6 kB
JavaScript
import { getHeight, getWidth } from "./canvas.js";
import { VECTOR_UP } from "./consts.js";
import { isRectangleValid, rect, setRectangle } from "./rectangle.js";
import { getDelta } from "./state.js";
import { clamp, random } from "./utils.js";
import { addVector, angleVector, copyVector, getVectorDistance, limitVector, normalizeVector, scaleVector, subtractVector, vec } from "./vector.js";
const position = vec();
const velocity = vec();
const target = vec();
const shake = vec();
const bounds = rect();
let smoothing = 1;
let zoom = 1;
let shakeIntensity = 0;
let shakeReduction = 0.1;
let shakeEnabled = true;
/**
* Updates the camera's `position` to the given target position ({@link x}, {@link y}). Does so smoothly if `smoothing` is smaller than 1.
*
* Updates the camera's `shake` vector, reducing the shaking `shakeIntensity` gradually with `shakeReduction`.
*
* All while taking into the camera's `zoom` factor into account.
*/
export function updateCamera(x, y) {
const delta = getDelta();
const scale = 1 / zoom;
const width = getWidth() * scale;
const height = getHeight() * scale;
target.x = x - width / 2;
target.y = y - height / 2;
if (smoothing < 1) {
const distance = getVectorDistance(position, target);
copyVector(velocity, target);
subtractVector(velocity, position);
normalizeVector(velocity);
scaleVector(velocity, distance * smoothing * delta);
limitVector(velocity, distance);
addVector(position, velocity);
}
else {
copyVector(position, target);
}
clampCameraToBounds(width, height);
if (shakeEnabled && shakeIntensity) {
shakeIntensity = Math.max(0, shakeIntensity - shakeReduction * delta);
copyVector(shake, VECTOR_UP);
angleVector(shake, random(0, 359));
scaleVector(shake, shakeIntensity * delta);
}
}
/**
* Snap the camera to the given position.
*/
export function setCameraPosition(x, y) {
const scale = 1 / zoom;
const width = getWidth() * scale;
const height = getHeight() * scale;
position.x = x - width / 2;
position.y = y - height / 2;
clampCameraToBounds(width, height);
}
/**
* Returns the camera's current position.
*
* NOTE - This is the top-left corner, not the center of the camera.
*/
export function getCameraPosition() {
return position;
}
/**
* Set the camera's smoothing value.
*/
export function setCameraSmoothing(value) {
smoothing = value;
}
/**
* The rectangular area which to bind the camera's movement within.
*/
export function setCameraBounds(x, y, width, height) {
setRectangle(bounds, x, y, width, height);
}
/**
* Get the camera's movement boundary.
*/
export function getCameraBounds() {
return bounds;
}
/**
* Set the current camera shake intensity and the value by which the intensity will be reduced every frame.
*/
export function setCameraShake(intensity, reduction) {
shakeIntensity = intensity;
shakeReduction = reduction;
}
/**
* Get the camera's shake vector.
*/
export function getCameraShake() {
return shake;
}
/**
* Set the camera's zoom value.
*/
export function setCameraZoom(value) {
zoom = value;
}
/**
* Get the camera's current zoom value.
*/
export function getCameraZoom() {
return zoom;
}
/**
* Keep the camera within its bounds.
*/
function clampCameraToBounds(width, height) {
if (isRectangleValid(bounds)) {
position.x = clamp(position.x, bounds.x, bounds.x + bounds.w - width);
position.y = clamp(position.y, bounds.y, bounds.y + bounds.h - height);
}
}