Making a Game with JavaScript

robotspacefish

Jess

Posted on May 5, 2020

Making a Game with JavaScript

(Note: I'm moving my posts from my time at Flatiron School from my Github to this platform. This blog entry was first posted on March 18, 2020)

For my JavaScript/Rails Single Page Application (SPA) project I made a game called Invasion!, about my dog dreaming of battling squirrels in space. The game was made with JavaScript, HTML, and CSS and a backend Rails API to store and fetch player’s names and scores.

For the most part I utilized object orientated design. All of the game objects and sprites (images) are broken into classes. For example, the player, enemies, and bullets are all objects that inherit from GameObject. Each GameObject has update() and draw() methods. Anything pertaining to displaying sprites or text goes in draw, and anything that manipulates these things goes into update.

Example of game objects inheriting from a GameObject class:

class GameObject {
    static all = [];
    constructor() {
        GameObject.all.push(this);
    }

    update() {
        this.checkForCollision();
    }

    draw(ctx) {
        const { sourceX, sourceY, sourceWidth, sourceHeight, x, y, width, height, image } = this.spriteObj;
        ctx.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, x, y, width, height);
    }

    // other methods to check for and handle 
    // collisions, out of bounds, etc ...
}
Enter fullscreen mode Exit fullscreen mode
class Player extends GameObject {
    constructor() {
        super();
        // other properties initialized here
    }

    update() {
        super.update();

        if (this.collided) {
            ExplosionObject.createExplosion(this);
        }

        this.move();

        // etc...
    }

    // no need for a draw method since nothing changes from 
    // the GameObject class
}
Enter fullscreen mode Exit fullscreen mode

Upon initialization, each GameObject is stored in a static variable array called all. This way I was able to handle looping through updates and draws for every existing object at once.

class Game {
    // constructor, other methods, etc...

    update() {
        // spawn enemies...

        GameObject.all.forEach(obj => obj.update());

        if (this.player.isHit) this.gameOver();
    }

     draw() {
        this.ctx.clearRect(0, 0, GAME_WIDTH, GAME_HEIGHT);

        if (this.mode === "play") {
        GameObject.all.forEach(obj => obj.draw(this.ctx));
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Sprites were separated into their own classes, depending on whether they were animated or not. My regular sprite class, SpriteObject consisted simply of a constructor that took in the source location on the spritesheet and size for the sprite, the (x,y) location and sizes I wanted, and created a new Image(). The AnimatedSpriteObject, which inherits from SpriteObject, is a lot more complicated. Aside from the properties already mentioned, I needed to know how many rows, columns, and frames an animation had.

A sprite object does not inherit from GameObject because the thing the sprite is an image/animation of does. For example, if an enemy squirrel ship appears on screen, a new enemy() is created (which inherits from GameObject. When it is created a new SpriteObject() is created for the enemy and stored as this.spriteObj on the enemy instance.

class Enemy extends GameObject {
  constructor(spawnX, speed = 1) {
    super();
    this.spriteObj = new SpriteObject(Enemy.initObj(spawnX));
    this.speed = speed;
  }
}

 static initObj(spawnX) {
    return {
      sourceX: 0,
      sourceY: 176,
      sourceWidth: 218,
      sourceHeight: 169,
      x: spawnX,
      y: -170,
      width: 218 / 2,
      height: 169 / 2
    }
  }
Enter fullscreen mode Exit fullscreen mode

Oh, I should mention that I used requestAnimationFrame to handle the game looping. requestAnimationFrame updates the browser roughly 60 times a second. It works similarly to setInterval but performs better for game purposes.

In order to animate, I had to create a delay value and keep track of how many 'ticks' went by. Each 'tick' is a frame per second (fps). If I didn't use a delay then the images would pretty much loop at rapid speed and you would never accurately see the animation. I set my delay to 3; this way it would only update to the next image every 3fps. Then I reset the tickCount to 0 to start over for the next frame.

Animating the sprites turned out to be the most challenging part of this whole project. I spent a lot of time googling and watching YouTube videos before I could get it working properly. If you're interested in knowing more about game development using JavaScript I found this channel to be pretty helpful: PothOnProgramming.

If you'd like to check out Invasion! you can do so here: github

💖 💪 🙅 🚩
robotspacefish
Jess

Posted on May 5, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Making a Game with JavaScript
flatiron Making a Game with JavaScript

May 5, 2020