Thursday, January 24, 2013

Building a Game Library: steps, design decisions, sacrifices. Part 1

Re-writing RaptorGL was a real eye opening experience. Even though everything went great at the beginning, somewhere in the back of my mind I knew it was too good to be true. Boy was I right.
But thats the end of the post so lets start at the beginning.

After playing around with WebGL back in late 2012 and reading this awesome book I knew that if I could use WebGL as a drawing backend to RaptorGL it would be a huge performance boost. I actually have been following one of the author's blog about WebGL @Tojiro. His demos are amazing. It's inspiring to see how far we can push the current state of WebGL. So I went ahead and wrote a very simple "click to destroy" style game which btw will be my January game for OneGameAMonth :))
Once it was working I realized that I needed a mouse position converter from World coordinates to Window coordinates. It was much simpler than I thought so now I could properly detect where the mouse was down.

Next came the Layer class... it was a total failure. But a good one! It showed me that the current implementation of RaptorGL using the Canvas didn't have a nice concise API that I could follow. Also, if the user's browser does not support WebGL I need to fall back to canvas.

There came the idea of a re-write with a properly defined internal API so I can hook WebGL in when it's available, and have the engine auto switch the TouchMgr and Layer classes to use the proper implementation... be it Canvas or WebGL.

But before I can run I need to learn to walk. 
It was time to seriously commit to RaptorGL and bring it up from "Pet Project" to "Project". This also meant that I had to downgrade my current obsession with MOAI and my TrexGL library to "Pet Project" but it is a sacrifice well worth making as you'll find out in an other post. Hint: RaptorGL now has it's very own native host so it runs as a standalone game without a browser for Win, Mac, Linux :))

With all that in place I embarked on the journey to re-write the Canvas implementation of RaptorGL, keeping in mind the implementation has to be able to work with WebGL... my main goal.

I structured the re-write into phases. So far there are 11, described below. I'm sure there will be more as I continue to use it for my games and share it with beta testers.

Phase 1: Remove 3rd party library dependency. Write everything in pure javascript. This was the best decision ever. Removing jQuery alone brought the size down by almost 100KB. Then came the really overused and over-recommended RequireJS library. Running my simple prototype was a breath of fresh air. Now I had full power and control over every aspect of the code. Love it!

Phase 2: Clean up the classes, class implementation. I used @Jeresig implementation of JavaScript inheritance. This design helps keep the overhead low and at the same time allows proper inheritance while still keeping the code simple. What I like most about this implementation is that it allows calling the super/parent classes method when you overwrite it in your own implementation. This will help devs create their own version of Sprite, Layer etc.. but still have the option to call the super/parent method from within their method.

Phase 3: Combine mouse and touch controls. Since I already had this done in TrexGL it was a matter of converting my Lua implementation to JavaScript... yeah right! See the game runs in the browser so everything in there is laid out using the DOM. So guess what, there are a lot of browser differences I needed to take into consideration, oh and did I tell you about resizing the browser window changes all the off sets? I decided to use a callback system instead of keeping the positions in globally accessible variables. I got the inspiration from Futile an awesome unity 2D framework written by @MattRix. If I ever decide to do 2D this is the tool I'll use. Although it works great now I can actually foresee adding the global variable option as well. Maybe my prototypes are just too simple and the overhead of a loop and function call bothers me. Time will tell.

Phase 4: Fix Scene and Layer implementation. These two were arguing all the time in the previous implementations. Scene was trying to be like Layer and Layer was trying to be like Scene. So it was time to put an end to this. Now Scene behaves nice and manages the drawing and updating of the Layers. Scene is also the main entry point in RaptorGL to start a game and RaptorGL uses it to dispatch draw and update calls. Layers can care less now about their surroundings and obey the Scene. Layer also holds all the Sprites and Labels. Layer can ask the Scene to call it every frame to update with the deltatime.

Thats all for the first post. Stay tuned for the second/final post of this series where you can read the other 6 Phases, two of which are tools to ease development and deploy/build your RaptorGL game.
Next post comes out this Saturday,

Part 2 available here, read on to learn about the tools and the other 6 Phases. :)

If you have any questions leave a comment or ping me on twitter @LZAntal