Skip to content

Commit

Permalink
Added a basic game built in VanillaJavascript with Parcel bundeler
Browse files Browse the repository at this point in the history
  • Loading branch information
azizkhoso committed Oct 30, 2021
1 parent b52a5d2 commit 575171d
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 0 deletions.
20 changes: 20 additions & 0 deletions BrickBreakerGame/.codesandbox/workspace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"responsive-preview": {
"Mobile": [
320,
675
],
"Tablet": [
1024,
765
],
"Desktop": [
1400,
800
],
"Desktop HD": [
1920,
1080
]
}
}
4 changes: 4 additions & 0 deletions BrickBreakerGame/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# BrickBreaker
Created with CodeSandbox works in Parcel

![brickbreaker](https://user-images.githubusercontent.com/60597318/118232580-36b1e400-b4aa-11eb-968c-0ecc3c8ecae8.gif)
Binary file added BrickBreakerGame/assets/images/ball.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BrickBreakerGame/assets/images/brick.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions BrickBreakerGame/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JavaScript Game</title>
<style>
#gameScreen {
border: 1px solid black;
}
img {
width: 10px;
height: 8px;
display: none;
}
</style>
</head>
<body>
<img id="ballImg" src="./assets/images/ball.png" />
<img id="brickImg" src="./assets/images/brick.png" alt="brick" />
<canvas id="gameScreen" width="800px" height="600px"></canvas>
<script src="src/index.js"></script>
</body>
</html>
33 changes: 33 additions & 0 deletions BrickBreakerGame/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "brickbreaker",
"version": "1.0.0",
"description": "JavaScript example starter project",
"main": "index.html",
"scripts": {
"start": "parcel index.html --open",
"build": "parcel build index.html"
},
"dependencies": {
"parcel-bundler": "^1.6.1"
},
"devDependencies": {
"@babel/core": "7.2.0"
},
"resolutions": {
"@babel/preset-env": "7.13.8"
},
"keywords": [
"javascript",
"starter"
],
"repository": {
"type": "git",
"url": "git+https://github.com/AbdulAziz0682/BrickBreaker.git"
},
"author": "Abdul Aziz Khoso",
"license": "ISC",
"bugs": {
"url": "https://github.com/AbdulAziz0682/BrickBreaker/issues"
},
"homepage": "https://github.com/AbdulAziz0682/BrickBreaker#readme"
}
41 changes: 41 additions & 0 deletions BrickBreakerGame/src/ball.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { detectCollision } from "./collisionDetection";
export default class Ball {
constructor(game) {
this.image = document.getElementById("ballImg");
this.size = 16;
this.gameHeight = game.gameHeight;
this.gameWidth = game.gameWidth;
this.game = game;
this.reset();
}
reset(){
this.pos = { x: 10, y: 500 };
this.speed = { x: 4, y: -4 };
console.log('Ball pos: '+this.pos.x+","+this.pos.y);
}
draw(ctx) {
ctx.drawImage(this.image, this.pos.x, this.pos.y, this.size, this.size);
}
update() {
this.pos.x += this.speed.x;
this.pos.y += this.speed.y;
//left and right walls
if (this.pos.x + this.size > this.gameWidth || this.pos.x < 0) {
this.speed.x = -this.speed.x;
}
//top
if (this.pos.y < 0) {
this.speed.y = -this.speed.y;
}
//bottom
if(this.pos.y + this.size >= this.gameHeight){
this.game.lives--;
this.reset();
}
//collision with paddle
if (detectCollision(this, this.game.paddle)) {
this.speed.y = -this.speed.y;
this.pos.y = this.game.paddle.pos.y - this.size;
}
}
}
20 changes: 20 additions & 0 deletions BrickBreakerGame/src/brick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { detectCollision } from "./collisionDetection";
export default class Brick {
constructor(game, position) {
this.image = document.getElementById("brickImg");
this.pos = position;
this.game = game;
this.width = 80;
this.height = 25;
this.markForDeletion = false;
}
update() {
if (detectCollision(this.game.ball, this)) {
this.game.ball.speed.y = -this.game.ball.speed.y;
this.markForDeletion = true;
}
}
draw(ctx) {
ctx.drawImage(this.image, this.pos.x, this.pos.y, this.width, this.height);
}
}
20 changes: 20 additions & 0 deletions BrickBreakerGame/src/collisionDetection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export function detectCollision(ball, gameObject) {
let bottomOfBall = ball.pos.y + ball.size;
let topOfBall = ball.pos.y;

let topOfObject = gameObject.pos.y;
let leftSideOfObject = gameObject.pos.x;
let rightSideoOfObject = gameObject.pos.x + gameObject.width;
let bottomOfObject = gameObject.pos.y + gameObject.height;

if (
bottomOfBall >= topOfObject &&
topOfBall <= bottomOfObject &&
ball.pos.x >= leftSideOfObject &&
ball.pos.x <= rightSideoOfObject
) {
return true;
} else {
return false;
}
}
94 changes: 94 additions & 0 deletions BrickBreakerGame/src/game.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import Paddle from "./paddle";
import InputHandler from "./input";
import Ball from "./ball";
import { buildLevel, level1, level2 } from "./levels";

const GAME_STATE = {
PAUSED: 0,
RUNNING: 1,
MENU: 2,
GAMEOVER: 3,
NEWLEVEL: 4
};

export default class Game {
constructor(gameWidth, gameHeight) {
this.gameWidth = gameWidth;
this.gameHeight = gameHeight;
this.gameState = GAME_STATE.MENU;
this.paddle = new Paddle(this);
this.ball = new Ball(this);
this.lives = 3;
this.bricks = [];
new InputHandler(this.paddle, this);
this.gameObjects = [];

this.levels = [level1, level2];
this.currentLevel = 0;
}
start() {
if(this.gameState !== GAME_STATE.MENU && this.gameState !== GAME_STATE.NEWLEVEL) return;
this.bricks = buildLevel(this, this.levels[this.currentLevel]);
this.ball.reset();
this.gameObjects = [this.paddle, this.ball];
this.gameState = GAME_STATE.RUNNING;
}
update(ctx) {
if(this.lives == 0) this.gameState = GAME_STATE.GAMEOVER;
if ((this.gameState == GAME_STATE.PAUSED) || (this.gameState == GAME_STATE.MENU) || (this.gameState == GAME_STATE.GAMEOVER)) return;
if(this.bricks.length === 0){
this.currentLevel++;
this.gameState = GAME_STATE.NEWLEVEL;
this.start();

}
[...this.gameObjects, ...this.bricks].forEach((obj) => {
obj.update(ctx);
});
this.bricks = this.bricks.filter((obj) => !obj.markForDeletion);
}
draw(ctx) {
[...this.gameObjects, ...this.bricks].forEach((obj) => {
obj.draw(ctx);
});
if(this.gameState == GAME_STATE.PAUSED){
ctx.rect(0, 0, this.gameWidth, this.gameHeight);
ctx.fillStyle = "rgb(0, 0, 5)";
ctx.fill();

ctx.font = "30px Arial";
ctx.fillStyle = "white";
ctx.textAlign = 'center';
ctx.fillText("Paused", this.gameWidth/2, this.gameHeight/2);
}
if(this.gameState == GAME_STATE.MENU){
ctx.rect(0, 0, this.gameWidth, this.gameHeight);
ctx.fillStyle = "rgb(0, 0, 5)";
ctx.fill();

ctx.font = "30px Arial";
ctx.fillStyle = "white";
ctx.textAlign = 'center';
ctx.fillText("Press Space to Start", this.gameWidth/2, this.gameHeight/2);
}
if(this.gameState == GAME_STATE.GAMEOVER){
ctx.rect(0, 0, this.gameWidth, this.gameHeight);
ctx.fillStyle = "rgb(0, 0, 5)";
ctx.fill();

ctx.font = "30px Arial";
ctx.fillStyle = "white";
ctx.textAlign = 'center';
ctx.fillText("GAME OVER", this.gameWidth/2, this.gameHeight/2);
}
}
togglePause() {

if (this.gameState == GAME_STATE.PAUSED) {
console.log('Pause func')
this.gameState = GAME_STATE.RUNNING;
} else {
this.gameState = GAME_STATE.PAUSED;
}
}
}
17 changes: 17 additions & 0 deletions BrickBreakerGame/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Game from "./game";

const GAME_WIDTH = 800;
const GAME_HEIGHT = 600;
let canvas = document.getElementById("gameScreen");
let ctx = canvas.getContext("2d");

let game = new Game(GAME_WIDTH, GAME_HEIGHT);

function gameloop(timestamp) {
ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
game.update();
game.draw(ctx);
requestAnimationFrame(gameloop);
}

gameloop();
34 changes: 34 additions & 0 deletions BrickBreakerGame/src/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export default class InputHandler {
constructor(paddle, game) {
document.addEventListener("keydown", (e) => {
switch (e.keyCode) {
case 37:
paddle.moveLeft();
break;
case 39:
paddle.moveRight();
break;
case 27:
game.togglePause();
break;
case 32:
game.start();
break;
default:
break;
}
});
document.addEventListener("keyup", (e) => {
switch (e.keyCode) {
case 37:
if (paddle.speed < 0) paddle.stop();
break;
case 39:
if (paddle.speed > 0) paddle.stop();
break;
default:
break;
}
});
}
}
31 changes: 31 additions & 0 deletions BrickBreakerGame/src/levels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Brick from "./brick";

export function buildLevel(game, level) {
let bricks = [];
level.forEach((row, rowIndex) => {
row.forEach((element, index) => {
if (element === 1) {
let position = {
x: index * 80,
y: 100 + 25 * rowIndex
};
bricks.push(new Brick(game, position));
}
});
});
return bricks;
}

export const level1 = [
[0, 1, 0, 1, 1, 0, 0, 0, 1, 1],
[1, 1, 1, 1, 0, 0, 0, 1, 1, 1],
[0, 1, 0, 1, 0, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0, 1, 1, 0, 0]
];

export const level2 = [
[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1],
[0, 1, 1, 1, 1, 0, 1, 1, 0, 1]
];
32 changes: 32 additions & 0 deletions BrickBreakerGame/src/paddle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export default class Paddle {
constructor(game) {
this.width = 150;
this.height = 25;
this.maxSpeed = 5;
this.speed = 0;
this.pos = {
x: game.gameWidth / 2 - this.width / 2,
y: game.gameHeight - this.height - 10
};

this.draw = (ctx) => {
ctx.fillStyle = "#0ff";
ctx.fillRect(this.pos.x, this.pos.y, this.width, this.height);
};
this.moveLeft = () => {
this.speed += -this.maxSpeed;
};
this.moveRight = () => {
this.speed += this.maxSpeed;
};
this.stop = () => {
this.speed = 0;
};
this.update = () => {
this.pos.x += this.speed;
if (this.pos.x < 0) this.pos.x = 0;
if (this.pos.x + this.width > game.gameWidth)
this.pos.x = game.gameWidth - this.width;
};
}
}

0 comments on commit 575171d

Please sign in to comment.