My Unnamed Game Engine
I've been working on creating a number of extensions and systems that I've found a need for to use with Gosu. It is all C++ since I don't really want to mess with wrapping most of it for Ruby (there are semi-equivalent Ruby solutions available), but in working on this I have certainly accrued quite a bit more experience with C++ and learned a nice set of tricks. The project can be found on Assembla where you will immediately be confronted with my unfinished stub documentation. Until recently, the code base has gone through several dramatic changes which made documenting anything a fairly needless task. However I will discuss a few of the major features here.
To start, I've built a simple game state system based on using a stack of states. The topmost state in the stack is sent the normal callbacks of update, render, and button events. In addition to these, there are also initialization, cleanup, pause and resume methods that are called on state transitions. These exist mainly for memory management (something I have not yet fully needed to flesh out). Just today, I added a pluggable factory implementation to aid the dynamic use of states. With this, it is now easy to create a new state that does not have to interfere with the core classes (saving compile times). It is also simple to dynamically create and push new states on at runtime, which eases my need for quick iteration through skipping titles and menus without recompiling (since I don't have hot asset loading yet). Information on this set up can be found on gamedev.net. The only problem I found with that particular example is that static member initialization order is undefined so in order to ensure that things work you must make your maker registry a pointer and create it in the registering function (this is detailed in the forum discussion).
Another large portion of the project are my graphics systems. Gosu itself already has a great interface to do 2D rendering, however I wanted to make a nice parallax rendering setup which required a few tweaks. In order to maintain a clean interface to rendering I needed to abstract the drawing code away from game objects. Otherwise each object would need to know how to translate world space coordinates into the screen, which can easily become hairy. I tried providing a translation function, but passing around a pointer to the translation module wasn't much nicer so I ended up pushing all rendering and sprite management into its own little unit. Within that unit, you can create sprites and spritesheets. Since the rendering itself is abstracted, each gameobject simply changes the state of the graphics objects to change how they are rendered within the manager. The sprite objects themselves are merely classes wrapping up the many parameters passed to Gosu's draw calls, listed here:
- position (world space)
- zoom factor
- rotation angle
- drawing layer
- visible flag
- scaling factors
- image center
- color modification
Spritesheets are a little more involved, since Gosu doesn't support them directly, but provides an interface to build sheets by returning a STL compliant container holding the Gosu::Image objects. This functionality is contained within my SpriteSheet class which adds support for cycle speed and all the same parameter functionality of Sprite. The parallax rendering is a full parallax implementation, meaning it supports the normal horizontal panning, but also vertical, zoom, and rotation. A demo of this can be viewed on YouTube.
Normally, text based configuration in games is done through XML. Personally I find XML to be bloated and goofy looking, despite its power and versatility. Instead, I chose JSON which I find much more readable even though it does not support schemas nor are there many nice libraries that take care of parsing, modification and serialization. The library I am using is TinyJSON, which seems to be disappearing from the Internet. The benefit of this sort of parser is that it is lightweight (aside from requiring Boost::Spirit) and fairly easy to use. It does not support serialization out of the box though it is easily implemented. Because of the complicated data structures used it is quite a pain to modify the data model (the structure does make it rather easy to use normally, just a pain to modify). However, both of these functionalities have been added within the project as well as a cleaner interface to obtain parsed data.
Using this, I have established a set of configuration files to direct the flow of the engine as well as tell it what assets to load and how to use them. This ranges from establishing key bindings to window size properties to level environment arrangements. At one point I added configuration support for menus, but for now I prefer to write custom menus in C++.
This addition is a popular sort of Gosu Extension, though at the time I started making it there weren't many available (I think everyone started one at the same time). Mine is fairly simple, you create a base object that represents your game window then add objects to that. There is a draggable window component that also supports adding components, but the hierarchy doesn't go much further than that. Alongside this scheme is functionality for what I call pages. A page here is a context for the UI containers that allows the user to use a single container for multiple interface configurations that can be switched between. This is not the most elaborate or feature rich UI system, but it suits me just fine.
The final addition I will talk about here is the inclusion of box2D physics. There aren't a great number of C++ 2D physics libraries around, but even if there were box2D is a fantastic one to choose. It doesn't have too many frills which makes it easy to get started using. Plus, it is actively developed on by a number of people who know game physics. At this point, my inclusion of it within the engine is pretty minimal. I have a few callback listeners set up to notify objects of collision events, but with the upcoming new version that API will change to simplify my implementation. For the most part I haven't had too much need to wrap any particular functionality or build any crazy contraptions. So I'm going to just let those things build up over time as I need specific things. I will probably be creating a particle emission system at some point that will make use of box2D, but for now I don't really need it.
Now, obviously there isn't much point in building all of this if I weren't creating some games. At this moment I'm working on two projects in my spare time. The first is a reincarnation of my "Circle Game" or Hamsterball Galaxy. The point of doing this is that originally I wanted to open up level creation to the users and add several graphical tweaks to the game. These additions were limited to my implementation however since I built my levels as static arrays (holy crap) and didn't spend much time working on the graphics code. This time around, using the engine should make these things much more feasible and hopefully allow me to take the project to a higher level where I'd be more comfortable with attaching a price to it.
The other game project is just now coming out of prototype phase and into a formal birth. Sometime last year I toyed around with doing Mario Galaxy style movement in 2D and found a nice starting point to accomplish it using box2D. With that, and more brainstorming I've come to believe that this style of movement would work amazing within a Metroid style run 'n gun - dungeon crawler game. There are still some tweaks that need to be done with movement to make it squeaky clean, but things are still looking promising.
This is but one side of my current status, next week-ish I will try to write a post about my graduate work.