Develop a Bomberman Maze Arcade Phaser Game In Browser Using Javascript CSS3 and HTML5 Complete Project

Welcome Learner today in this blog post we will be Develop a Bomberman Maze Arcade in Phaser game in Browser With Javascript HTML5 and CSS3. All the Complete source code of the application is shown Down.

 

Bomberman Maze Arcade Game

 

index.html 

 

<!--
Cursors and space to move and plant bombs respectively.
-->
<div id="screen"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser-ce/2.8.1/phaser.min.js"></script>

<script src="https://rawgit.com/spite/ccapture.js/master/build/CCapture.all.min.js"></script>

 

READ Develop a Greedy snake Game In Browser Using Javascript CSS3 and HTML5 Complete Project For learner

 

style.css 

 

html, body {
     background: #222;
     padding: 0;
     margin: 0;
}
 #screen {
     position: relative;
}
 #screen:after {
     position: absolute;
     left: 0;
     top: 0;
     right: 0;
     bottom: 0;
     content: '';
     background-image: linear-gradient(to bottom, #fff, #fff 33%, #000 66%, #000);
     opacity: 0.1;
     background-size: 100% 0.3472%;
}
 #screen canvas {
     box-sizing: border-box;
     display: block;
     width: 100% !important;
     height: auto !important;
     margin: 0;
     pointer-events: none;
     padding: 2%;
     background-color: #000;
}

 

 

script.js 

 

 

'use strict';

class Entity extends Phaser.Sprite {
  constructor(game, x, y, grid, index = 0) {
    super(game, x, y, 'sprites', index);
    this.anchor.setTo(.5);
    this.game.physics.arcade.enable(this);
    this.grid = grid;
    this.grid.add(this);
    if (this.gridPos) {
      this.grid.screenToGrid(this.x, this.y, this.gridPos);
    }
  }

  destroy() {
    this.grid.remove(this);
    super.destroy();
  }

  kill() {
    super.kill();
  }
}

class Wall extends Entity {
  constructor(game, x, y, grid) {
    super(game, x, y, grid, 0);
    this.body.moves = false;
    this.body.immovable = true;
    this.slack = 0.5;
    this.body.setSize(32 - this.slack, 32 - this.slack, this.slack * 0.5, this.slack * 0.5)
  }
  
  kill() {
    // cannot be killed
  }
}

class Bricks extends Wall {
  constructor(game, x, y, grid) {
    super(game, x, y, grid);
    this.frame = 1;
  }
  
  kill() {
    const pickupChance = this.game.rnd.frac();
    const tween = this.game.add.tween(this).to({alpha: 0}, 300, Phaser.Easing.Linear.None, true);
    
    tween.onComplete.add(() => {
      this.destroy();
    }, this);
    
    // 1/4 chance of dropping a power-up feels about right to me...
    if (pickupChance < 0.25) {
      this.dropPickup();
    }
  }
  
  dropPickup() {
    const place = this.gridPos.clone();
    const screenPos = this.grid.gridToScreen(place.x, place.y);
    
    const pickupClasses = [PickupBomb, PickupFire];
    const pickupClass = this.game.rnd.pick(pickupClasses);
    
    const pickup = new (pickupClass)(this.game, screenPos.x, screenPos.y, this.grid);
    
    this.parent.add(pickup);
  }
}

class Player extends Entity {
  constructor(game, x, y, grid) {
    super(game, x, y, grid, 6);

    this.controls = this.game.input.keyboard.createCursorKeys();
    this.speed = 96;

    this.totalBombs = 1;
    this.currentBombs = 0;
    this.bombSize = 3;

    this.body.setCircle(16);
    this.body.drag.set(768);

    this.lastGridPos = this.gridPos.clone();
    
    this.blastThrough = true;
  }

  update() {
    super.update();
    if (!this.alive) {
      return;
    }
    if (this.controls.up.isDown) {
      this.body.velocity.y = this.speed * -1;
    }
    else if (this.controls.down.isDown) {
      this.body.velocity.y = this.speed;
    }

    if (this.controls.left.isDown) {
      this.body.velocity.x = this.speed * -1;
    }
    else if (this.controls.right.isDown) {
      this.body.velocity.x = this.speed;
    }

    if (this.game.input.keyboard.justPressed(Phaser.Keyboard.SPACEBAR)) {
      this.dropBomb();
    }
    if (this.gridPos) {
      this.grid.screenToGrid(this.x, this.y, this.gridPos);
    }

    if (!this.gridPos.equals(this.lastGridPos)) {
      this.lastGridPos.copyFrom(this.gridPos);
      this.checkGrid();
    }
  }

  kill() {
    this.body.moves = false;
    super.kill();
  }

  canPlaceBomb(place) {
    const item = this.grid.getAt(place.x, place.y, this);
    if (!item) {
      return true;
    }
    return false;
  }

  dropBomb() {    
    const place = this.gridPos.clone();
    const screenPos = this.grid.gridToScreen(place.x, place.y);
    if (this.currentBombs < this.totalBombs && this.canPlaceBomb(place)) {
      const bomb = new Bomb(this.game, screenPos.x, screenPos.y, this.grid, this);
      this.parent.add(bomb);
    }
  }
  
  checkGrid() {
    const item = this.grid.getAt(this.gridPos.x, this.gridPos.y, this);
    if (item && item instanceof Pickup) {
      item.collect(this);
    }
  }
}

class Pickup extends Entity {
  constructor(game, x, y, grid, index) {
    if (new.target === Pickup) {
      throw new TypeError("Cannot construct Abstract instances directly");
    }
    super(game, x, y, grid, index);
    this.body.enable = false;
    this.body.moves = false;
  }
  
  collect(player) {
    this.destroy();
  }
}

class PickupBomb extends Pickup {
  constructor(game, x, y, grid) {
    super(game, x, y, grid, 8);
  }
  
  collect(player) {
    super.collect(player);
    player.totalBombs += 1;
  }
}

class PickupFire extends Pickup {
  constructor(game, x, y, grid) {
    super(game, x, y, grid, 9);
  }
  
  collect(player) {
    super.collect(player);
    player.bombSize += 1;
  }
}

class Bomb extends Entity {
  constructor(game, x, y, grid, owner) {
    super(game, x, y, grid, 2);

    this.owner = owner;

    this.body.immovable = true;
    this.body.moves = false;

    if (this.owner) {
      this.owner.currentBombs += 1;
    }
    
    this.size = this.owner.bombSize || 3;

    this.duration = Phaser.Timer.SECOND * 3;
    this.explodeTimer = this.game.time.events.add(this.duration, this.explode, this);

    const tween1 = this.game.add.tween(this.scale).to({x: 1.1, y: 0.9}, this.duration / 9, Phaser.Easing.Circular.InOut, true, 0, -1);
    tween1.yoyo(true, 0);
    const tween2 = this.game.add.tween(this.anchor).to({y: 0.45}, this.duration / 9, Phaser.Easing.Circular.InOut, true, 0, -1);
    tween2.yoyo(true, 0);
  }

  explode() {
    this.game.time.events.remove(this.explodeTimer);
    if (this.owner) {
      this.owner.currentBombs -= 1;
    }
    this.grid.remove(this);

    const explosion = new Explosion(this.game, this.x, this.y, this.grid, this.owner, this.size, this.parent);

    this.destroy();
  }

  kill() {
    this.explode();
  }
}

class Explosion extends Entity {
  constructor(game, x, y, grid, owner, size = 3, parent = null) {
    super(game, x, y, grid, 5);
    this.size = size;
    this.owner = owner;
    this.body.immovable = true;
    this.body.moves = false;
    
    this.game.camera.shake(0.0075, 500);

    this.duration = Phaser.Timer.SECOND * .5;
    this.decayTimer = this.game.time.events.add(this.duration, this.destroy, this);

    parent.add(this);

    this.locs = this.getExplosionLocations();
    this.doExplosion();
  }

  doExplosion() {
    this.blast = [];

    // Urgh. Improve plz.
    for (let i = 0; i < this.locs.left.length; i++) {
      const blastPos = this.grid.gridToScreen(this.locs.left[i].x, this.locs.left[i].y);
      const blast = new Blast(this.game, blastPos.x, blastPos.y, this.grid, this.owner);
      blast.angle = -90;
      if (i === this.size - 2) {
        blast.frame = 3;
      }
      this.blast.push(blast);
      this.parent.add(blast);
    }

    for (let i = 0; i < this.locs.right.length; i++) {
      const blastPos = this.grid.gridToScreen(this.locs.right[i].x, this.locs.right[i].y);
      const blast = new Blast(this.game, blastPos.x, blastPos.y, this.grid, this.owner);
      blast.angle = 90;
      if (i === this.size - 2) {
        blast.frame = 3;
      }
      this.blast.push(blast);
      this.parent.add(blast);
    }

    for (let i = 0; i < this.locs.up.length; i++) {
      const blastPos = this.grid.gridToScreen(this.locs.up[i].x, this.locs.up[i].y);
      const blast = new Blast(this.game, blastPos.x, blastPos.y, this.grid, this.owner);
      blast.angle = 0;
      if (i === this.size - 2) {
        blast.frame = 3;
      }
      this.blast.push(blast);
      this.parent.add(blast);
    }

    for (let i = 0; i < this.locs.down.length; i++) {
      const blastPos = this.grid.gridToScreen(this.locs.down[i].x, this.locs.down[i].y);
      const blast = new Blast(this.game, blastPos.x, blastPos.y, this.grid, this.owner);
      blast.angle = 180;
      if (i === this.size - 2) {
        blast.frame = 3;
      }
      this.blast.push(blast);
      this.parent.add(blast);
    }
  }

  getExplosionLocations() {
    const x = this.gridPos.x;
    const y = this.gridPos.y;
    const points = {
      left: [],
      right: [],
      up: [],
      down: []
    };
    const obstructed = {
      left: false,
      right: false,
      up: false,
      down: false
    }

    // Jesus, these explosion routines... gotta fix these :(
    for (let w = 1; w < this.size; w++) {
      let entity;
      if (!obstructed.right) {
        entity = this.grid.getAt(x + w, y);
        if (!entity || entity.blastThrough) {
          points.right.push(new Phaser.Point(x + w, y));
        }
        else {
          obstructed.right = true;
          if (entity && entity instanceof Entity) {
            entity.kill();
          }
        }
      }

      if (!obstructed.left) {
        entity = this.grid.getAt(x - w, y);
        if (!entity || entity.blastThrough) {
          points.left.push(new Phaser.Point(x - w, y));
        }
        else {
          obstructed.left = true;
          if (entity && entity instanceof Entity) {
            entity.kill();
          }
        }
      }

      if (!obstructed.down) {
        entity = this.grid.getAt(x, y + w);
        if (!entity || entity.blastThrough) {
          points.down.push(new Phaser.Point(x, y + w));
        }
        else {
          obstructed.down = true;
          if (entity && entity instanceof Entity) {
            entity.kill();
          }
        }
      }

      if (!obstructed.up) {
        entity = this.grid.getAt(x, y - w);
        if (!entity || entity.blastThrough) {
          points.up.push(new Phaser.Point(x, y - w));
        }
        else {
          obstructed.up = true;
          if (entity && entity instanceof Entity) {
            entity.kill();
          }
        }
      }
    }
    return points;
  }

  destroy() {
    this.game.time.events.remove(this.decayTimer);
    for (let i = 0; i < this.blast.length; i++) {
      this.blast[i].destroy();
    }
    const tween = this.game.add.tween(this).to({alpha: 0}, 300, Phaser.Easing.Linear.None, true);
    tween.onComplete.add(() => {
      super.destroy();
    }, this);
  }
  
  kill() {
    // cannot be killed
  }
}

class Blast extends Entity {
  constructor(game, x, y, grid, owner) {
    super(game, x, y, grid, 4);
    this.body.moves = false;
    this.body.immovable = true;
    this.slack = 18;
    this.body.setSize(32 - this.slack, 32 - this.slack, this.slack * 0.5, this.slack * 0.5)
    
    this.blastThrough = true;
  }
  
  kill() {
    // cannot be killed
  }
  
  destroy() {
    this.body.enable = false;
    const tween = this.game.add.tween(this).to({alpha: 0}, 300, Phaser.Easing.Linear.None, true);
    tween.onComplete.add(() => {
      super.destroy();
    }, this);
  }
}

class Grid {
  constructor(width, height, size = 32) {
    this.width = width;
    this.height = height;
    this.size = size;
    this.items = [];
  }

  add(item) {
    this.items.push(item);
    item.gridPos = this.screenToGrid(item.x, item.y);
  }

  remove(item) {
    if (this.items.indexOf(item) !== -1) {
      this.items.splice(this.items.indexOf(item), 1);
    }
  }

  getAt(x, y, ignore) {
    if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
      for (let i = 0; i < this.items.length; i++) {
        let item = this.items[i];
        if (item !== ignore && item.gridPos.x === x && item.gridPos.y === y) {
          return item;
        }
      }
      return null;
    }
    return -1;
  }

  screenToGrid(x, y, point) {
    if (point) {
      point.x = Math.round(x / this.size);
      point.y = Math.round(y / this.size);
      return point;
    }
    return new Phaser.Point(Math.round(x / this.size), Math.round(y / this.size));
  }

  gridToScreen(x, y, point) {
    if (point) {
      point.x = x * this.size;
      point.y = y * this.size;
      return point;
    }
    return new Phaser.Point(x * this.size, y * this.size);
  }
}

class Level extends Phaser.State {
  preload() {
    this.stage.disableVisibilityChange = true;
    this.game.load.spritesheet('sprites', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACABAMAAAAxEHz4AAAAElBMVEUAAAD///+2trZLS0va2toAAAAGLkTLAAAAAXRSTlMAQObYZgAABB5JREFUaN6Ml2GO3CAMhRE5QZIewDy2/5Nwgq72BJV6/6vU2J4ExmzL+5HB0vD02TF4Jnytnb4iOlH4n371Bj+gylBdYajGen3Tm0EOoqWUgz9i1FAwXwYbmt3pHBIUUQNAQKSXwfYYpDQkKKawGgFE0wRLMZ0GEKnWgGi2BqUgmwFpBURjgzOXTlcFuNZNgv1QAlKLMUGLrwSlpJdBeTIAxTHBm8ElAGqQsr5LqGiSYGGANddsEsQAqAQbP6cILAMzKNUg8naG2jBFIAZZDKAGvD+l+s049xZkowhZCRDXqg1TfcAl2Bq/gwkYQb5JNDBwndgblGpASEoQ5wiu3BMEmAGBpghYPQFgNQBNEbA6AkgKWoSpt9Aq22u0FDDRB94g3EUETXViq10PoxnQ3FnoS/AUMSHOEHQG6dBOvFOYIQgNwB6aIiYEmruReoAAMwATuEt1eCu3AHqcN0vBX+vjW7kB0LMEM8AUgSFcqQTV3Ylx0EjfTKbrunJ55uJmNZDhunf6kXu1s1EV71aWPvDj/ep0BCewgxFEtUS0nOBir683yYb2cPh4bPDRGMQ7JwQXi4roGBG43o59LFpW0T4i6E8XR0RtrA7nqjrGBOGFTNUAhKcG7GUAhjAmIDtdmgKAO2Y3AzCEf74FENASyEoNiuhUA08QsD1FA+uOtdfOHT9/4w/yNwT96YLIYtY3Bp+NAQmyMgemSUga82Jk0Ks/XUQhJawqXUwQoBuW65smCKjJ2RnMEER2uFMYGqwFrHx+T2Ap0IBAO1HaQDrxk1UJPlhm0M97b+BbuZrU3dWkpvA0ztignLYu4xT6ee8Nyl4MoOyHa2U3753Bwhurg3zsjsDN+5RW2KiRRWB+ZqjaeXm8E7h5j9rJllLitRicoqIGvdy8R5XFVUog8gT+TjQDjdVgOfcXQVmLq4Gb90TNjcQBt8GxlMpQSii+ld28fwief1aL/OVBHl3rbt5HBnpivdjl5zY/juAJ3LyniCaOCgBkeQwI3Lx3cWfgCfy87+MJgn7eu3iCoJv3LrbZeshjXIPu6LzHE1pLo5Xjv+3VwW3DMAyFYWQDPxodgOQE5hulyP6rtFVkR1YPFhPkpv8sfCZsg7o3DQg3Wttyu7NtuQaiA75ZilFgtVP6xb/cK7GNAmQLhIQ5E0A5bKZyTEBIYgJnKaROEAwqbBxgPA4/34G6Qn0c2FCWpj0nUECGJ2AA5amsgLoAEB8GFHICgorfRgGnwk+ACXJA/Yw7EKEFkFEghLV4AHwXMOQAsgMEojDAXwdcZNM8EPt/gBXYkAe2AyiNAnYA3gFMArG+CNgxwBmQJBCyA5EFvAAaHbBmVloEm52oBfA3lirQLZTsWjdAOAbcrLtYeGr5JFCDNeHfZXvV1fU+m81ms9lslu4HtQ9fHtWYNW8AAAAASUVORK5CYII=', 32, 32);
  }

  create() {
    this.game.renderer.renderSession.roundPixels = true;
    this.game.physics.startSystem(Phaser.Physics.ARCADE);

    this.game.input.keyboard.addKeyCapture([ Phaser.Keyboard.UP, Phaser.Keyboard.DOWN, Phaser.Keyboard.LEFT, Phaser.Keyboard.RIGHT, Phaser.Keyboard.SPACEBAR ]);

    this.grid = new Grid(18, 14);

    this.background = this.game.add.group();
    this.items = this.game.add.physicsGroup();
    this.items.x = this.background.x = 16;
    this.items.y = this.background.y = 16;

    for (let x = 0; x <= this.grid.width; x++) {
      for (let y = 0; y <= this.grid.height; y ++) {
        if (x === 0 || y === 0 || x === this.grid.width || y === this.grid.height) {
          const wall = new Wall(this.game, x * this.grid.size, y * this.grid.size, this.grid);
          this.items.add(wall);
        }
        else if ((x > 0 && x < this.grid.width && !(x%2)) && (y > 0 && y < this.grid.height && !(y%2))) {
          const wall = new Wall(this.game, x * this.grid.size, y * this.grid.size, this.grid);
          this.items.add(wall);
        }
        else {
          this.background.create((x * this.grid.size), (y * this.grid.size), 'sprites', 7).anchor.set(.5);
          if (x > 1 && x < this.grid.width - 1 && y > 1 && y < this.grid.height - 1 && Math.random() > 0.25) {
            const bricks = new Bricks(this.game, x * this.grid.size, y * this.grid.size, this.grid);
            this.items.add(bricks);
          }
        }
      }
    }
    
    for (let x = 3; x < this.grid.width - 3; x++) {
        if (Math.random() > 0.15) {
          const bricks = new Bricks(this.game, x * this.grid.size, this.grid.size, this.grid);
          this.items.add(bricks);
        }
        if (Math.random() > 0.15) {
          const bricks = new Bricks(this.game, x * this.grid.size, (this.grid.height - 1) * this.grid.size, this.grid);
          this.items.add(bricks);
        }
    }
    for (let y = 3; y < this.grid.height - 3; y++) {
        if (Math.random() > 0.15) {
          const bricks = new Bricks(this.game, this.grid.size, y * this.grid.size, this.grid);
          this.items.add(bricks);
        }

        if (Math.random() > 0.15) {
          const bricks = new Bricks(this.game, (this.grid.width - 1) * this.grid.size, y * this.grid.size, this.grid);
          this.items.add(bricks);
        }
    }

    this.player = new Player(this.game, this.grid.size, this.grid.size, this.grid);
    this.items.add(this.player);
  };

  update() {
    this.game.physics.arcade.collide(this.player, this.items, (a, b) => {
      if (a instanceof Player && (b instanceof Blast || b instanceof Explosion)) {
        a.kill();
      }
    });
  };

  render() {
    /*
    this.game.debug.start();
    this.items.forEach((i) => {
      if (i.alive) {
        this.game.debug.context.fillStyle = 'rgba(255, 0, 0, 0.4)';
        const gridPos = this.grid.gridToScreen(i.gridPos.x, i.gridPos.y);
        this.game.debug.context.fillRect(gridPos.x, gridPos.y, this.grid.size, this.grid.size);
      }
    });
    this.game.debug.stop();

    this.items.forEach((i) => {
      if (i.alive) {
        this.game.debug.body(i);
      }
    })
    */
  };
};

class Game extends Phaser.Game {
  constructor() {
    super(608, 480, Phaser.AUTO, 'screen', null);
    this.state.add('Level', Level, false);
    this.state.start('Level');
  };
};

new Game();

Leave a Comment

Your email address will not be published. Required fields are marked *