02/12/2023
This commit is contained in:
12
need-for-speed/README.md
Normal file
12
need-for-speed/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Need For Speed - A car racing game (using JS and CSS)
|
||||
|
||||
Need for Speed using Javascript(JS) and CSS only.
|
||||
Play here: https://ashimregme.github.io/need-for-speed
|
||||
|
||||
## Controls
|
||||
|
||||
```
|
||||
Space -> Fires weapon
|
||||
Left and Right Arrows -> Avoid Obstacle
|
||||
```
|
||||

|
4
need-for-speed/css/reset.css
Normal file
4
need-for-speed/css/reset.css
Normal file
@@ -0,0 +1,4 @@
|
||||
*{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
76
need-for-speed/css/style.css
Normal file
76
need-for-speed/css/style.css
Normal file
@@ -0,0 +1,76 @@
|
||||
.title{
|
||||
|
||||
width: 40%;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid black;
|
||||
height: 500px;
|
||||
width: 302px;
|
||||
top: 15px;
|
||||
}
|
||||
|
||||
.container {
|
||||
height: 2000px;
|
||||
width: 100%;
|
||||
background-image: url('../images/road.png');
|
||||
background-size: contain;
|
||||
background-repeat: repeat-y;
|
||||
}
|
||||
|
||||
.lane {
|
||||
float: left;
|
||||
width: 33.33%;
|
||||
height: 500px;
|
||||
min-height: 500px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.lane > .car {
|
||||
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
margin: 0 auto;
|
||||
width: 40px;
|
||||
height: 80px;
|
||||
margin-left: 10%;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: absolute;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.obstacle{
|
||||
|
||||
width: 100px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.bullets{
|
||||
|
||||
display: block;
|
||||
position: absolute;
|
||||
margin-left: 13%;
|
||||
bottom: 90px;
|
||||
}
|
||||
|
||||
.game-over{
|
||||
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
background: red;
|
||||
width: 80%;
|
||||
padding: 10%;
|
||||
text-align: center;
|
||||
color: white;
|
||||
font-size: 27px;
|
||||
}
|
BIN
need-for-speed/images/bullets.png
Normal file
BIN
need-for-speed/images/bullets.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
BIN
need-for-speed/images/car.png
Normal file
BIN
need-for-speed/images/car.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
BIN
need-for-speed/images/obstacle.png
Normal file
BIN
need-for-speed/images/obstacle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
need-for-speed/images/road.png
Normal file
BIN
need-for-speed/images/road.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
32
need-for-speed/index.html
Normal file
32
need-for-speed/index.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Need for Kergi</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/reset.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class = "title">
|
||||
<h1>Need for Kergi - Most Wanted</h1>
|
||||
<span style="color: red">Spacebar fires bullets</span>
|
||||
<br>
|
||||
<span style="color: red">Press 'start' to begin</span>
|
||||
<br>
|
||||
<button id="toggle">Start</button>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<div class="container" id="container">
|
||||
<div class="lane">
|
||||
</div>
|
||||
<div class="lane">
|
||||
</div>
|
||||
<div class="lane">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="js/nfs.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
401
need-for-speed/js/nfs.js
Normal file
401
need-for-speed/js/nfs.js
Normal file
@@ -0,0 +1,401 @@
|
||||
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();
|
BIN
need-for-speed/sample.png
Normal file
BIN
need-for-speed/sample.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
Reference in New Issue
Block a user