2017-05-18

JavaScript ES6 Game Loop Design Pattern

Get Started

This is just a short overview how to setup a very simple game loop with ES6 (JavaScript) using classes.

The following code sections are pretty easy to understand

Note that in many cases you need to use ES6's arrow operator => to make sure, you are accessing the correct this. Otherwise you will often get the error "this.method is not a function". That happens because when accessing this from anonymous methods, this points to the object of the anonymous method, not the object your calling it from.

In the HTML snippet, we set up a simple X3D scene with a ground and a small bar.

In the JavaScript main.js we create a game object. In Game.js the constructor sets up the game object and initializes the game loop to be triggered every 10 ms. We keep track of the pressed buttons (WASD) with booleans and move the bar accordingly.

This is what you will see, you can move the bar around with the WASD keys.



Have fun :)

PS: To develop this into a real game, have a look at the tutorial at MDN Developers, which is for 2D games with canvas, but much of it can be applied to our system as well: Tutorial

HTML Base Project


Here is the HTML frame:


<!doctype html>
<html>
  <!-- ......................................................................... HEAD -->
  <head>
    <title>LinuVerse Simple Game Loop Example</title>
    <meta charset="utf-8" />
    <script
      type='text/javascript'
      src='http://www.x3dom.org/download/x3dom.js'></script>
    <link
      rel='stylesheet'
      type='text/css'
      href='http://www.x3dom.org/download/x3dom.css'></link>
  </head>
  <!-- ......................................................................... BODY -->
  <body>
    <h1>LinuVerse Simple Game Loop Example</h1>
    <!-- ....................................................................... x3d -->
    <x3d width="800px" height="600px">
      <scene>
        <Viewpoint position="0,5,20" orientation="1,0,0,-.2"></Viewpoint>
        
        <!-- Scene ......................................................... -->
        <!-- Bar -->
        <transform id="bar" translation="0 -3 0">
          <shape>
            <appearance>
              <material diffuseColor=".9 .9 .9" />
            </appearance>
            <box size="5 1 1" />
          </shape>
        </transform>

        <!-- Scene ground -->
        <transform translation="0 -4 0">
          <shape>
            <appearance>
              <material diffuseColor=".8 .8 .8" />
            </appearance>
            <box size="20 1 20" />
          </shape>
        </transform>
      </scene>
    </x3d>

    <!-- ....................................................................... SCRIPTS -->
    <script type='text/javascript' src='Game.js'></script>
    <script type='text/javascript' src='main.js'></script>
    <script>
      main();
    </script>
  </body>
</html>

JavaScript Code


The Main JavaScript-File:
var game;

function main(args) {
  game = new Game();
}
And the Game Class:
'use strict'

class Game {

  constructor() {
    this.bar = document.getElementById('bar');
    this.barPos = [0,-3,0];

    this.upKeyPressed = false;
    this.downKeyPressed = false;
    this.leftKeyPressed = false;
    this.rightKeyPressed = false;

    document.addEventListener('keydown', event => this.onKeyDown(event));
    document.addEventListener('keyup', event => this.onKeyUp(event));

    setInterval(() => this.render(), 10);
  }

  /**
   * Main Render Cycle
   */
  render() {
    this.moveBar();
  }

  moveBar() {
    if(this.upKeyPressed){
      this.barPos[2] -= .1;
    }
    if(this.downKeyPressed){
      this.barPos[2] += .1;
    }
    if(this.leftKeyPressed){
      this.barPos[0] -= .1;
    }
    if(this.rightKeyPressed){
      this.barPos[0] += .1;
    }
    this.bar.setAttribute('translation', this.barPos);
  }

  onKeyDown(event) {
    switch(event.keyCode) {
      case 87: this.upKeyPressed = true; break;
      case 83: this.downKeyPressed = true; break;
      case 65: this.leftKeyPressed = true; break;
      default: this.rightKeyPressed = true; break;
    }
  }

  onKeyUp(event) {
    switch(event.keyCode) {
      case 87: this.upKeyPressed = false; break;
      case 83: this.downKeyPressed = false; break;
      case 65: this.leftKeyPressed = false; break;
      default: this.rightKeyPressed = false; break;
    }
  }
}

No comments:

Post a Comment