Or how to refactor the code from your last game to build up your reusable libs.
First and foremost, thanks to the people at FGL chat that brainstormed a jolly good topic to write about. This post also helps me to rethink my strategy about an issue I have with our core libs that I’ll hopfully address in the future as soon as I make sense.
Basic question is how do I handle the code I used in the previous game to reuse it… I’ll give several examples of how our core classes appeared or changed hoping that you find something useful for your own code and games.
In the beggining there was music
When we wrote Tech Wars, I had to write a music manager that would know when to change tracks. There are three tracks in Tech Wars, all with the same beats per minute, two share the melody but with different instruments and one has a slight variation of the melody. Each track served a part of the game, such has menus, level, and post-level.
Our current music manager has code from Tech Wars. That code evolved from a game specific class to a generic sound manager class and then to two separate classes: sound manager and music manager. These shifts occured as the next games needed or between projects.
What started with Tech Wars is now what we call the core, which is simply a bunch of abstract, cross-project oriented organization of directories and classes that goes from one project to another. It is not something you do, it is something you keep doing, building and evolving. That sound manager class was a bad case of refactoring, but a good start since we had no reusable AS code.
To create your libs you should make each class abstract from the game code. This maybe trickier than it sounds. For instance, we have a Scene Manager. What it does is quite simple:
1. ensures that one and only one scene is running
2. ensures that one and only one dialog is running
3. ensures that when a scene is started the current scene and current dialog are closed
4. ensures that when a dialog is started the current dialog is closed
And this has to work in every game. To be sure that it works in every game I made sure that a scene or a dialog is always a movie clip that is linked in the fla library and that I can pass up to five arguments to it. I also made sure that the Scene Manager is a singleton.
Get yourself organized
To be sure that your code is generic, organize it! Create a structure outside your game logic, as an example, when I start a project I copy the core directory from the previous project to the root of the current project and I create a separate directory “game” where all the game specific classes go.
It’s that simple.
Refactoring plays a big role in all of this. Now that the core classes are a few and that most of the nasty work is done, the process of refactoring tunes it and adds to it.
Again… an example. Some hours ago I was using a static method MathKit.AngleBetweenPoints(p1, p2) which is pretty obvious, but for some reason the code did not produce the results I predicted, so I wrote a bit of code to ensure the output I was looking for.
The issue was that MathKit.AngleBetweenPoints(p1,p2) returns an angle in radians and I wanted degrees. I already have two static methods in the MathKit class to convert radians in degrees and vice-versa, so in the next refactoring session I’ll rename MathKit.AngleBetweenPoints to MathKit.RadiansBetweenPoints and create a new DegreesBetweenPoints.
The refactoring will eliminate generic code from game specific code, it will reuse static methods we already have in the MathKit class, make the method already there more intuitive and create an additional method for other uses.
Managers = Singletons
Managers are classes that take care of a specific aspect of your game. Scenes, music, sound and so on. You should be sure that your managers are singletons and that you can access them everywhere. To be sure of it, all our managers are loaded by the Application Manager which is what all our document classes extend. Neat trick and quite useful.
Tools = Static
All our tools are static methods. We don’t want our tools to be instantiated. We don’t want our tools to hold data. We want our tools to do something specific and produce an output.
At the end of the day
Like I said, when we start a new game I copy the core directory of the latest game to the new one. Usually I take a look a t it or look for //TODO remarks for something I want to review. While the code base was growing this was very useful, right now it’s a matter of tunning some details since most work is done while refactoring.
I do have a damn project to go though… writing the graphic handling classes… but I still have a load of doubts to sort first.
Oooops… big one… Vlad out!