Cannon Ball! is a game I created that stemmed from a tutorial found in the book "The Essential Guide to HTML5". It's your typical Cannon shoots target game play. You control the cannon's angle & velocity with the arrow keys, and press space-bar to shoot. You have 5 chances to hit the grey square with your cannonball. The levels go on forever and you're given a score which adds up until you fail to hit the target in 5 tries.

Game Link: Cannon Ball!

Feel free to provide feedback such as bugs, or additions you'd like to see. Or just ask questions about my source and I'll answer them here.

Thinks I'd like to add:

  • Fix issue where ball collision isn't detected well.
  • High Score list.
  • A reset button after you lose.
  • On-screen score & instructions for manipulating the cannon.
The Code:
            var ctx,
                myBall,
                myCannon,
                physics,
                everything = [],
                targets = [],
                shotsLeft = [],
                shot = 0,
                gravity = 0.5,
                velocity = 10,
                score = 0,
                inMotion = false,
                level = 0;
        /**
         * DtoR - Degrees to Radian conversion
         * @param degrees
         * @returns radian equivilant
         */
        function DtoR(degrees){
            var radians = degrees * (Math.PI/180);
            return radians;
        }

        /**
         * Cannon
         * @param sx - Bottom left corner X coord
         * @param sy - Bottom left corner Y coord
         * @param angle - Starting angle of cannon
         * @param stylestring  - "rgb(250,50,50)"
         */
        function Cannon(sx, sy, angle, stylestring){
            this.sx = sx;
            this.sy = sy;
            this.length = 100;
            this.width = 25;
            this.angle = angle;
            this.fillStyle = stylestring;
            this.draw = function(){
                ctx.fillStyle = this.fillStyle;
                ctx.save();
                ctx.translate(this.sx,this.sy);
                ctx.rotate(DtoR(-1 * (this.angle + 90))); //The minus one is to reverse the angle.
                ctx.translate(-this.sx,-this.sy);
                ctx.fillRect(this.sx,this.sy,this.width, this.length);
                ctx.restore();
                //Base of cannon
                ctx.fillRect(this.sx-30,this.sy-30,50,60);
            }
            this.rotate = function(angle){
                this.angle = angle || 30;
            }
            this.getAngle = function(){
                return this.angle;
            }

        }

        function Myrectangle(sx,sy,swidth,sheight,stylestring) {
            this.sx = sx;
            this.sy = sy;
            this.swidth = swidth;
            this.sheight = sheight;
            this.fillstyle = stylestring;
            this.draw = function drawrects() {
                ctx.fillStyle = this.fillstyle;
                ctx.fillRect(this.sx,this.sy,this.swidth,this.sheight);
            };
        }

        function Ball(sx, sy, rad, stylestring){
            this.sx = sx; //Starting X coord
            this.sy = sy; //Starting Y coord
            this.rad = rad; //Radius
            this.fillstyle = stylestring;
            this.draw = function(){
                ctx.fillStyle = this.fillstyle;
                ctx.beginPath();
                ctx.arc(this.sx, this.sy, this.rad, 0, Math.PI*2, true);
                ctx.fill();
            };
            this.moveit = function(dx, dy){
                this.sx = this.sx + dx; //Increment X coord
                this.sy = this.sy + dy; //Increment Y coord
            };
        }

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

            // Create Ground
            ground = new Myrectangle(0,470,900,30,"rgb(154,205,0)");
            everything.push(ground);

            // Create Cannon Ball
            myBall = new Ball(55, 460, 10, "rgb(250,0,0)");
            everything.push(myBall);

            // Create Cannon
            myCannon = new Cannon(50, 450, 40, "rgb(150,105,105)");
            everything.push(myCannon);

            resetShotsLeft()

            generateTargets();

            //Draw our Canvas
            redrawCanvas();
        }

        function reset(){
            //Erase Canvas
            ctx.clearRect(0,0,900,500);

            resetShotsLeft()

            generateTargets();

            //Reset Cannon Ball
            myBall.sx = 55;
            myBall.sy = 460;

            redrawCanvas();

        }

        function resetShotsLeft(){
            // Shots Left
            var startingX = 890;
            shotsLeft.length = 0;
            for(var i=1; i=target.sx) && (bx=target.sy)&&(by= target.sx) && ( bx-br =target.sy)&&(by-br=ground.sy) {
                inMotion = false;
                clearInterval(tid);
                shotsLeft.pop(); //Remove a shot

                if(shotsLeft.length < 1){                         showYouLose();                         return;                     }                 }                 redrawCanvas();             }             function setVelocity(vel){                 velocity = parseInt(vel);                 $("#vo").val(velocity);             }             $(function(){                 init();                 //setup Input events                 $("#vo").change(function(){                     //Update the Velocity                     velocity = parseInt(this.value);                 });                 $("#ang").change(function(){                     //Update the angle                     myCannon.rotate(parseInt(this.value));                     redrawCanvas();                 });                 $("#ang").val(myCannon.angle); //Set UI to initial angle                 $("#fire").click(function(){                     if(shot > 2){
                    fire();
                }
            })

            //Track arrow keystrokes
            $(document).keydown(function(e){
                var keyCode = e.keyCode;

                if(inMotion === true){
                    return;
                }

                switch (keyCode){
                    case 37:
                        //console.log("Left");
                        //Lower velocity
                        setVelocity(velocity-1);
                        break;
                    case 38:
                        //console.log("Up");
                        //Raise angle
                        myCannon.rotate(myCannon.angle+1);
                        $("#ang").val(myCannon.angle+1);
                        redrawCanvas();
                        break;
                    case 39:
                        //console.log("right");
                        //increase velocity
                        setVelocity(velocity+1);
                        break;
                    case 40:
                        //console.log("down");
                        //Lower Angle
                        myCannon.rotate(myCannon.angle-1);
                        $("#ang").val(myCannon.angle-1);
                        redrawCanvas();
                        break;
                    case 32:
                        //console.log("Fire");
                        fire();
                        break;
                }
            });

        });</pre>