Maybe I should ask if you’ve ever thought about how games work, perhaps even about building a game from scratch? If not, turn away now; I see lots of math in your future!
In my childhood, I was fascinated by Mario and other games like it. They were very simplistic and yet extremely fun to play. Mario is making a comeback with Super Mario Maker on Wii U which actually didn’t surprise me one bit.
After years of programming, I tried to make a few games of my own and I quickly realized that the methodologies, working environments, strategies, planning, testing, and ways of thinking were totally different.
I still wanted to learn… and using a framework wasn’t enough; I wanted to know enough to build one from the ground up. Pure foolishness right? I prefer to think about it as Witold Gombrowicz did:
Foolishness is a twin sister of wisdom.
There’s no code in this part (sorry); we need to get some things out of the way first…
So how does one start building a game? Here’s the thing, a game is not usually something one does without a team. You need a few things: a story/idea, a game genre, the game platform (web, desktop, mobile, console), a programmer and a designer at the very least. Currently the team consists of me, myself, and I …well see how that works out.
I wanted to make a mini-engine/framework/library/bundle that would enable me to build games. It needed to have some of the basic functionalities like:
- the game loop
- generic screen drawing and refreshing logic
- multiple screen containers (like you would see in a 2 player split-screen game)
- screen container clipping
- screen layering
- input event handling (from a keyboard and/or mouse)
- custom event dispatching
- asset loading (for in-game media files like sounds and sprite sheets)
- displaying and animating sprites (blitting a.k.a. bit blit)
- animation frame rate control
- path finding (this might be nice to have)
- a 2D physics engine (2D to keep things “simple” as it should have collision detection support and other features)
You might be thinking that’s a hefty list but the ideal engine should not be opinionated on the game types you can build; besides, the list is actually pretty small and I wanted to get out of my comfort zone a bit.
I wanted to write everything in ES6 so I prepared a babel-gulp-webpack-sassboilerplate. It works with the live reload extension to facilitate development so make sure you install it in your browser. Follow the instructions to get it running.
I’ll do all the coding in another GIT repository, to keep the boilerplate intact.
For rendering I decided I’m going to use the Canvas element. It’s not interactive (I’ll go into more details about this later) so it might add more coding challenges, which is perfect. It’s generally the preferred choice for web games so it fits the bill.
The approach will be simple, we’ll have a dual purpose code base:
- one part will be the engine and
- the other will be games using that engine.
Creating mini games with an immature engine will quickly let us know what it’s lacking and how to improve it.
Let’s start with the first thing:
The game loop
What is it? Why do we need it?
I consider the game loop as the heartbeat of a game. It keeps everything updated and rendered correctly. Everything drawn on the screen needs to work with a single game loop if we want deterministic behavior.
You don’t want to create a shooter game and have bullets pass through players without damage or have the players fall through the map because the player, bullet, and map updates were in different loops.
In older browsers, the setInterval() method was the way to go, as you could call it once every n milliseconds. Nowadays that’s a bad practice and only used as a fallback if requestAnimationFrame() is not available. The requestAnimationFrame() method will trigger ~60 fps. It’s an approximation because it will generally match the refresh rate; more here.
Class Diagram
I usually like to have a small class diagram before I start coding to at least highlight the main class containers. Something along these lines should suffice for now:
This diagram is incomplete and that’s perfectly fine, we just need something to get started, but first some explanations:
- at the core of everything we have an EventDispatcher which we can use to listen for and emit (trigger) events; this should probably be a singleton and it will act like a global publish and subscribe.
- the Keyboard will help us determine when keys are pressed and released. Now while it does extend EventDispatcher, we should not use its features to implement the Keyboard logic as we don’t want to propagate events back and forward, we simply want to have that option if we need it.
- the Canvas has only two jobs: to create and store a reference to the canvas tag and its context, to update its properties on screen resize. Everything will be drawn on a Canvas instance.
- the Scene extends the Canvas and you can think about it as a viewport/camera/screen. We can have multiple Scene instances for when we want to do things like split-screen. Its job will also include calling the update() and possibly render() methods of all elements within it.
- the DisplayObject is what holds any items that we want to render. Other classes will extend it and add more properties; for instance we might want to set things like isSolid, hasGravity, and others to be consumed by the physics engine.
- the Game class will hold the main game loop, all the scenes as well as some game play and pause functionalities.
- the AssetLoader is self-explanatory.
The structure might not be perfect but it’s good for our needs as any class directly or indirectly related to Canvas will be able to: dispatch events, listen for keyboard inputs, and draw to the screen which is nice.
You might be asking yourself if we really need the event dispatcher; I’m actually planning on using that later to facilitate unidirectional data flow.
Next, we’ll start working on all of these classes and maybe implement the basis of a mini-game to see some actual progress. Here’s part 2.
Radu B. Gaspar
This article was originally published here.