Friday, January 25, 2013

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



This is the second and final part of the series. If you missed the first part you should read it here.

Here I continue to define the phases I went through while re-writing my game library RaptorGL and the tools I added to ease the development and deploy/build your RaptorGL game.

Phase 5: Give some TLC to Sprite. Sprite was pretty dumb in previous implementation. It required the dev to add pretty much any feature to it besides drawing and moving. I realized that this not a very nice thing so Sprite can now rotate itself based on anchor points between 0-1, the default being 0.5 which is the center. It can also scale now too using the same anchor points used for rotating. I may separate them in future versions. Also the new Sprite.moveBy() and Sprite.moveTo() does not create a new object every time.  Instead it stores the values in a private variable of the Sprite object.

Phase 6: Throw away label and write new one. Label was well, not my proudest piece of code lol. So when it came to a re-write I just deleted the module all together, being very careful not even seeing a line of code in there. So the new label is a totally new implementation which I'm very happy with right now. I decided to stay away from inheritance hell, so I did not inherit from Sprite even though they share many common features. This turned out to be an awesome decision. Label has scale, rotate, align left, right, center, and of course it can move.

Phase 7: Simplify assets loading. Now each class handles the loading of the proper assets and notifies the object when the loading is done. This includes Textures, SpriteSheets, Sounds, and soon custom Fonts. When RaptorGL boots up it asks all these classes to start loading their resources. After they are done RaptorGL removes the loading screen and calls the game's main function.

Phase 8: Write a simple module loading system. This one was very fun to work on. Implementation is super simple and it also allows the RaptorGL build tool to combine all your modules into one JS file and even compress it for you. The way I got around adding all those extra functions, and with it all the extra function calls, was to introduce the includes.js file into the project. This file gets run before your main.js file and imports all the modules that are defined in there. Syntax is very simple: you write rgl.include('gam-module.js'); That's all, now your module files are not polluted with all the require and import statements and it also enforces you to think about your code layout. I'm planning on adding module folder support as well.

Phase 9: Development Server. I noticed right away the it can be a pain to run the game using the "file:///" url in the browser, especially when using webworkers. Also I want to test on my iPad and iPhone so I needed a lan IP for that. It helps debugging to see which resources are getting requested etc.. So I opened up my Python editor and with only about 70 lines of code (which includes comments) I got an awesome small dev server. It can accept 3 arguments for IP, Port, Directory.  Now one can fire it up from the command line and test your game from anywhere on your network.
I even found another cool use of the server. Since you can define any directory to be the root directory you can start the server with your home directory and others can read and download files from your computer. Pretty snazzy ;)

Phase 10: Build tools. Now if you've done any development you know that there is a difference between your dev and build versions. Since RaptorGL implements the module import in such a straight forward way it was a natural choice to provide a build tool to get rid of those rgl.include(); calls and just combine the files into the main.js file in the same order as the includes. So just like with the Server I opened up my Python editor and with 174 lines of code I wrote an awesome build tool. I say Awesome because it not just combines your JS files, it also creates a build directory in your project and copies all other assets and RaptorGL itself. But wait! There is "One More Thing..." :)
RaptorGL build tool also can compress your main game file using the Google Closure Compiler
It supports all three compressions: Whitespace, Simple, and Advance. It creates a new file with the .min extension so your packaged JS file will not be overwritten.

Phase 11: Sacrifice platform. This one was Hard.  I realized that many parts of the library were being updated, adjusted, and expanded just to support Mobile Browsers... But Why?! RaptorGL already has hosts for desktops, why not just create hosts for iOS, Android, and Windows 8 Phone as well? Since I'm much more familiar with iOS I decided to tackle it first. It only took me about 2 hours to get a host up and running. RaptorGL was running an average 50FPS with over 800 sprites. Thats perfect! I can live with that, since I know there is a lot of room for optimization. So I dropped the Mobile Browser support... for now. But since I already have the orientation support with dynamic viewport/scene/layer resize and full touch support including multi touch you can bet that "It Will Be Back" :) 

Conclusion: Well, there you have it. Looking at all that, now you can see writing a game library is not a walk in the park, but it's so worth it! Very challenging and rewarding at the same time.
Stay tuned to read all about the native hosts for RaptorGL, which even includes the same dev tools you are used to in Safari and Chrome.

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

2 comments:

  1. Congrats on this - looks huge amount of work but you must have learned a ton in the process!

    ReplyDelete
  2. Thank you Ray. Yes it was very educational. I look forward to getting feedback on it from you ;)

    ReplyDelete