GameLoop 0.02 – Restructuring the code into JavaScript classes

December 9th, 2019 9:00 am |  by David.Reid  |  Posted in GameLoop development log

In my last article, I walked through the code for my first iteration of a JavaScript 2D game engine. That first iteration lives here. The game engine – GameLoop – is based on the code used to develop JavaScript Pong and JavaScript Breakout.

Since writing the aforementioned article, I’ve developed a JavaScript clone of Asteroids using the first iteration of GameLoop. And whilst that worked, it clearly demonstrated that GameLoop has a long way to go before we can consider the code a useful addition to future JavaScript game projects.

I’ve published a new pre-release of GameLoop which basically is a restructuring of the code we’ve developed to this point. The logic behind restructuring is to make the code cleaner and move us a step closer to modulation.  What follows is an overview of  the changes we’ve made.

Removed Index.js and replaced it with the GameLoop class

The Index.js file contained the core code that made our engine tick. I’ve replaced that file with a new GameLoop.js file which we will discuss later in the article. As part of that change, all our core engine code is now packaged in a game class which is instantiated in the index.html file as shown below.

window.onload = function() {
    window.game = new Game( { /* config data goes here */ } );
    window.game.Start();
}

The new game class accepts a configuration object that allows the developer to pass game specific requirements such as resources, keys and game functions. This new configuration approach has made the Register.js file redundant.

Removed Register class and replaced it with a config object

As mentioned above, the game class now accepts a configuration object containing all the game specific options, resources and keys. The current list of options are listed in the GameLoop ReadMe file. Below is an example of a configuration object.

let config = {
    Fullscreen: true,
    Resources: [
        { id: "player", var: playerPic = document.createElement('img'), file: 'player.png'},
    ],
    MoveEverything: CustomMoveEverythingFunction,
    DrawEverything: CustomDrawEverythingFunction,
    GameReady: CustomGameReadyFunction,
    GameEnded: CustomGameEndedFunction,
}

Now that we have a configuration object that is passed to our game, the register file is redundant and thus has been removed from our game engine.

As you can see from the above code, the configuration object also accepts functions for DrawEverything, MoveEverything, GameReady and GameEnded which replaces the need for the old game class which used to contain these game specific methods.

Removed the Game class

In the first iteration of GameLoop our game class was an blank slate containing methods that the code in our old Index.js file would use to run game specific code. In short, the game class separated the specific game code from our generic game loop code.

However, the introduction of a config object that accepts functions that contain game specific code has made the old game class redundant and thus it has been removed.

Converted Graphics.js to a Graphics class

I’ve also taken the code in the Graphics.js file and wrapped it up in a Graphics class. The graphics class is stored in the default config settings and is accessible using the following statement.

window.game.settings.Fx;

In addition to creating the class, I’ve added a couple of new functions for drawing images in the game. Below is a full list of the functions available in the Graphics class.

settings.Fx.SetContext(context)

settings.Fx.ColorRect(topLeftX,topLeftY, boxWidth,boxHeight, fillColor)

settings.Fx.ColorCircle(centerX,centerY, radius, fillColor)

settings.Fx.PrintText(text, xPos, yPos, size, font, color)

settings.Fx.DrawBitmapCenteredWithRotation(useBitmap, atX, atY, withAng)

settings.Fx.DrawImage(image, x, y)

settings.Fx.DrawBitmapCenteredWithRotation(useBitmap, atX, atY, withAng)

settings.Fx.DrawImage(image, x, y)

Obviously, future iterations of GameLoop will contain more functions but for now, the listed functions have served us well, in Pong, Breakout and Asteroids.

The new main GameLoop class

As mentioned above, we took all the functions from the Graphics.js file and wrapped it in a Graphics class. Well, we’ve basically done the same with the Index.js file. We’ve taken all our code from the Index.js file and wrapped it in a new main GameLoop class. The major difference is that we have replaced the Register with a configuration object which we discussed earlier.

The new class operates the same as it did before. It initialises the game window, initialises the game keys and then loads the game resources before finally triggering the game loop.

As a refresher, here are the methods available in the new main GameLoop class.

InitWindow();
LaunchIfReady();
BeginLoadingImage(imgVar, fileName, directory);
BeginLoadingAudio(audioVar, fileName, directory);
LoadResources();

Start(); // Initialises, load resources and invokes Run().

Run(); // Runs the game loop.

// State methods
SetGameToReady();
SetGameToRunning(pressed);
SetGameToQuit(pressed);
SetGameToPaused(pressed);

// Game Key functions
InitKeys();
KeyDown(event);
KeyUp(event);
KeySet(event, setTo);

// Utility methods
ResizeCanvas();
GetSettings();
GetKey(id);
GetKeys();
GetResource(id);
GetResources();
GetCanvas();
GetContext();
PrintSettings();

Finally, before we move on, this class will change as we use GameLoop to create new games. But for now, this is the guts of what makes GameLoop tick.

And that is pretty much the changes that have been made in this iteration of GameLoop. But there is one thing I want to talk about before we close out this development log article.

We’ve taken a step closer to Modulation

In the previous and current iteration of GameLoop, JavaScript code is accessed via the landing page – index.html – as shown below.

<script src="Graphics.js"></script>
<script src='GameLoop.js'></script>

At this particular juncture in the GameLoop development process, the above code is perfectly adequate. However,  as the project progresses, there could be dozens of JavaScript files and thus adding them as script elements in the index file will be both laborious and prone to accidental omissions.

With this in mind, we need to move towards modulation. In the last article, I suggested that I wanted to focus on game logic rather than architectural logic. However, since building Asteroids, its become clear that whilst modulation is necessary now, delaying the transition may lead to major headaches in the future. Thus it makes sense to consider modulation now.

Restructuring GameLoop into JavaScript classes in this iteration takes us a step closer to modulation which I’ll probably address next.

And that is pretty much it for this development log.

Happy coding my fellow programmers.