HTML5 Game - Projectile with vector

Description

Projectile with vector

Demo

ResultView the demo in separate window

<!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>