metapod-madness

Metapod Madness is a 4-player minigame built using HTML5 Canvas and JavaScript.

Stars
7

Metapod Madness

Metapod Madness is a 4-player minigame drawing inspiration from the N64 classic, Pokemon Stadium, remastered in the form of a web application. Avoid damage from the boulders being launched at your cuddly cocoon pokemon by using its only move, Harden. However, be careful about overusing Harden since it will gradually drain your HP. Compete with your friends to see whose coordination is the fittest... last one standing wins!

Technologies Used

  • JavaScript
  • HTML5
  • CSS3

Features

Animation loop

The animate(time) method in the GameView class minimizes graphic rendering lag through usage of HTML5 Canvas and recursively looping the requestAnimationFrame method until the game is complete.

animate(time) {
  const timeDelta = time - this.lastTime;
  this.game.step(timeDelta);
  this.game.draw(this.ctx);
  this.lastTime = time;
  this.gameOver = this.game.over;

  if (!this.paused) {
    requestAnimationFrame(this.animate);
    if (this.gameOver) {
        this.paused = true;
        setTimeout(() => this.end(), 1000);
    };
  };
};

Metapod used Harden!

bindKeyHandlers () {
  const keys = this.keys;

  const keyDownHandler = (e) => {
    for (let i = 0; i < 4; i++) {
      if (e.key == keys[i]) {
        this.game.metapodsHardened[i] = true;
      };
    };
  };

  const keyUpHandler = (e) => {
    for (let i = 0; i < 4; i++) {
      if (e.key == keys[i]) {
        this.game.metapodsHardened[i] = false;
      };
    };
  };

  document.addEventListener("keydown", keyDownHandler, false);
  document.addEventListener("keyup", keyUpHandler, false);
};

3D in 2D

Though I initially planned to utilize three.js for this project, using diagonal lines as diminishing scale, I was able to reconfigure my Boulder and Shadow classes to craft the illusion of depth.

With each iteration of boulders that are added to the game, the shadows follow fixed vectors that uniformly spawn below their respective boulders, traverse diagonally toward their respective Metapods, and reach their final destination as the boulders fall to collide with the Metapods.

const shadowVelocities = [
  [-0.62, 1.3],
  [-0.28, 1.3],
  [0.12, 1.3],
  [0.48, 1.3],
];

The boulders spawn at various points closer to the vertical center of the canvas. They travel parallel to each other upwards, and upon reaching a fixed height, they grow in size and horizontally adjust to different points directly above their respective Metapod character models.

move(timeDelta) {
  if (this.pos[1] < -500) {
    this.width *= 1.5;
    this.height *= 1.5;
    this.vel = [0, 16];

    switch (this.idx) {
      case 0:
        this.pos[0] = this.game.dimensionX * (1 / 8) - 60
        break;
      case 1:
        this.pos[0] = this.game.dimensionX * (3 / 8) - 60
        break;
      case 2:
        this.pos[0] = this.game.dimensionX * (5 / 8) - 60
        break;
      case 3:
        this.pos[0] = this.game.dimensionX * (7 / 8) - 60
        break;
      default:
        break;
    };
  };

  super.move(timeDelta)
};

Collision mechanics (yay math!)

isCollidedWith(otherObject) {
  const pos1 = this.pos;
  const pos2 = otherObject.pos;
  const centerDist = Math.sqrt(
    Math.pow(pos1[0] - pos2[0], 2) + Math.pow(pos1[1] - pos2[1], 2)
  );
  const distance = (this.width / 2 + otherObject.width / 2);
  return (centerDist < distance + 5 && centerDist > distance - 5);
};

Layering Screens

An issue that I came across with using HTML5 Canvas was layering my Canvas element with the game's menu and victory screens. To solve this, I weaved a state attribute into my GameView constructor function, initializing state accordingly: this.state = "menu"; Each state is tied to different absolutely positioned z-index planes which allow for a more holistic gaming experience.

Upon clicking "Start Game" on the menu screen, this.state = "game"; which introduces the main Canvas element displaying all the Metapods and launching boulders. Once at least 3 Metapods have fainted, this.state = "victory"; which then transitions the game into the victory screen.

Future Patches

Some ideas that I would love to implement in time:

  • Allow users to select number of AI players with varying difficulties for additional flexibility
  • Additional objects being launched at the Metapods, such as berries which could provide healing
  • Single-player mode with high score rankings

If you have any feedback for patches or improvement, please feel free to share!