Giter Site home page Giter Site logo

mario_js's Introduction

Mario JS

PRs Welcome

Super Mario Bros Level 1-1 recreated in JavaScript

Mario runs through each level trying to reach the castle on the other side to save the princess. Each level contains various enemies, coins to collect, and mushrooms to power-up Mario. Mario's primary form of attack is jumping on top of enemies but touching enemies from the sides results in loss of a life.

gameplay gif

Controls

Action Key Input
Move Left 'A' / Left-Arrow
Move Right 'D' / Right-Arrow
Jump 'W' / Spacebar / Up-Arrow

Technologies Used

Mario JS was build using the following technologies:

  • Vanilla JavaScript used for overall game structure and logic.

  • Minified version of jQuery used to detect user input.

  • A HTML5 Canvas used for rendering of the current game state and all game entities.

  • Webpack used to bundle and serve up the various scripts in the correct order.

Screenshot One

Technical Details

Game viewport updates to follow Mario based of his current x-position on the canvas. Render will only draw entities currently in the viewport, preventing unnessesary usage of resources and memory.

// game.js
static updateView(data) {
  const viewport = data.viewport;
  const margin = viewport.width / 6;
  const center = {
    x: data.entities.mario.xPos + (data.entities.mario.width * 0.5),
    y: data.entities.mario.yPos + (data.entities.mario.height * 0.5),
  };

  if (center.x < viewport.vX + (margin * 2)) {
    viewport.vX = Math.max(center.x - margin, 0);
  } else if (center.x > (viewport.vX + viewport.width) - (margin * 2)) {
    viewport.vX = Math.min((center.x + margin) - viewport.width, 3400 - viewport.width);
  }
}

// render.js
drawEntity(entity, data) {
  if (((entity.xPos + entity.width >= data.viewport.vX &&
        entity.xPos + entity.width <= data.viewport.vX + data.viewport.width)) &&
      ((entity.yPos + entity.height >= data.viewport.vY &&
        entity.yPos + entity.height <= data.viewport.vY + data.viewport.height))) {
      // draw entity to screen
    }
  }

Entities are animated by looping through and drawing a series sprites similar to a flipbook. SpriteAnimations object holds groups of sprites corresponding to each state an entity could be in such as walking, jumping, squashed, or dying. An entity's currentState is updated depending on changes to x and y velocity as well as collisions with other entities in the game.

// coin.js
this.spriteAnimations = {
  spin: {
    frames: [
      new Sprite(spriteSheet, 5, 5, 10, 14),
      new Sprite(spriteSheet, 21, 5, 10, 14),
      new Sprite(spriteSheet, 37, 5, 10, 14),
      new Sprite(spriteSheet, 53, 5, 10, 14),
    ],
    currentFrame: 0,
  }

this.states = {
  spinning: {
    animation(data) {
      if (data.animationFrame % 13 === 0) {
        self.sprite =
          self.spriteAnimations.spin.frames[self.spriteAnimations.spin.currentFrame];
        self.spriteAnimations.spin.currentFrame += 1;

        if (self.spriteAnimations.spin.currentFrame > 3) {
          self.spriteAnimations.spin.currentFrame = 0;
        }
      }
    },
  },

MapBuilder was designed with the goal of allowing easy addition of levels after the completion of the project. Data for each level is stored in an object containing all the locations of scenery entities and enemy spawn points.

When the main Game class is initialized it creates and instance of MapBuilder loading in the current level. MapBuilder then creates the appropriate scene and enemy entities for the current level and begins rendering them to the canvas.

// game.js
mapBuilder: new MapBuilder(levelOne, tileset, spriteSheet),

// mapBuilder.js
level.ground.forEach((ground) => {
  this.sceneryEntities.push(
    new Scenery.Ground(this.tileset, ground[0], ground[1], ground[2], ground[3]),
  );
});

level.pipes.forEach((pipe) => {
  this.sceneryEntities.push(
    new Scenery.Pipe(this.tileset, pipe[0], pipe[1], pipe[2], pipe[3]),
  );
});

renderMap(data) {
  this.sceneryEntities.forEach((scene) => {
    this.drawEntity(scene, data);
  });

  this.brickEntities.forEach((brick) => {
    this.drawEntity(brick, data);
  });

Screenshot Two

Bonus features

There are many additional feature that could be added in the future. Some anticipated updates are:

  • Add the ability to grab flower power-ups and shoot fireballs at enemies.
  • Underground portion of level.
  • Multiple levels and additional enemy types.

mario_js's People

Contributors

tylerreichle avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.