402 lines
10 KiB
JavaScript
402 lines
10 KiB
JavaScript
|
var NFS_HEIGHT = 500;
|
||
|
var CAR_BOTTOM = 10;
|
||
|
var CAR_HEIGHT = 80 + CAR_BOTTOM;
|
||
|
var CAR_WIDTH = 40;
|
||
|
var OBSTACLE_WIDTH = 100;
|
||
|
var OBSTACLE_HEIGHT = 33.328;
|
||
|
var OBSTACLE_APPEARANCE_GAP = 1000; //1 second
|
||
|
var OBSTACLE_APPEARANCE_DX = 100;
|
||
|
var PX_DX = 3;
|
||
|
var PX_DX_DX = 0.05;
|
||
|
var GAME_TIME = 1;
|
||
|
var GAME_TIME_DX = 11;
|
||
|
var INITIAL_BULLETS_BOTTOM = CAR_HEIGHT;
|
||
|
|
||
|
function Util() {}
|
||
|
|
||
|
Util.getRandomInt = function(min, max) {
|
||
|
|
||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||
|
};
|
||
|
|
||
|
function Obstacle(lanes, laneNo) {
|
||
|
|
||
|
var _this = this;
|
||
|
this._init = function() {
|
||
|
|
||
|
this.element = document.createElement('img');
|
||
|
this.laneNo = laneNo;
|
||
|
this.lanes = lanes;
|
||
|
this.element.className = 'obstacle';
|
||
|
this.element.setAttribute('src', 'images/obstacle.png');
|
||
|
this.lanes[laneNo].appendChild(this.element);
|
||
|
this.dynamicMarginTop = 1;
|
||
|
};
|
||
|
|
||
|
this._init();
|
||
|
}
|
||
|
|
||
|
function ObstacleManager(lanes, car) {
|
||
|
|
||
|
var _this = this;
|
||
|
this._init = function() {
|
||
|
|
||
|
this.lanes = lanes;
|
||
|
this.car = car;
|
||
|
this.obstacles = [];
|
||
|
};
|
||
|
|
||
|
this.generateObstacles = function() {
|
||
|
|
||
|
_this.obstacleGeneratorId = setInterval(_this._generateObstacle, OBSTACLE_APPEARANCE_GAP);
|
||
|
};
|
||
|
|
||
|
this._generateObstacle = function() {
|
||
|
|
||
|
if (_this.obstacles.length < 3) {
|
||
|
|
||
|
var laneNo;
|
||
|
laneNo = Util.getRandomInt(0, _this.lanes.length - 1);
|
||
|
var obstacle = new Obstacle(_this.lanes, laneNo);
|
||
|
_this.obstacles.push(obstacle);
|
||
|
|
||
|
return obstacle;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.refreshObstacles = function() {
|
||
|
|
||
|
var updatedObstacles = [];
|
||
|
for (var i = 0; i < _this.obstacles.length; i++) {
|
||
|
|
||
|
_this.obstacles[i].element.style.top = _this.obstacles[i].dynamicMarginTop + 'px';
|
||
|
if (!(parseInt(_this.obstacles[i].element.style.top) > NFS_HEIGHT - CAR_BOTTOM)) {
|
||
|
|
||
|
_this.obstacles[i].dynamicMarginTop += PX_DX;
|
||
|
updatedObstacles.push(_this.obstacles[i]);
|
||
|
} else {
|
||
|
|
||
|
_this.obstacles[i].element.parentElement.removeChild(_this.obstacles[i].element);
|
||
|
for (var j = 0; j < _this.obstacles.length; j++) {
|
||
|
|
||
|
if (_this.obstacles[j].element.parentElement === _this.obstacles[i].element.parentElement) {
|
||
|
|
||
|
_this.obstacles[j].element.style.top = _this.obstacles[j].dynamicMarginTop + OBSTACLE_HEIGHT + 'px';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
_this.obstacles = updatedObstacles;
|
||
|
};
|
||
|
|
||
|
this.removeObstacle = function(obstacle){
|
||
|
|
||
|
var index = this.obstacles.indexOf(obstacle);
|
||
|
|
||
|
if(index !== -1){
|
||
|
console.log(this.obstacles[index].parentElement);
|
||
|
this.obstacles[index].element.parentElement.removeChild(this.obstacles[index].element);
|
||
|
this.obstacles.splice(index, 1);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.getOldestObstacleInLane = function(bulletLane){
|
||
|
|
||
|
var obstacle;
|
||
|
for(var i = 0; i < _this.obstacles.length; i++){
|
||
|
|
||
|
if(_this.obstacles[i].laneNo == bulletLane){
|
||
|
|
||
|
if(obstacle === undefined || _this.obstacles[i].dynamicMarginTop > obstacle.dynamicMarginTop){
|
||
|
|
||
|
obstacle = _this.obstacles[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return obstacle;
|
||
|
};
|
||
|
|
||
|
this.stop = function() {
|
||
|
|
||
|
if (this.obstacleGeneratorId) {
|
||
|
clearInterval(this.obstacleGeneratorId);
|
||
|
this.obstacleGeneratorId = false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this._init();
|
||
|
}
|
||
|
|
||
|
function CollisionHandler(car, obstacleManager) {
|
||
|
|
||
|
var _this = this;
|
||
|
this._init = function() {
|
||
|
|
||
|
this.car = car;
|
||
|
this.obstacleManager = obstacleManager;
|
||
|
};
|
||
|
|
||
|
this.checkCollisions = function() {
|
||
|
|
||
|
for (var i = 0; i < _this.obstacleManager.obstacles.length; i++)
|
||
|
return _this._checkCollision(_this.obstacleManager.obstacles[i]);
|
||
|
};
|
||
|
|
||
|
this._checkCollision = function(obstacleO) {
|
||
|
|
||
|
if ((obstacleO.dynamicMarginTop + OBSTACLE_HEIGHT > NFS_HEIGHT - CAR_HEIGHT) && (obstacleO.laneNo == _this.car.currentLane)) {
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.checkShot = function(){
|
||
|
|
||
|
var bulletLane;
|
||
|
|
||
|
for(var i = 0; i < _this.obstacleManager.lanes.length; i++){
|
||
|
|
||
|
if(_this.obstacleManager.lanes[i].getElementsByClassName('bullets').length > 0) {
|
||
|
bulletLane = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var oldestObstacleInCurrentLane = obstacleManager.getOldestObstacleInLane(bulletLane);
|
||
|
if(oldestObstacleInCurrentLane !== undefined && _this.car.gun.bullets !== undefined) {
|
||
|
if (_this.car.gun.dynamicBulletBottom + oldestObstacleInCurrentLane.dynamicMarginTop + CAR_HEIGHT + OBSTACLE_HEIGHT > NFS_HEIGHT) {
|
||
|
|
||
|
_this.car.gun.stop();
|
||
|
_this.car.enableGun();
|
||
|
_this.obstacleManager.removeObstacle(oldestObstacleInCurrentLane);
|
||
|
}
|
||
|
}
|
||
|
if(_this.car.gun.dynamicBulletBottom + CAR_HEIGHT > NFS_HEIGHT){
|
||
|
|
||
|
_this.car.gun.stop();
|
||
|
_this.car.enableGun();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this._init();
|
||
|
}
|
||
|
|
||
|
function Car(currentLane, lanes) {
|
||
|
|
||
|
var _this = this;
|
||
|
this._init = function() {
|
||
|
|
||
|
this.currentLane = currentLane;
|
||
|
this.lanes = lanes;
|
||
|
this.element = document.createElement('img');
|
||
|
this.element.className = 'car';
|
||
|
this.element.setAttribute('src', 'images/car.png');
|
||
|
this.lanes[this.currentLane].appendChild(this.element);
|
||
|
this.gun = new Gun(this.lanes);
|
||
|
};
|
||
|
|
||
|
this._changeLane = function(laneNumber) {
|
||
|
|
||
|
|
||
|
if (_this.currentLane != laneNumber) {
|
||
|
|
||
|
_this.lanes[laneNumber].appendChild(_this.element);
|
||
|
}
|
||
|
if (_this.currentLane > laneNumber) {
|
||
|
|
||
|
_this.currentLane--;
|
||
|
} else if (_this.currentLane < laneNumber) {
|
||
|
|
||
|
_this.currentLane++;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this._keyNavigation = function(e) {
|
||
|
|
||
|
switch (e.which) {
|
||
|
case 37: // left
|
||
|
_this._changeLane((_this.currentLane - 1) < 0 ? 0 : (_this.currentLane - 1));
|
||
|
break;
|
||
|
|
||
|
case 39: // right
|
||
|
_this._changeLane((_this.currentLane + 1) > _this.lanes.length - 1 ? _this.lanes.length - 1 : (_this.currentLane + 1));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return; // exit this handler for other keys
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
this._fireGunEvent = function(e){
|
||
|
|
||
|
switch (e.which){
|
||
|
|
||
|
case 32:
|
||
|
_this._disableGun();
|
||
|
_this.gun.fireBullets(_this.currentLane);
|
||
|
break;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.enableGun = function(){
|
||
|
|
||
|
document.addEventListener('keyup', this._fireGunEvent, false);
|
||
|
};
|
||
|
|
||
|
this._disableGun = function(){
|
||
|
|
||
|
document.removeEventListener('keyup', this._fireGunEvent, false);
|
||
|
};
|
||
|
|
||
|
this._initEvents = function() {
|
||
|
|
||
|
document.addEventListener('keydown', this._keyNavigation, false);
|
||
|
this.enableGun();
|
||
|
};
|
||
|
|
||
|
this._removeEvents = function() {
|
||
|
|
||
|
document.removeEventListener('keydown', this._keyNavigation, false);
|
||
|
this._disableGun();
|
||
|
};
|
||
|
|
||
|
this.stop = function() {
|
||
|
|
||
|
_this._removeEvents();
|
||
|
};
|
||
|
|
||
|
this._init();
|
||
|
}
|
||
|
|
||
|
function Gun(lanes){
|
||
|
|
||
|
var _this = this;
|
||
|
this._init = function(){
|
||
|
|
||
|
this.lanes = lanes;
|
||
|
};
|
||
|
|
||
|
this.fireBullets = function(currentLane){
|
||
|
|
||
|
var bullets = document.createElement('img');
|
||
|
bullets.setAttribute('src', 'images/bullets.png');
|
||
|
bullets.className = 'bullets';
|
||
|
_this.lanes[currentLane].appendChild(bullets);
|
||
|
_this.bullets = bullets;
|
||
|
_this.dynamicBulletBottom = INITIAL_BULLETS_BOTTOM;
|
||
|
|
||
|
_this.bulletId = requestAnimationFrame(_this.animateFireBullets);
|
||
|
};
|
||
|
|
||
|
this.animateFireBullets = function () {
|
||
|
|
||
|
_this.dynamicBulletBottom += PX_DX;
|
||
|
_this.bullets.style.bottom = _this.dynamicBulletBottom + 'px';
|
||
|
|
||
|
_this.bulletId = requestAnimationFrame(_this.animateFireBullets);
|
||
|
};
|
||
|
|
||
|
_this.stop = function () {
|
||
|
|
||
|
if(_this.bulletId){
|
||
|
|
||
|
cancelAnimationFrame(_this.bulletId);
|
||
|
_this.bulletId = false;
|
||
|
_this.bullets.parentElement.removeChild(_this.bullets);
|
||
|
_this.bullets = undefined;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this._init();
|
||
|
}
|
||
|
|
||
|
function NFS() {
|
||
|
|
||
|
var _this = this;
|
||
|
|
||
|
this._init = function() {
|
||
|
|
||
|
this.lanes = document.getElementsByClassName('lane');
|
||
|
this.container = document.getElementById('container');
|
||
|
this.obstacles = [];
|
||
|
this.car = new Car(Util.getRandomInt(0, this.lanes.length - 1), this.lanes);
|
||
|
this.obstacleManager = new ObstacleManager(this.lanes, this.car);
|
||
|
this.collisionHander = new CollisionHandler(this.car, this.obstacleManager);
|
||
|
|
||
|
this.dynamicBackgroundPositionY = 1;
|
||
|
|
||
|
document.getElementById('toggle').addEventListener('click', function() {
|
||
|
|
||
|
if (this.innerHTML == 'Start') {
|
||
|
_this.obstacleManager.generateObstacles();
|
||
|
_this.play();
|
||
|
_this.car._initEvents();
|
||
|
_this._startTime();
|
||
|
this.innerHTML = 'Pause';
|
||
|
} else if (this.innerHTML == 'Pause') {
|
||
|
_this.stop();
|
||
|
this.innerHTML = 'Start';
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
this._startTime = function(){
|
||
|
|
||
|
this.timeId = setInterval(function(){GAME_TIME++;}, 1000);
|
||
|
};
|
||
|
|
||
|
this._stopTime = function(){
|
||
|
|
||
|
if(this.timeId){
|
||
|
|
||
|
clearInterval(this.timeId);
|
||
|
this.timeId = false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.play = function() {
|
||
|
|
||
|
_this.dynamicBackgroundPositionY += PX_DX;
|
||
|
_this.container.style.backgroundPositionY = _this.dynamicBackgroundPositionY + 'px';
|
||
|
|
||
|
_this.obstacleManager.refreshObstacles();
|
||
|
|
||
|
if(GAME_TIME % GAME_TIME_DX == 0) {
|
||
|
PX_DX += PX_DX_DX;
|
||
|
OBSTACLE_APPEARANCE_GAP -= OBSTACLE_APPEARANCE_DX;
|
||
|
}
|
||
|
|
||
|
_this.playId = window.requestAnimationFrame(_this.play);
|
||
|
|
||
|
if (_this.collisionHander.checkCollisions()) {
|
||
|
|
||
|
_this.gameOver();
|
||
|
}
|
||
|
|
||
|
_this.collisionHander.checkShot();
|
||
|
};
|
||
|
|
||
|
this.gameOver = function(){
|
||
|
|
||
|
var gameOver = document.createElement('div');
|
||
|
gameOver.className = 'game-over';
|
||
|
gameOver.innerHTML = 'GAME OVER';
|
||
|
_this.container.appendChild(gameOver);
|
||
|
_this.stop();
|
||
|
};
|
||
|
|
||
|
this.stop = function() {
|
||
|
|
||
|
this.obstacleManager.stop();
|
||
|
window.cancelAnimationFrame(_this.playId);
|
||
|
_this.car.stop();
|
||
|
_this._stopTime();
|
||
|
};
|
||
|
|
||
|
this._init();
|
||
|
}
|
||
|
|
||
|
var nfs = new NFS();
|