From 142efe1e47a516b2ccd8f21710f78a7e903944eb Mon Sep 17 00:00:00 2001 From: Cristian Marcelo de Picciotto Date: Sun, 13 Oct 2024 01:29:19 -0300 Subject: [PATCH] feat: init car controls [#1] --- docs/js/core/car.js | 45 +++++--- docs/js/core/car/control.js | 198 ++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 docs/js/core/car/control.js diff --git a/docs/js/core/car.js b/docs/js/core/car.js index f8eac4b..ac4e6d0 100644 --- a/docs/js/core/car.js +++ b/docs/js/core/car.js @@ -2,7 +2,14 @@ * @description Car * @author C. M. de Picciotto (https://d3p1.dev/) */ +import Control from './car/control.js' + export default class Car { + /** + * @type {Control} + */ + control + /** * @type {number} */ @@ -26,26 +33,28 @@ export default class Car { /** * Constructor * - * @param {number} centerX - * @param {number} centerY - * @param {number} width - * @param {number} height + * @param {number} centerX + * @param {number} centerY + * @param {number} width + * @param {number} height + * @param {Control} control */ - constructor(centerX, centerY, width, height) { + constructor(centerX, centerY, width, height, control = new Control()) { this.centerX = centerX this.centerY = centerY this.width = width this.height = height + this.control = control } /** * Update car * - * @param {number} t + * @param {number} t Delta time in seconds * @returns {void} */ update(t) { - console.log(t) + this.control.update(t) } /** @@ -58,13 +67,23 @@ export default class Car { * drawing commands like `lineTo()`, `arc()`, etc. */ draw(context) { + context.save() + context.translate(this.centerX, this.centerY) + context.rotate(this.control.angle) + this.#draw(context, -this.width / 2, -this.height / 2) + context.restore() + } + + /** + * Draw + * + * @param {CanvasRenderingContext2D} context + * @param {number} x + * @param {number} y + */ + #draw(context, x, y) { context.beginPath() - context.rect( - this.centerX - this.width / 2, - this.centerY - this.height / 2, - this.width, - this.height, - ) + context.rect(x, y, this.width, this.height) context.fill() } } diff --git a/docs/js/core/car/control.js b/docs/js/core/car/control.js new file mode 100644 index 0000000..a572ac8 --- /dev/null +++ b/docs/js/core/car/control.js @@ -0,0 +1,198 @@ +/** + * @description Car control + * @author C. M. de Picciotto (https://d3p1.dev/) + */ +export default class Control { + /** + * @type {number} + */ + friction + + /** + * @type {number} + * @note This is the angular force + */ + torque + + /** + * @type {number} + * @note This is the angular acceleration. Generally, `alpha` is the + * greek letter that denotes angular acceleration + */ + alpha = 0 + + /** + * @type {number} + * @note This is the angular velocity. Generally, `omega` is the + * greek letter that denotes angular velocity + */ + omega = 0 + + /** + * @type {number} + */ + angle = 0 + + /** + * @type {boolean} + */ + forward = false + + /** + * @type {boolean} + */ + reverse = false + + /** + * @type {boolean} + */ + left = false + + /** + * @type {boolean} + */ + right = false + + /** + * Constructor + * + * @param {number} friction + * @param {number} torque + */ + constructor(friction = 0, torque = 20) { + this.friction = friction + this.torque = torque + + this.#addKeyListeners() + } + + /** + * Update + * + * @param {number} t Delta time in seconds + * @returns {void} + * @note Calculate the car angle based on the pressed key + */ + update(t) { + this.#applyAcceleration(t) + this.#applyFriction(t) + this.angle += this.omega * t + } + + /** + * Apply friction + * + * @param {number} t Delta time in seconds + * @returns {void} + * @note Friction is a force that is always opposite + * to the movement/velocity/`omega`. + * If there is no movement, there is no friction. + * That is why friction decelerates the movement/velocity/`omega` + * until it reaches `0`. At that moment, the friction disappears + */ + #applyFriction(t) { + if (Math.abs(this.friction) > Math.abs(this.omega)) { + this.omega = 0 + } else if (this.omega > 0) { + this.omega -= this.friction * t + } else if (this.omega < 0) { + this.omega += this.friction * t + } + } + + /** + * Apply acceleration + * + * @param {number} t Delta time in seconds + * @returns {void} + * @note The acceleration is how much the velocity + * is changed in a given time, that is why + * the `omega`/angular velocity is changed by the + * `alpha`/angular acceleration amount + */ + #applyAcceleration(t) { + this.omega += this.alpha * t + } + + /** + * Add key listeners + * + * @returns {void} + */ + #addKeyListeners() { + this.#addKeyDownListener() + this.#addKeyUpListener() + } + + /** + * Add key down listener + * + * @returns {void} + * @note When left or right arrows are pressed, it is considered that + * the user is applying a `torque` to the car. Because `torque` is + * an angular force, and every force causes acceleration, then + * the `alpha`/angular acceleration is created/generated + */ + #addKeyDownListener() { + window.addEventListener('keydown', (e) => { + switch (e.code) { + case 'ArrowUp': + this.forward = true + break + + case 'ArrowDown': + this.reverse = true + break + + case 'ArrowLeft': + this.left = true + this.alpha = -this.torque + break + + case 'ArrowRight': + this.right = true + this.alpha = +this.torque + break + } + }) + } + + /** + * Add key up listener + * + * @returns {void} + * @note When left or right arrows are released, it is considered that + * the user stops applying a `torque` to the car. + * Because `torque` is an angular force, + * and every force causes acceleration, then + * the `alpha`/angular acceleration is removed + * @todo For now, we are note going to use friction, and the + * `omega`/angular velocity will be reduce immediately to `0` + * without any force acting on it + */ + #addKeyUpListener() { + window.addEventListener('keyup', (e) => { + switch (e.code) { + case 'ArrowUp': + this.forward = false + break + + case 'ArrowDown': + this.reverse = false + break + + case 'ArrowLeft': + this.left = false + this.alpha = 0 + this.omega = 0 + break + + case 'ArrowRight': + this.right = false + this.alpha = 0 + this.omega = 0 + break + } + }) + } +}