Projectile with vector
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Projectile test</title> <link rel="stylesheet" href="style.css"> </head>// w w w .ja v a 2s. c o m <body> <canvas id="canvas" width="700" height="500"></canvas> <script> class Vector2D { constructor(x, y) { this.x = x; this.y = y; } lengthSquared() { return this.x * this.x + this.y * this.y; } length() { return Math.sqrt(this.lengthSquared()); } clone() { return new Vector2D(this.x, this.y); } negate() { this.x = -this.x; this.y = -this.y; } normalize() { const length = this.length(); if (length > 0) { this.x /= length; this.y /= length; } return this.length(); } add({ x, y }) { return new Vector2D(this.x + x, this.y + y); } incrementBy({ x, y }) { this.x += x; this.y += y; } subtract({ x, y }) { return new Vector2D(this.x - x, this.y - y); } decrementBy({ x, y }) { this.x -= x; this.y -= y; } multiply(k) { return new Vector2D(k * this.x, k * this.y); } addScaled({ x, y }, k) { return new Vector2D(this.x + k * x, this.y + k * y); } scaleBy(k) { this.x *= k; this.y *= k; } dotProduct({ x, y }) { return this.x * x + this.y * y; } } Vector2D.distance = (vec1, vec2) => (vec1.subtract(vec2)).length() Vector2D.angleBetween = (vec1, vec2) => Math.acos(vec1.dotProduct(vec2) / (vec1.length() * vec2.length())) class Ball { constructor() { this.radius = 20; this.color = '#0000ff'; this.mass = 1; this.charge = 0; this.x = 0; this.y = 0; this.vx = 0; this.vy = 0; } get pos2D() { return new Vector2D(this.x, this.y); } set pos2D({ x, y }) { this.x = x; this.y = y; } get velo2D() { return new Vector2D(this.vx, this.vy); } set velo2D({ x, y }) { this.vx = x; this.vy = y; } draw(context) { context.fillStyle = this.color; context.beginPath(); context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, true); context.closePath(); context.fill(); } } const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); let ball1; let ball2; let t; // time from start of simulation let t0; // time at last call let dt; // elapsed time between calls let animId; const pos0 = new Vector2D(100, 350); const velo0 = new Vector2D(20, -80); const acc = new Vector2D(0, 10); // acceleration due to gravity const animTime = 16; // duration of animation window.onload = init; function init() { ball1 = new Ball(15, '#000000', 1, 0, true); ball1.pos2D = pos0; ball1.velo2D = velo0; ball2 = new Ball(15, '#aaaaaa', 1, 0, true); ball2.pos2D = pos0; ball2.velo2D = velo0; ball1.draw(context); ball2.draw(context); t0 = new Date().getTime(); t = 0; animFrame(); } function animFrame() { animId = requestAnimationFrame(animFrame, canvas); onTimer(); } function onTimer() { const t1 = new Date().getTime(); dt = 0.001 * (t1 - t0); t0 = t1; if (dt > 0.2) { dt = 0; } // fix for bug if user switches tabs t += dt; // current time since start of simulation; not used here if (t < animTime) { move(); } } function move() { // numerical solution - Euler scheme ball1.pos2D = ball1.pos2D.addScaled(ball1.velo2D, dt); ball1.velo2D = ball1.velo2D.addScaled(acc, dt); // analytical solution ball2.pos2D = pos0.addScaled(velo0, t).addScaled(acc, 0.5 * t * t); ball2.velo2D = velo0.addScaled(acc, t); // display context.clearRect(0, 0, canvas.width, canvas.height); ball1.draw(context); ball2.draw(context); } </script> </body> </html>