Javascript eTableSoccer Canvas Game

           
		    var BALLVELOCITY = 7;
			var VYREDUCTION = 40/BALLVELOCITY;
			var GOALSTOWIN = 2;

			var difficulty = 0.2; // 0:easier - 1:harder
			var fps = 50;

			var state = 0;
			var level = 1;
			var levelTime = 30;

			var stats = { wins: 0, loses:0, gf: 0, ga: 0 };

			$(document).ready(function(e){
				$("#play").click(function(){initGame(false);return false;});
			});


			$(document).mousemove(function(e){
				if(state === 1){
					var canvasTopPos = $("#canvas").position().top;
					p1.moveToY(e.pageY - canvasTopPos, field);
					p2.moveToY(e.pageY - canvasTopPos, field);
				}
			});

			var field = {
				
				width:700,
				height:450,
				
				goaly: 100,
				goalHeight: 220,
				
				draw: function(){
					//draw green field
					ctx.fillStyle = "#339933";
					ctx.fillRect(0,0,700,450);
					
					//draw goals
					ctx.strokeStyle = "#ffffff";
					ctx.lineWidth = 3;
					ctx.strokeRect(0,field.goaly,60,field.goalHeight);
					ctx.strokeRect(700-60,field.goaly,60,field.goalHeight);
					
					//draw middle line
					ctx.beginPath();
					ctx.moveTo(350,0);
					ctx.lineTo(350,450);
					ctx.stroke();
					
					//draw center circle
					ctx.beginPath();
					ctx.arc(350,225,50,0,Math.PI*2,true);
					ctx.stroke();
				}

			};

			function Ball(x,y){
				this.x = x;
				this.y = y;
				this.d = 10;
				this.vx = -Math.sqrt(BALLVELOCITY * BALLVELOCITY / 2);
				this.vy = Math.sqrt(BALLVELOCITY * BALLVELOCITY / 2);
				
				this.update = function(field){
					this.x = this.x + this.vx;
					this.y = this.y + this.vy;

					if(this.y >= field.goaly && this.y <= field.goaly + field.goalHeight)return;
					
					//check collisions against the field bounds
					if (this.x < BALLVELOCITY + 1 || this.x > field.width - (BALLVELOCITY + 1)) {
						this.vx = -this.vx;
						this.x = this.x + this.vx;
					};
					if (this.y < BALLVELOCITY + 1 || this.y > field.height - (BALLVELOCITY + 1)) {
						this.vy = -this.vy;
						this.y = this.y + this.vy;
					};
				};
				
				this.draw = function(){
					ctx.save();
					ctx.fillStyle = "#ffffff";
					ctx.beginPath();
					ctx.arc(this.x,this.y,this.d,0,Math.PI*2,true);
					ctx.fill();
					ctx.fillStyle = "#ff0000";
					ctx.beginPath();
					ctx.arc(this.x,this.y,2,0,Math.PI*2,true);
					ctx.fill();
					ctx.restore();
				};
			}


			function Player(x, y, color, visitor){
				this.x = x;
				this.color = color;
				this.y = y;
				this.width = 15;
				this.height = 90;
				this.visitor = visitor;
				this.moveToY = function(y){
					if(y > -this.height && y < field.height+this.height/2){
						this.y = y;
					}
				};
				this.move = function(dy){
					if(y > -this.height && y < field.height+this.height/2){
						this.y += dy;
					}
				};
				this.detectCollisions = function(ball) {
					if (this.x - this.width / 2 <= ball.x && this.x + this.width / 2 >= ball.x && this.y - this.height / 2 <= ball.y && this.y + this.height / 2 >= ball.y) {
						//collision detected
						if (ball.y < this.y) {
							//increment ball y velocity if the player hits the ball with the upper
							ball.vy = Math.min(0, Math.max(-BALLVELOCITY+1, (ball.y - this.y) / VYREDUCTION));
							ball.vx = Math.sqrt(BALLVELOCITY * BALLVELOCITY - ball.vy * ball.vy);
						}
						else {
							ball.vy = Math.max(0, Math.min(BALLVELOCITY-1, (ball.y - this.y) / VYREDUCTION));
							ball.vx = Math.sqrt(BALLVELOCITY * BALLVELOCITY - ball.vy * ball.vy);
						}

						if (this.visitor === true) { ball.vx *= -1; } //ball should go from right to left when hitted by a visitor
					}
				};
				this.draw = function(){
					ctx.save();
					ctx.fillStyle = this.color;
					ctx.fillRect(this.x-this.width/2,this.y-this.height/2,this.width,this.height);
					ctx.fillStyle = "#ff0000";
					ctx.beginPath();
					ctx.arc(this.x,this.y,2,0,Math.PI*2,true);
					ctx.fill();
					ctx.restore();
				};
			}


			var ctx = document.getElementById("canvas").getContext("2d");  

			var p1 = new Player(20, field.height/2, "#0033cc", false);
			var p2 = new Player(515, field.height/2, "#0033cc", false);
			var c1 = new Player(170, field.height/2, "#663399", true);
			var c2 = new Player(665, field.height/2, "#663399", true);
			var ball = new Ball(field.width/2, field.height/2);
			var timer = null;
			var levelTimeTimer = null;
			var goldenGoal = false;


			function initGame(startForVisitor){
				state = 1;
				$("#menu").hide();
				$("#canvascontainer").show();
				field.draw();
				p1.y = field.height/2;
				p1.draw();
				p2.y = field.height/2;
				p2.draw();
				c1.y = field.height/2;
				c1.draw();
				c2.y = field.height/2;
				c2.draw();
				ball.x = field.width/2;
				ball.y = field.height/2;
				ball.draw();
				setTimeout(function() { timer = setInterval(draw, 1000 / fps); }, 1000);
				levelTimeTimer = setInterval(updateLevelTime, 1000);
				ball.x = field.width/2;
				ball.y = field.height/2;
				if (startForVisitor) {
					ball.vx = -Math.sqrt(BALLVELOCITY * BALLVELOCITY / 2);
				}
				else{
					ball.vx = Math.sqrt(BALLVELOCITY * BALLVELOCITY / 2);
				}
				ball.vy = Math.floor(Math.random()*11) - 5;
			}

			function updateLevelTime() {
				if (goldenGoal === true) {
					$("#time").html("Golden Goal");
				}
				else {
					levelTime--;
					$("#time").html(levelTime);
					if (levelTime === 0) endGame();
				}
			}

			function endGame(){
				state = 2;
				clearInterval(timer);
				clearInterval(levelTimeTimer);
				levelTime = 30;
				
				$("#canvascontainer").hide();
				$("#menu").show();
				
				var lgoals = parseInt($("#lgoals").html());
				var vgoals = parseInt($("#vgoals").html());

				if (lgoals > vgoals) {
					goldenGoal = false;
					level++;
					fps = Math.min(100, fps + 2);
					difficulty = difficulty + 0.032;
					$("#message1").html("You Win");
					$("#message1").css("color", "#00cc00");
					$("#play").html("Play Next Level");
					$("#lgoals").html(0);
					$("#vgoals").html(0);
					stats.wins++;
					stats.gf += lgoals;
					stats.ga += vgoals;
				}
				else if (lgoals === vgoals) {
					goldenGoal = true;
					initGame(false);
					return;
				}
				else {
					goldenGoal = false;
					$("#message1").html("You Lose");
					$("#message1").css("color", "#ff0000");
					$("#play").html("Play Level Again");
					$("#lgoals").html(0);
					$("#vgoals").html(0);
					stats.loses++;
					//level = 1;
					//fps = 50;
					//difficulty = 0.2;
				}
				$("#message2").html(lgoals + " - " + vgoals);
				$("#stats").html("Wins:" + stats.wins + " Loses: " + stats.loses + " GF: " + stats.gf + " GA: " + stats.ga);
				$("#level").html(level);
				
			}

			function detectGoals(){
				//check if it is a local's goal
				if(ball.x > field.width - 10 && ball.y >= field.goaly && ball.y <= field.goaly + field.goalHeight){
					var goals = parseInt($("#lgoals").html()) + 1;
					$("#lgoals").html(goals);
					clearInterval(timer);
					clearInterval(levelTimeTimer);
					if (goldenGoal === true) { endGame(); }
					else { setTimeout(function() { initGame(true); }, 2500); }
				};
				
				//check if it is a visitor's goal
				if(ball.x < 10 && ball.y >= field.goaly && ball.y <= field.goaly + field.goalHeight){
					var goals = parseInt($("#vgoals").html()) + 1;
					$("#vgoals").html(goals);
					clearInterval(timer);
					clearInterval(levelTimeTimer);
					if (goldenGoal === true) { endGame(); }
					else { setTimeout(function() { initGame(false); }, 2500); }
				};
			}



			function moveComputerPlayers() {

				if (Math.random() < difficulty) {

					if ((ball.x < c1.x && ball.vx > 0) || (ball.x < c2.x && ball.vx < 0)) {
						//Calculate where the ball is going to intersect the player
						var yInter = ball.y + ((c1.x - ball.x) * ball.vy / ball.vx);
						if (yInter < 0 || yInter > field.height) { yInter = ball.y; }

						//Calculate where to shoot
						var goalPointY0 = field.goaly;
						var goalPointY1 = field.goaly + field.goalHeight;
						if (p1.y < field.height / 2) { goalPointY0 = Math.max(goalPointY0, p1.y + p1.height / 2); }
						else { goalPointY1 = Math.min(goalPointY1, p1.y - p1.height / 2); }
						var goalPointY = (goalPointY0 + goalPointY1) / 2;

						//Calculate the y axis velocity needed to make a goal
						var newVy = VYREDUCTION * ((yInter - goalPointY) * ball.vx / (c1.x - 0));
						newVy = Math.min(c1.height / 2, Math.max(-c1.height / 2, newVy));
						if (ball.vx < 0) newVy *= -1;

						//Move the player
						if (Math.abs(c1.y - (yInter + newVy)) < 10) { c1.y = c2.y = yInter + newVy; }
						else if (c1.y > yInter + newVy) { c1.y = c2.y -= 10; }
						else { c1.y = c2.y += 10; }

						if (c1.y < 0) { c1.y = c2.y = 0; }
						else if (c1.y > field.height) { c1.y = c2.y = field.height; }
					}
					else {
						//Calculate where the ball is going to intersect the player
						var yInter = ball.y + ((c2.x - ball.x) * ball.vy / ball.vx);
						if (yInter < 0 || yInter > field.height) { yInter = ball.y; }

						//Calculate where to shoot
						var goalPointY = 0;
						if (p2.y < field.height / 2) { goalPointY = field.height; }

						//Calculate the y axis velocity needed to make a goal
						var newVy = VYREDUCTION * ((yInter - goalPointY) * ball.vx / (c2.x - p2.x));
						newVy = Math.min(c1.height / 2, Math.max(-c1.height / 2, newVy));
						if (ball.vx < 0) newVy *= -1;

						//Move the player
						if (Math.abs(c1.y - (yInter + newVy)) < 10) { c1.y = c2.y = yInter + newVy; }
						else if (c1.y > yInter + newVy) { c1.y = c2.y -= 10; }
						else { c1.y = c2.y += 10; }

						if (c1.y < 0) { c1.y = c2.y = 0; }
						else if (c1.y > field.height) { c1.y = c2.y = field.height; }
					}

				}
			}


			function draw(){
				
				ctx.clearRect(0, 0, 700, 450);

				field.draw();
				
				p1.draw();
				p2.draw();
				moveComputerPlayers()
				c1.draw();
				c2.draw();
				ball.update(field);
				detectGoals();
				p1.detectCollisions(ball);
				p2.detectCollisions(ball);
				c1.detectCollisions(ball);
				c2.detectCollisions(ball);
				ball.draw();
				
			}