Bomb HTML

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 13

<!

DOCTYPE html>

<html>

<head>

<title>Basic Bomberman HTML Game</title>

<meta charset="UTF-8">

<style>

html, body {

height: 100%;

margin: 0;

body {

background: black;

display: flex;

align-items: center;

justify-content: center;

canvas {

background: forestgreen;

</style>

</head>

<body>

<canvas width="960" height="832" id="game"></canvas>

<script>

const canvas = document.getElementById('game');

const context = canvas.getContext('2d');

const grid = 64;

const numRows = 13;

const numCols = 15;


// create a new canvas and draw the soft wall image. then we can use this

// canvas to draw the images later on

const softWallCanvas = document.createElement('canvas');

const softWallCtx = softWallCanvas.getContext('2d');

softWallCanvas.width = softWallCanvas.height = grid;

softWallCtx.fillStyle = 'black';

softWallCtx.fillRect(0, 0, grid, grid);

softWallCtx.fillStyle = '#a9a9a9';

// 1st row brick

softWallCtx.fillRect(1, 1, grid - 2, 20);

// 2nd row bricks

softWallCtx.fillRect(0, 23, 20, 18);

softWallCtx.fillRect(22, 23, 42, 18);

// 3rd row bricks

softWallCtx.fillRect(0, 43, 42, 20);

softWallCtx.fillRect(44, 43, 20, 20);

// create a new canvas and draw the soft wall image. then we can use this

// canvas to draw the images later on

const wallCanvas = document.createElement('canvas');

const wallCtx = wallCanvas.getContext('2d');

wallCanvas.width = wallCanvas.height = grid;

wallCtx.fillStyle = 'black';

wallCtx.fillRect(0, 0, grid, grid);

wallCtx.fillStyle = 'white';
wallCtx.fillRect(0, 0, grid - 2, grid - 2);

wallCtx.fillStyle = '#a9a9a9';

wallCtx.fillRect(2, 2, grid - 4, grid - 4);

// create a mapping of object types

const types = {

wall: '▉',

softWall: 1,

bomb: 2

};

// keep track of all entities

let entities = [];

// keep track of what is in every cell of the game using a 2d array. the

// template is used to note where walls are and where soft walls cannot spawn.

// '▉' represents a wall

// 'x' represents a cell that cannot have a soft wall (player start zone)

let cells = [];

const template = [

['▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉'],

['▉','x','x', , , , , , , , , ,'x','x','▉'],

['▉','x','▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉','x','▉'],

['▉','x', , , , , , , , , , , ,'x','▉'],

['▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉'],

['▉', , , , , , , , , , , , , ,'▉'],

['▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉'],

['▉', , , , , , , , , , , , , ,'▉'],

['▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉'],

['▉','x', , , , , , , , , , , ,'x','▉'],

['▉','x','▉', ,'▉', ,'▉', ,'▉', ,'▉', ,'▉','x','▉'],


['▉','x','x', , , , , , , , , ,'x','x','▉'],

['▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉','▉']

];

// populate the level with walls and soft walls

function generateLevel() {

cells = [];

for (let row = 0; row < numRows; row++) {

cells[row] = [];

for (let col = 0; col < numCols; col++) {

// 90% chance cells will contain a soft wall

if (!template[row][col] && Math.random() < 0.90) {

cells[row][col] = types.softWall;

else if (template[row][col] === types.wall) {

cells[row][col] = types.wall;

// blow up a bomb and its surrounding tiles

function blowUpBomb(bomb) {

// bomb has already exploded so don't blow up again

if (!bomb.alive) return;

bomb.alive = false;
// remove bomb from grid

cells[bomb.row][bomb.col] = null;

// explode bomb outward by size

const dirs = [{

// up

row: -1,

col: 0

}, {

// down

row: 1,

col: 0

}, {

// left

row: 0,

col: -1

}, {

// right

row: 0,

col: 1

}];

dirs.forEach((dir) => {

for (let i = 0; i < bomb.size; i++) {

const row = bomb.row + dir.row * i;

const col = bomb.col + dir.col * i;

const cell = cells[row][col];

// stop the explosion if it hit a wall

if (cell === types.wall) {

return;
}

// center of the explosion is the first iteration of the loop

entities.push(new Explosion(row, col, dir, i === 0 ? true : false));

cells[row][col] = null;

// bomb hit another bomb so blow that one up too

if (cell === types.bomb) {

// find the bomb that was hit by comparing positions

const nextBomb = entities.find((entity) => {

return (

entity.type === types.bomb &&

entity.row === row && entity.col === col

);

});

blowUpBomb(nextBomb);

// stop the explosion if hit anything

if (cell) {

return;

});

// bomb constructor function

function Bomb(row, col, size, owner) {

this.row = row;

this.col = col;
this.radius = grid * 0.4;

this.size = size; // the size of the explosion

this.owner = owner; // which player placed this bomb

this.alive = true;

this.type = types.bomb;

// bomb blows up after 3 seconds

this.timer = 3000;

// update the bomb each frame

this.update = function(dt) {

this.timer -= dt;

// blow up bomb if timer is done

if (this.timer <= 0) {

return blowUpBomb(this);

// change the size of the bomb every half second. we can determine the size

// by dividing by 500 (half a second) and taking the ceiling of the result.

// then we can check if the result is even or odd and change the size

const interval = Math.ceil(this.timer / 500);

if (interval % 2 === 0) {

this.radius = grid * 0.4;

else {

this.radius = grid * 0.5;

};

// render the bomb each frame


this.render = function() {

const x = (this.col + 0.5) * grid;

const y = (this.row + 0.5) * grid;

// draw bomb

context.fillStyle = 'black';

context.beginPath();

context.arc(x, y, this.radius, 0, 2 * Math.PI);

context.fill();

// draw bomb fuse moving up and down with the bomb size

const fuseY = (this.radius === grid * 0.5 ? grid * 0.15 : 0);

context.strokeStyle = 'white';

context.lineWidth = 5;

context.beginPath();

context.arc(

(this.col + 0.75) * grid,

(this.row + 0.25) * grid - fuseY,

10, Math.PI, -Math.PI / 2

);

context.stroke();

};

// explosion constructor function

function Explosion(row, col, dir, center) {

this.row = row;

this.col = col;

this.dir = dir;

this.alive = true;
// show explosion for 0.3 seconds

this.timer = 300;

// update the explosion each frame

this.update = function(dt) {

this.timer -= dt;

if (this.timer <=0) {

this.alive = false;

};

// render the explosion each frame

this.render = function() {

const x = this.col * grid;

const y = this.row * grid;

const horizontal = this.dir.col;

const vertical = this.dir.row;

// create a fire effect by stacking red, orange, and yellow on top of

// each other using progressively smaller rectangles

context.fillStyle = '#D72B16'; // red

context.fillRect(x, y, grid, grid);

context.fillStyle = '#F39642'; // orange

// determine how to draw based on if it's vertical or horizontal

// center draws both ways

if (center || horizontal) {

context.fillRect(x, y + 6, grid, grid - 12);

}
if (center || vertical) {

context.fillRect(x + 6, y, grid - 12, grid);

context.fillStyle = '#FFE5A8'; // yellow

if (center || horizontal) {

context.fillRect(x, y + 12, grid, grid - 24);

if (center || vertical) {

context.fillRect(x + 12, y, grid - 24, grid);

};

// player character (just a simple circle)

const player = {

row: 1,

col: 1,

numBombs: 1,

bombSize: 3,

radius: grid * 0.35,

render() {

const x = (this.col + 0.5) * grid;

const y = (this.row + 0.5) * grid;

context.save();

context.fillStyle = 'white';

context.beginPath();

context.arc(x, y, this.radius, 0, 2 * Math.PI);

context.fill();
}

// game loop

let last;

let dt;

function loop(timestamp) {

requestAnimationFrame(loop);

context.clearRect(0,0,canvas.width,canvas.height);

// calculate the time difference since the last update. requestAnimationFrame

// passes the current timestamp as a parameter to the loop

if (!last) {

last = timestamp;

dt = timestamp - last;

last = timestamp;

// update and render everything in the grid

for (let row = 0; row < numRows; row++) {

for (let col = 0; col < numCols; col++) {

switch(cells[row][col]) {

case types.wall:

context.drawImage(wallCanvas, col * grid, row * grid);

break;

case types.softWall:

context.drawImage(softWallCanvas, col * grid, row * grid);

break;

}
// update and render all entities

entities.forEach((entity) => {

entity.update(dt);

entity.render();

});

// remove dead entities

entities = entities.filter((entity) => entity.alive);

player.render();

// listen to keyboard events to move the snake

document.addEventListener('keydown', function(e) {

let row = player.row;

let col = player.col;

// left arrow key

if (e.which === 37) {

col--;

// up arrow key

else if (e.which === 38) {

row--;

// right arrow key

else if (e.which === 39) {

col++;

// down arrow key


else if (e.which === 40) {

row++;

// space key (bomb)

else if (

e.which === 32 && !cells[row][col] &&

// count the number of bombs the player has placed

entities.filter((entity) => {

return entity.type === types.bomb && entity.owner === player

}).length < player.numBombs

){

// place bomb

const bomb = new Bomb(row, col, player.bombSize, player);

entities.push(bomb);

cells[row][col] = types.bomb;

// don't move the player if something is already at that position

if (!cells[row][col]) {

player.row = row;

player.col = col;

});

// start the game

generateLevel();

requestAnimationFrame(loop);

</script>

</body>

</html>

You might also like