<repo_name>rohan-dhar/runnr<file_sep>/JS/vectr.js
/********************************************************************************

	Vectr.js: A general purpose JavaScript library for Vector operations.
	Developed by <NAME>

**********************************************************************************/

//Main global constructor/
window.Vectr = function(p1, p2){
	//If coordinates are provided as discreet parameters
	if(typeof p1 === "number" || typeof p1 === "string" || typeof p2 === "number" || typeof p2 === "string"){
		this.x = ( !isNaN(p1) ) ? Number(p1) : 0;
		this.y = ( !isNaN(p2) ) ? Number(p2) : 0;		

	//If coordinates or angle and magnitude are provided as an object
	}else if(typeof p1 === "object"){
		if(p1.x || p1.x === 0 || p1.y || p1.y === 0){
			this.x = ( !isNaN(p1.x) ) ? Number(p1.x) : 0;
			this.y = ( !isNaN(p1.y) ) ? Number(p1.y) : 0;
		}else if(p1.magnitude && (p1.angleDeg || p1.angle || p1.angle === 0 || p1.angleDeg === 0)){			

			//If the angle is provided in degrees
			//If both angle and angleDeg are provided, angleDeg is given prefernece
			if(p1.angleDeg || p1.angleDeg === 0){
				this.x = p1.magnitude * Math.cos(this.toRadian(p1.angleDeg));
				this.y = p1.magnitude * Math.sin(p1.angleDeg * Math.PI / 180);
			}else{
				this.x = p1.magnitude * Math.cos(p1.angle);				
				this.y = p1.magnitude * Math.sin(p1.angle);				
			}
		}

	//If nothing is provided
	}else{
		this.x = 0;		
		this.y = 0;		
	}
}







/********************************************************************************

	Helper Methods OR zero Vectr methods
	Used to provide general utility and do not perform and vector operations

**********************************************************************************/
Vectr.toDegree = function(rad) {
	(isNaN(rad)) ? rad = 1 : rad = Number(rad);
	return rad * 180 / Math.PI;
};

Vectr.toRadian = function(deg) {
	(isNaN(deg)) ? deg = 1 : deg = Number(deg);
	return deg * Math.PI / 180;
}







/********************************************************************************

	Vectr representation methods
	Used to get a Vectr is a particular format

**********************************************************************************/
Vectr.prototype.magnitude = function(){
	return Math.sqrt(this.x*this.x + this.y*this.y); //Math.pow avoided due to performance limitations
}

Vectr.prototype.angle = function(deg){
	if(deg){
		return Vectr.toDegree(Math.atan2(this.x , this.y));
	}else{
		return Math.atan2(this.x , this.y);
	}
}

Vectr.prototype.direction = function(deg){
	return this.angle(deg);
};

Vectr.prototype.verticalAngle = function(deg){
	return this.angle(deg) - (deg) ? 90 : Math.PI/2;
}

Vectr.prototype.getAs = function(type, angleAndMag, deg){

	if(type.toLowerCase() === "array"){
		if(angleAndMag){
			if(deg){
				return [this.angle(true), this.magnitude()]
			}else{
				return [this.angle(), this.magnitude()];
			}
		}else{
			return [this.x, this.y];
		}
	}else if(type.toLowerCase() === "object"){
		if(angleAndMag){
			if(deg){
				return {angle: this.angle(true), magnitude: this.magnitude()};
			}else{
				return {angle: this.angle(), magnitude: this.magnitude()};
			}
		}else{
			return {x: this.x, y: this.y}
		}
	}else{
		if(angleAndMag){
			if(deg){
				return "angle: "+this.angle(true)+", magnitude: "+this.magnitude();
			}else{
				return "angle: "+this.angle()+", magnitude: "+this.magnitude();
			}
		}else{
			return "x: "+this.x+", y: "+this.y;
		}
	}
}






/********************************************************************************

	Single Vectr operation methods
	Used to perform common single Vectr operations

**********************************************************************************/
Vectr.prototype.normalize = function(onNew){
	var magnitude =  this.magnitude();
	return this.divide(magnitude, onNew);
}


Vectr.prototype.invert = function(onNew){
	if(onNew){
		return new Vectr(-this.x, -this.y);
	}else{	
		this.x = -this.x;
		this.y = -this.y;
		return this;
	}
}
Vectr.prototype.invertX = function(onNew){
	if(onNew){
		return new Vectr(-this.x, this.y);
	}else{	
		this.x = -this.x;
		return this;
	}
}
Vectr.prototype.invertY = function(onNew){
	if(onNew){
		return new Vectr(this.x, -this.y);
	}else{	
		this.y = -this.y;
		return this;
	}
}

Vectr.prototype.abs = function(onNew){
	if(onNew){
		return new Vectr(Math.abs(this.x), Math.abs(this.y));
	}else{	
		this.x = Math.abs(this.x);
		this.y = Math.abs(this.y);
		return this;
	}
}
Vectr.prototype.absX = function(onNew){
	if(onNew){
		return new Vectr(Math.abs(this.x), this.y);
	}else{	
		this.x = Math.abs(this.x);
		return this;
	}
}
Vectr.prototype.absY = function(onNew){
	if(onNew){
		return new Vectr(this.x, Math.abs(this.y));
	}else{	
		this.y = Math.abs(this.y);
		return this;
	}
}

Vectr.prototype.roundOff = function(onNew){
	if(onNew){
		return new Vectr(Math.round(this.x), Math.round(this.y));
	}else{
		this.x = Math.round(this.x);
		this.y = Math.round(this.y);		
	}
}
Vectr.prototype.roundOffX = function(onNew){
	if(onNew){
		return new Vectr(Math.round(this.x),this.y);
	}else{
		this.x = Math.round(this.x);
	}

}
Vectr.prototype.roundOffY = function(onNew){
	if(onNew){
		return new Vectr(this.x, Math.round(this.y));
	}else{
		this.y = Math.round(this.y);		
	}
}

Vectr.prototype.swapXY = function(){
	var t = this.x;		
	this.x = this.y;
	this.y = t;
}

Vectr.prototype.rotateTo = function(angle, deg, onNew){
	if(isNaN(angle)){
		return false;
	}
	if(deg){
		angle = Vectr.toRadian(Number(angle));
	}

	var mag = this.magnitude();
	var x =  mag * Math.sin(angle), y = mag * Math.cos(angle);	

	if(onNew){
		return new Vectr(x, y);
	}else{
		this.x = x;
		this.y = y;		
		return this;
	}
}

Vectr.prototype.rotateBy = function(angle, deg, onNew){
	if(isNaN(angle)){
		return false;
	}
	if(deg){
		angle = Vectr.toRadian(Number(angle));
	}

	angle += this.angle();
	return this.rotateTo(angle, false, onNew);

}







/********************************************************************************

	Vectr arithmetic methods
	Used to perform common arethmetic operations on Vectrs

**********************************************************************************/
Vectr.prototype.operation = function(conf){

	//Unpacking the supplied object
	var x = conf.x, y = conf.y, n = conf.operant, onNew = conf.onNew, opt = conf.operation; 

	if(opt === "+"){	
		if(n instanceof Vectr){
			if(onNew){
				if(x && y){
					return new Vectr(this.x + n.x, this.y + n.y);
				}else if(x){
					return new Vectr(this.x + n.x, this.y);
				}else if(y){
					return new Vectr(this.x, this.y + n.y);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x += n.x;
				}
				if(y){
					this.y += n.y;	
				}
				return this;
			}
		}else if(!isNaN(n)){
			n = Number(n);

			if(onNew){
				if(x && y){
					return new Vectr(this.x + n, this.y + n);
				}else if(x){
					return new Vectr(this.x + n, this.y);
				}else if(y){
					return new Vectr(this.x, this.y + n);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x += n;
				}
				if(y){
					this.y += n;	
				}
				return this;
			}		
		}else{
			return false;
		}	
	}else if(opt === "*"){
		if(n instanceof Vectr){
			if(onNew){
				if(x && y){
					return new Vectr(this.x * n.x, this.y * n.y);
				}else if(x){
					return new Vectr(this.x * n.x, this.y);
				}else if(y){
					return new Vectr(this.x, this.y * n.y);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x *= n.x;
				}
				if(y){
					this.y *= n.y;	
				}
				return this;
			}
		}else if(!isNaN(n)){
			n = Number(n);

			if(onNew){
				if(x && y){
					return new Vectr(this.x * n, this.y * n);
				}else if(x){
					return new Vectr(this.x * n, this.y);
				}else if(y){
					return new Vectr(this.x, this.y * n);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x *= n;
				}
				if(y){
					this.y *= n;	
				}
				return this;
			}		
		}else{
			return false;
		}	
	}else if(opt === "-"){
		if(n instanceof Vectr){
			if(onNew){
				if(x && y){
					return new Vectr(this.x - n.x, this.y - n.y);
				}else if(x){
					return new Vectr(this.x - n.x, this.y);
				}else if(y){
					return new Vectr(this.x, this.y - n.y);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x -= n.x;
				}
				if(y){
					this.y -= n.y;	
				}
				return this;
			}
		}else if(!isNaN(n)){
			n = Number(n);

			if(onNew){
				if(x && y){
					return new Vectr(this.x - n, this.y - n);
				}else if(x){
					return new Vectr(this.x - n, this.y);
				}else if(y){
					return new Vectr(this.x, this.y - n);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x -= n;
				}
				if(y){
					this.y -= n;	
				}
				return this;
			}		
		}else{
			return false;
		}	
	}else if(opt === "/"){
		if(n instanceof Vectr){
			if(onNew){
				if(x && y){
					return new Vectr(this.x / n.x, this.y / n.y);
				}else if(x){
					return new Vectr(this.x / n.x, this.y);
				}else if(y){
					return new Vectr(this.x, this.y / n.y);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x /= n.x;
				}
				if(y){
					this.y /= n.y;	
				}
				return this;
			}
		}else if(!isNaN(n)){
			n = Number(n);

			if(onNew){
				if(x && y){
					return new Vectr(this.x / n, this.y / n);
				}else if(x){
					return new Vectr(this.x / n, this.y);
				}else if(y){
					return new Vectr(this.x, this.y / n);					
				}else{
					return false;
				}
			}else{
				if(x){
					this.x /= n;
				}
				if(y){
					this.y /= n;	
				}
				return this;
			}		
		}else{
			return false;
		}	
	}else{
		return false;
	}
}

//Wrapper to operation: ADDITION
Vectr.prototype.add = function(n, onNew){
	return this.operation({
		operation: "+",
		operant: n,
		x: true,
		y: true,
		onNew: onNew
	});
}
Vectr.prototype.addX = function(n, onNew){
	return this.operation({
		operation: "+",
		operant: n,
		x: true,
		y: false,
		onNew: onNew
	});
}
Vectr.prototype.addY = function(n, onNew){
	return this.operation({
		operation: "+",
		operant: n,
		x: false,
		y: true,
		onNew: onNew
	});
}

//Wrapper to operation: MULTIPLICATION
Vectr.prototype.multiply = function(n, onNew){
	return this.operation({
		operation: "*",
		operant: n,
		x: true,
		y: true,
		onNew: onNew
	});
}
Vectr.prototype.multiplyX = function(n, onNew){
	return this.operation({
		operation: "*",
		operant: n,
		x: true,
		y: false,
		onNew: onNew
	});
}
Vectr.prototype.multiplyY = function(n, onNew){
	return this.operation({
		operation: "*",
		operant: n,
		x: false,
		y: true,
		onNew: onNew
	});
}

//Wrapper to operation: SUBTRACTION
Vectr.prototype.subtract = function(n, onNew){
	return this.operation({
		operation: "-",
		operant: n,
		x: true,
		y: true,
		onNew: onNew
	});
}
Vectr.prototype.subtractX = function(n, onNew){
	return this.operation({
		operation: "-",
		operant: n,
		x: true,
		y: false,
		onNew: onNew
	});
}
Vectr.prototype.subtractY = function(n, onNew){
	return this.operation({
		operation: "-",
		operant: n,
		x: false,
		y: true,
		onNew: onNew
	});
}

//Wrapper to operation: DIVISION
Vectr.prototype.divide = function(n, onNew){
	return this.operation({
		operation: "/",
		operant: n,
		x: true,
		y: true,
		onNew: onNew
	});
}
Vectr.prototype.divideX = function(n, onNew){
	return this.operation({
		operation: "/",
		operant: n,
		x: true,
		y: false,
		onNew: onNew
	});
}
Vectr.prototype.divideY = function(n, onNew){
	return this.operation({
		operation: "/",
		operant: n,
		x: false,
		y: true,
		onNew: onNew
	});
}

Vectr.prototype.dotProduct = function(vec){
	if(!vec instanceof Vectr){
		return false;
	}
	return this.multiply(vec, true).magnitude();	
}

Vectr.prototype.crossProduct = function(vec, onNew){
	if(!vec instanceof Vectr){
		return false;
	}
	return this.magnitude() * vec.magnitude() * Math.sin(this.angleBetween(vec));
}







/********************************************************************************

	General Vectr methods
	Used to perform other common operations on Vectrs

**********************************************************************************/




Vectr.prototype.distanceX = function(vec, abs){
	if(!vec instanceof Vectr){
		return false;
	}
	if(abs){
		return Math.abs(this.x - vec.x);
	}else{
		return this.x - vec.x;
	}
}

Vectr.prototype.distanceY = function(vec, abs){
	if(!vec instanceof Vectr){
		return false;
	}
	if(abs){
		return Math.abs(this.y - vec.y);
	}else{
		return this.y - vec.y;
	}
}

Vectr.prototype.distance = function(vec){
	if(!vec instanceof Vectr){
		return false;
	}
	return this.subtract(vec, true).magnitude();
}

Vectr.prototype.angleBetween = function(vec, deg){
	if(!vec instanceof Vectr){
		return false;
	}
	var theta = Math.acos(this.dotProduct(vec)/(this.magnitude() * vec.magnitude()));
	if(deg){
		return Vectr.toDegree(theta);
	}else{
		return theta;
	}
}

Vectr.prototype.project = function(vec){
	if(!vec instanceof Vectr){
		return false;
	}
	var scaleFactor = this.magnitude() * Math.cos(this.angleBetween(vec));
	return vec.normalize(true).multiply(scaleFactor);
}
<file_sep>/JS/script.js
function rand(min,max){
	return Math.floor(Math.random()*(max-min+1)+min);
}

var can, ctx, $can;

var conf = {
	groundHeight: 4,
	waterHeight: 4,
	gravity: 1.5,
	tileSide: 60,
	worldColor: "#D0F4F7",
	cloudDensity: 22, // No of Clouds in 500 px
	cloudTopRange: [0, 90],
	cloudWidth: 128,
	cloudHeight: 71,
	enemySide: 50,
	maxGameSpeed: 17,
	minPlayerLeftIncrement: 3,
	minPlayerRightIncrement: 1,
	tileType: "ground",
}

var tileImages = {
	underGround: "underGroundTile.png",
	ground: "groundTile.png",	
	underWater: "underWaterTile.png",	
	water: "waterTile.png",	
};
var playerImages = {
	1: "p1.png",
	2: "p2.png",
	3: "p3.png",
	4: "p4.png",
	5: "p5.png",
	6: "p6.png",
	7: "p7.png",
	8: "p8.png",
	9: "p9.png",
	10: "p1.png",
	11: "p1.png",
};
var cloudImages = {
	1: "cloud1.png",	
	2: "cloud2.png",	
	3: "cloud3.png",		
};
var enemyImages = {
	1: "enemy1.png",	
	2: "enemy2.png",	
	3: "enemy3.png",		
};

var totalLoadCount = Object.keys(tileImages).length + Object.keys(playerImages).length + Object.keys(enemyImages).length + Object.keys(cloudImages).length, totalLoaded = 0;



function Tile(type, x, side){
	this.type = type || "ground";
	this.side = side || conf.tileSide;
	this.x = x;	
}

Tile.prototype.draw = function() {
	var tile, underTile, height;
	
	if(this.type == "water"){
		tile = tileImages.water;
		underTile = tileImages.underWater;
		height = conf.waterHeight;
	}else{
		tile = tileImages.ground;
		underTile = tileImages.underGround;
		height = conf.groundHeight;
	}

	for(var i = 0; i < height; i++){			
		ctx.drawImage(underTile, this.x, can.height - (i*this.side), this.side, this.side);
	}	

	ctx.drawImage(tile, this.x, can.height - ((height)*this.side), this.side, this.side);
}

Tile.prototype.move = function(){
	if(this.x < -this.side){
		var maxX = 0;
		var l = tiles.length;
		while(l--){
			if(tiles[l].x > maxX){
				maxX = tiles[l].x;
			}
		}
		this.x = maxX + this.side - player.gameSpeed;
	}else{
		this.x -= player.gameSpeed;
	}
}


function Cloud(type, x, y, speed, width, height){

	this.type = type;
	this.x = x;
	this.y = y;
	this.width = width || conf.cloudWidth;
	this.height = height || conf.cloudHeight;
	this.speed = speed;
}

Cloud.prototype.draw = function(){
	ctx.drawImage(this.type, this.x, this.y, this.width, this.height);
}

Cloud.prototype.move = function(){
	if(this.x < -this.width){
		var maxX = 0;
		var l = clouds.length;
		while(l--){
			if(clouds[l].x > maxX){
				maxX = clouds[l].x;
			}
		}
		this.x = maxX + this.width - this.speed;
	}else{
		this.x -= this.speed;
	}

}
var clouds = [];


function Enemy(type, orientation, length, x, y, side){
	this.type = type;
	this.orientation = orientation;
	this.length = length;
	this.x = x;
	this.y = y;
	this.side = side || conf.enemySide;
}

Enemy.prototype.draw = function(){
	if(this.orientation == "horizontal"){
		for(var i = 0; i < this.length; i++){
			ctx.drawImage(this.type, this.x + (this.side * i), this.y, this.side, this.side);			
		}	
	}else{
		for(var i = 0; i < this.length; i++){
			ctx.drawImage(this.type, this.x, this.y - (this.side * i), this.side, this.side);			
		}	
	}
}

Enemy.prototype.move = function(){	
	var i = enemies.indexOf(this);
	if(this.orientation == "horizontal"){
		if(this.x < -this.side * this.length){
			enemies.splice(i, 1);
		}else{
			this.x -= player.gameSpeed;
		}
	}else{
		if(this.x < -this.side){
			enemies.splice(i, 1);
		}else{
			this.x -= player.gameSpeed;
		}		
	}
}

var enemies = [];

var initPlayerSettings = {
	gameSpeed: 6,
	movementSpeed: 5,
	leftIncrement: 8,
	rightIncrement: 8,			
	bounceSpeed: 26,	
}

var player = {
	gameSpeed: 0,
	movementSpeed: 0,
	leftIncrement: 0,
	rightIncrement: 0,			
	bounceSpeed: 0,
	minX: 0,
	maxX: 0,
	x: 0,
	y: 0,
	groundLevel: 0,
	currentSprite: 1,
	time: 0,
	width: 72,
	height: 97,
	inMotion: false,
	movingTo: 0,
	inBounce: false,
	ySpeed: 0,
	setup: function(){
		this.gameSpeed = initPlayerSettings.gameSpeed;
		this.movementSpeed = initPlayerSettings.movementSpeed;
		this.leftIncrement = initPlayerSettings.leftIncrement;
		this.rightIncrement = initPlayerSettings.rightIncrement;			
		this.bounceSpeed = initPlayerSettings.bounceSpeed;

		this.minX = can.width * 3/10 - (this.width / 2);
		this.maxX = can.width * 7/10 - (this.width / 2);
		this.x = can.width / 2 - (this.width / 2);
		this.y = can.height - ((conf.groundHeight+1) * conf.tileSide) - 30;
		this.groundLevel = can.height - ((conf.groundHeight+1) * conf.tileSide) - 30;
	},
	draw: function(){
		this.time++;
		if(player.time >= 35/player.gameSpeed){
			player.currentSprite++;

			if(player.currentSprite == 11){
				player.currentSprite = 1;
			}
			player.time = 0;
		}

		if(player.inMotion){
			if(player.x < player.movingTo && player.x + player.movementSpeed <= player.movingTo){
				player.x += player.movementSpeed;
			}else if(player.x > player.movingTo && player.x - player.movementSpeed >= player.movingTo){
				player.x -= player.movementSpeed;
			}else{
				player.inMotion = false;
			}
		}

		if(player.inBounce){
			if(player.y - player.ySpeed < player.groundLevel){
				player.ySpeed -= conf.gravity;
				player.y -= player.ySpeed;
			}else if(player.y < player.groundLevel){
				player.y = player.groundLevel;
				player.inBounce = false;
			}else{
				player.y = player.groundLevel;
				player.inBounce = false;
			}
		}

		ctx.drawImage(playerImages[player.currentSprite], player.x, player.y, this.width, this.height);	

	}, 
	move: function(where){
		if(where === "left"){
			if(player.x - player.leftIncrement > player.minX){
				player.x -= player.leftIncrement;
			}
		}else if(where === "right"){
			if(player.x + player.rightIncrement < player.maxX){
				player.x += player.rightIncrement;
			}
		}else if(where == "up" && !player.inBounce){
			player.ySpeed = player.bounceSpeed;
			player.y--;
			player.inBounce = true;
		}else if(where == "down" && player.inBounce){
			if(Math.sign(player.speed) === -1){
				player.ySpeed *= 20;
			}else if(Math.sign(player.speed) === 1){
				player.ySpeed *= -20
			}else{
				player.ySpeed = -20;
			}
		}
	}, 
	checkCollision: function(){
		var l = enemies.length;
		var hasCollided = false;
		while(l--){
			var e = enemies[l];
			if(e.orientation == "horizontal"){
				if(player.x + player.width - 8 >= e.x && player.x <= e.x + (e.side * e.length) && player.y >= e.y - e.side){
					hasCollided = true;
					break;
				}
			}else{
				if(player.x + player.width - 8 >= e.x && player.x <= e.x + e.side  && player.y >= e.y - (e.side * e.length) ){
					hasCollided = true;
					break;
				}
			}
		}
		return hasCollided;
	}

}


var tiles = [];
var lastEnemy = 0;

var game = {	
	status: false,
	score: 0,
	timeStarted: 0,
	animationId: 0,
	setWorldSize: function(){
		can.height = window.innerHeight;
		can.width = window.innerWidth;						
	},
	loadImagesFromObject: function(obj){
		var loaders = {};
		var url = "";
		for(img in obj){			
			loaders[img] = new Image();
			$(loaders[img]).load(function(){
				var that = this;
				for(item in obj){
					if(obj[item] == that.src.substr(that.src.lastIndexOf("/") + 1)){
						obj[item] = that;
						totalLoaded++;
						$("#load-bar-prog").width((totalLoaded/totalLoadCount*100)+"%")
						if(totalLoaded == totalLoadCount){

							game.init();

							$("#load-bar-base").animate({
								"opacity": "0"
							}, 400);
							setTimeout(function(){
								$("#load-bar-base").css("display","none")
								$("#load-head").text("Runnr");
								$("#start-btn").css("display","block").animate({
									"opacity": "1"
								}, 400);
							}, 400);
						}
						break;
					}
				}
			});
			loaders[img].src = "IMG/"+obj[img];
		}
	},
	loadAssets: function(){
		this.loadImagesFromObject(tileImages);
		this.loadImagesFromObject(playerImages);
		this.loadImagesFromObject(cloudImages);
		this.loadImagesFromObject(enemyImages);
	},
	init: function(){

		player.setup();

		tiles = [];
		clouds = [];
		enemies = [];

		game.score = 0;

		var nos = (can.width / conf.tileSide) + 2;		
		for(var i = 0; i < nos; i++){	
			tiles.push(new Tile(conf.tileType, i*conf.tileSide, conf.tileSide));
		}

		nos = conf.cloudDensity * can.width/500;

		for(var i = 0; i < nos; i++){
			var ch = rand(1, 3);
			var denom = rand(2, 5);
			clouds.push(new Cloud(cloudImages[ch], rand(0, can.width), rand(conf.cloudTopRange[0], conf.cloudTopRange[1]), player.gameSpeed / denom));
		}

		clouds.push(new Cloud(cloudImages[1], can.width + conf.cloudWidth, conf.cloudTopRange[0]));


	},
	animate: function(){
		ctx.fillStyle = conf.worldColor;
		ctx.fillRect(0, 0, can.width, can.height);
		var l = tiles.length;
		var scoreMultiplier = 1;

		while(l--){
			tiles[l].draw();
			tiles[l].move();
		}

		var l = clouds.length;
		while(l--){
			clouds[l].draw();			
			clouds[l].move();						
		}

		var l = enemies.length;
		while(l--){
			enemies[l].draw();			
			enemies[l].move();						
		}

		player.draw();
		
		var timePassed = Date.now() - game.timeStarted;

		if(player.checkCollision()){
			game.over();
		}		
		
		var randomizer;			

		if(timePassed > 12000){
			randomizer = rand(-155, -100);
			scoreMultiplier = 1.2;
		}else if(timePassed > 30000){
			randomizer = rand(-210, -140);	
			scoreMultiplier = 1.6;
		}else if(timePassed > 60000){
			randomizer = rand(-280, -190);
			scoreMultiplier = 1.9;
		}else{
			randomizer = rand(-100, 0);				
		}		

		if(lastEnemy >= (710 + randomizer)/player.gameSpeed){
			var ch = rand(1, 3);
			var change = rand(-10, 10);
			side = conf.enemySide + change;
			var y = can.height - ((conf.groundHeight) * conf.tileSide) - side;			

			var ori = rand(1, 2);
			var len = rand(1, 3);
			
			if(ori == 1){
				ori = "horizontal";
			}else{
				ori = "vertical";				
			}

			enemies.push(new Enemy(enemyImages[ch], ori, len, can.width + side * len, y, side));
			lastEnemy = 0;
		}else{
			lastEnemy++;
		}			

		if(timePassed > 15000 && player.gameSpeed < conf.maxGameSpeed){
			player.gameSpeed += 0.005;
			if(player.rightIncrement >= conf.minPlayerRightIncrement){
				player.rightIncrement -= 0.0035;
			}else{
				player.rightIncrement = conf.minPlayerRightIncrement;
			}
			if(player.rightIncrement >= conf.minPlayerRightIncrement){
				player.rightIncrement -= 0.0035;
			}else{
				player.rightIncrement = conf.minPlayerRightIncrement;
			}				
				
		}


		if(game.status){
			game.score = timePassed/1000;			
			game.score *= scoreMultiplier;
			game.score = Math.round(game.score * 10) / 10;

			$(".game-sidebar-stat-score .game-sidebar-stat-data").text((game.score));
			requestAnimationFrame(game.animate);
		}				
		

	},
	start: function(){
		$("#load-screen, #screen-score").animate({
			"opacity": "0"
		}, 400);
		$(".game-sidebar").css("display", "block").animate({
			"opacity": "1"
		}, 400);
		game.status = true;
		setTimeout(function(){			
			$("#load-screen").css({
				"display": "none",
				"background-color": "rgba(79,166,255, 0.8)",
			});
			$("#screen-score").css("display", "none");
			game.timeStarted = Date.now();
			game.animationId = requestAnimationFrame(game.animate);
		}, 400);

	},
	setup: function(){
		$can = $("<canvas id='game-world'></canvas>");
		$("body").append($can);
		can = $can[0];
		ctx = can.getContext("2d");
		this.setWorldSize();		
		this.loadAssets();				
	},
	over: function(){
		game.status = false;
		$("#game-score-stat").text(game.score);
		$("#screen-score").css("display", "block").animate({
			"opacity": "1"
		}, 400);

		$("#load-head").text("Game Over!");
		$("#start-btn").text("Play again");

		$(".game-sidebar").animate({
			"opacity": "0"
		}, 400);
		setTimeout(function(){			
			$(".game-sidebar").css({
				"display": "none",				
			});
		}, 400);

		$("#load-screen").css("display","block").animate({
			"opacity": "1"
		}, 400);

		game.init();
	}
}

$(document).ready(function(){

	game.setup();

	$("#start-btn").click(function(){
		if(!game.status){
			game.start();
		}
	});

	$(".game-sidebar-act-end").click(function(){
		if(game.status){
			game.start();
		}
	});
	
	var leftIntr = false, rightIntr = false;

	$(document).on("keyup", function(e){
		if(e.keyCode == 37){
			if(leftIntr !== false){
				clearInterval(leftIntr);
				leftIntr = false;
			}
		}
		if(e.keyCode == 39){
			if(rightIntr !== false){
				clearInterval(rightIntr);
				rightIntr = false;
			}
		}
	});

	$(document).on("keydown", function(e){
		if(e.keyCode == 37){
			if(leftIntr === false){
				leftIntr = setInterval(function(){
					player.move("left");					
				}, 17);
			}
		}
		if(e.keyCode == 39){
			if(rightIntr === false){
				rightIntr = setInterval(function(){
					player.move("right");					
				}, 17);
			}
		}

		if(e.keyCode == 38){
			player.move("up");			
		}
		if(e.keyCode == 40){
			player.move("down");			
		}

	});

});<file_sep>/readme.md
<h1>Runnr</h1>
An endless runner game developed using HTML 5 <code>canvas</code> API.

<h3>Installation</h3>
Just clone the git repo and run the <code>index.html</code> in any HTML 5 supporting web browser to check the project out!
