Physics_topDownCarMovimentation.js
import { clamp } from "../Maths/clamp.js";
/**
* Updates the position, rotation, and speed of a car in a top-down view.
*
* The algorithm is based on {@link https://www.youtube.com/watch?v=Rs_rAxEsAvI}.
*
* @see example -> {@link https://codesandbox.io/s/top-down-car-movimentation-sobjn0}
*
* @param {Object} state - the current state of the car
* @param {Object} state.keys - the object containing the input keys
* @param {boolean} [state.keys.forward=false] - true if the forward key is pressed
* @param {boolean} [state.keys.left=false] - true if the left key is pressed
* @param {boolean} [state.keys.right=false] - true if the right key is pressed
* @param {boolean} [state.keys.reverse=false] - true if the reverse key is pressed
* @param {number} state.x - the current x position of the car
* @param {number} state.y - the current y position of the car
* @param {number} state.speed - the current car speed
* @param {number} state.acceleration - the acceleration value per update
* @param {number} [state.maxSpeed=Infinity] - the maximum speed limit of the car
* @param {number} [state.friction=0] - the friction of the car (0 to 1)
* @param {number} state.rotation - the current car rotation
* @param {number} state.rotationSpeed - the car rotation speed
* @param {Object} state.bounds - the maximum position limits on the axes
* @param {Object} state.bounds.x - the maximum x axis position limits
* @param {number} [state.bounds.x.min=-Infinity] - the minimum x axis limit
* @param {number} [state.bounds.x.max=Infinity] - the maximum x axis limit
* @param {Object} state.bounds.y - the maximum y axis position limits
* @param {number} [state.bounds.y.min=-Infinity] - the minimum y axis limit
* @param {number} [state.bounds.y.max=Infinity] - the maximum y axis limit
* @returns {Object}
*
* @function topDownCarMovimentation
* @memberof Physics
*/
export function topDownCarMovimentation({
keys = { forward: false, left: false, right: false, reverse: false },
x, y,
speed,
acceleration,
maxSpeed = Infinity,
friction = 0,
rotation,
rotationSpeed,
bounds = {
x: { min: -Infinity, max: Infinity },
y: { min: -Infinity, max: Infinity },
}
}) {
// Add Speed
if (keys.forward) speed += acceleration;
else if (keys.reverse) speed -= acceleration;
// Limit Speed
const reverseForce = Number(keys.reverse) + 1; // if the forward and reverse are pressed at the same time
if (speed > maxSpeed) speed = maxSpeed / reverseForce;
else if (speed < -maxSpeed / 2) speed = -maxSpeed / 2;
// Friction
if (speed > 0) speed -= friction;
else if (speed < 0) speed += friction;
if (Math.abs(speed) < friction) speed = 0; // if the speed is less than the friction, set it to 0
// Rotation
if (speed) {
const flip = speed > 0 ? 1 : -1; // Check if the forward or reverse
if (keys.left) rotation -= rotationSpeed * flip;
if (keys.right) rotation += rotationSpeed * flip;
}
// Update position
const newX = x + Math.sin(rotation) * speed;
const newY = y - Math.cos(rotation) * speed;
// Check if the car is out of bounds and return values
return {
x: clamp(newX, bounds.x.min, bounds.x.max),
y: clamp(newY, bounds.y.min, bounds.y.max),
speed,
rotation,
}
}