Snowball cannon

Demo that illustrates how to achieve a cannon functionality with aiming.

by Sam Westwood

HTML

<div class="castle">
 <img src="https://www.misskatecuttables.com/uploads/shopping_cart/11354/large_princess-castle-0217.png" width="200px"; >
 </div>
 
 <canvas id="canvas" width="600" height="400" style="background:#ccc">
 
</canvas>

 <div class="cannon">
 <img src="https://toppng.com/public/uploads/preview/cannon-11523191672hmevozmt2k.png" width="50px"; >
 </div>

CSS

.cannon{
  position:absolute;
  top:280px;
  left:40px
 
}

.castle{
  position:absolute;
  top:130px;
  left:400px
 
}

JavaScript

(function () {
    'use strict';
    var alpha = 0,
        cannonSpeed = 420,
        canvas = null,
        ctx = null,
        gravity = 340,
        lastPress = null,
        lastUpdate = 0,
        mouse = {
            x: 0,
            y: 0
        },
        moving = false,
        player = new Circle(50, 300, 5),
        snowballs = [],
        track = [];
    window.addEventListener('load', init, false);

    function init() {
        canvas = document.getElementById('canvas');
        ctx = canvas.getContext('2d');

        enableInputs();
        run();
    }

    function Circle(x, y, radius) {
        this.x = (x == null) ? 0 : x;
        this.y = (y == null) ? 0 : y;
        this.radius = (radius == null) ? 0 : radius;
        this.vx = 0;
        this.vy = 0;
    }

    Circle.prototype.distance = function (circle) {
        if (circle != undefined) {
            var dx = this.x - circle.x;
            var dy = this.y - circle.y;
            return (Math.sqrt(dx * dx + dy * dy) - (this.radius + (circle.radius || 0)));
        }
    }

    Circle.prototype.fill = function (ctx) {
        if (ctx != undefined) {
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
            ctx.fill();
        }
    }

    Circle.prototype.getAngle = function (circle) {
        if (circle != undefined) {
            return (Math.atan2(this.y - circle.y, this.x - circle.x));
        }
    }

    Circle.prototype.setDirection = function (angle, speed) {
        if (speed != undefined) {
            this.vx = Math.cos(angle) * speed;
            this.vy = Math.sin(angle) * speed;
        }
    }

    function enableInputs() {
        document.addEventListener('mousemove', function (evt) {
            mouse.x = evt.pageX - canvas.offsetLeft;
            mouse.y = evt.pageY - canvas.offsetTop;
            moving = true;
        }, false);
        canvas.addEventListener('mousedown', function (evt) {
            lastPress...