Technical implementation of a game engine
I don’t really regret building my own game engine given how much I learned from the experience. I do, however, feel that the quality of my game has suffered from not using a framework such as Phaser.js and if I ever [hopefully] make another game one day then I’ll be going with something like Unity instead. Why all the negativity, you ask? Let’s take a look at the implementation and see.
So here’s a class diagram of the the main bones of the game. I’ve excluded some modules as not to over-complicate the diagram but I’ll explain the additions in a later post.
It’s fairly self-explanitory, the Main module contained a MenuLoader responsible for drawing the menus (this wasn’t always the case but I’ll cover that in a later post). The MenuLoader was also was responsible for creating a Game. I’m not sure that was the best design decision, it’s implementation just had the least time impact a very late stage of development. Like I said, I’ll cover that later. My Game module consisted of an [initially, 1d] array of entities which made up the enemies (which were just obstacles that weren’t bound to 32px grid co-ordinates). The terrain data was just integers stored in a 2d array. The integers corresponded to an image’s position in a large tilesheet and the array slot corresponded to the tiles position in the game world, which was tracked by the Camera. This data was stored in the Map module, which is essentially a glorified var containing the JSON game config.
Both the terrain tiles and the entities had their own Sprites (in the case of terrain, a single Sprite), some of which had Animations and Boundries. The Boundry was just a simple box with a width, height and offset co-ordinates from the Sprite image. The Renderer was responsible for drawing the entities and tiles in the Game, the Updater was responsible for updating the Player co-ordinates (based on input from the Controller) and also for checking any boundry collisions via the CollisionDetector. If there was a collision then the Game state would be updated accordingly.
Right, so what’s that red box all about? This box is lined with the bleak tinge of remorse. These are my god modules that got way too big with too many responsibilities. They are very tightly coupled and more a reflection of my inexperience at the time. With more software design knowledge, proper tests and the ability to smell when the code needed refactoring then this problem could have been avoided. Changing parts of this code was time consuming, but I knew it well enough to handle it and I’m just glad I never had to show it to anyone in an interview. To quote BuildKite founder Keith Pitt, it’s not legacy code, it’s founder code. I wrote that when I founded the company!
Building a game engine from scratch is a really difficult problem. If you haven’t been in the industry for a long time then there’s going to a be a lot of things that you don’t account for; and unless you’re a AAA game development company, my advice right now is to avoid building your own game engine altogether and just focus on building a great game. There’s no shame in sparing yourself the hard work and using something that someone else has already built for you. Having said that, if you just want to learn the ins and outs of game development then doing this is a great exercise.
What about the LevelEditor, you say? Calm down, I’ll tell you about that next.