The code for Shootah is divided into three layers. There’s the game itself at the “top”, the code that actually renders the graphics, plays sound, etc at the bottom, and a layer of abstraction in the middle that glues the whole lot together.
There are a couple of reasons for choosing this architecture. One is that putting all the stuff that’s not unique to the game in its own library means that it can be easily reused in other games. When I start another project it will just be a matter of dropping it in, and calling some quite simple and self-explanatory interfaces in order to get the main game loop running and get stuff moving around the screen.
The second, and the reason for the “abstraction” layer in the middle, is that it makes Shootah easier to port to other platforms in the future. At the moment it renders all its graphics via LWJGL, but should I decide to try and get it running on – say – Android, where LWJGL isn’t available, I can simply re-write that layer according to the demands of that platform, conforming to the same interfaces described by the abstraction layer, and drop the main game on top with very little change.
This was all well and good until I started adding controller support. I was so in love with this design that I decided that keyboard and controllers would be handled the same way. I envisioned an abstract “Controller” object at the game level, that exposed controls such as “up” and “fire” which the game state would bind listeners to, in order to be notified when one of these virtual controls was pressed. This abstract controller would then call down to the implementation level to bind its own set of listeners to controls and keys exposed by the library.
This resulted in a horrible, horrible mess. Listeners listening to listeners? Bleugh. What was I thinking?
Oh, it was working all right, with the keyboard at least, but as I said in my post from the other week the sheer ugliness of it was sapping my will to keep going.
Finally I realized: hiding the controls under two levels of abstraction (the virtual controller that the game state listens to and the interfaces to “real” controllers exposed by the lower-level library) was completely unnecessary. Building Shootah with Java already means that it runs on Windows, OS X and Linux. If I’m to port it anywhere it’s most likely to be a handheld device where the controls will have to be totally revamped anyway. So I’ve stripped out everything keyboard or controller-related from the abstraction layer and I’m writing LWJGL-based controller code that’s entirely specific to Shootah. The “virtual” controller that the game listens to is still there, but instead of an extra level of goo between that and LWJGL, it’s responsible for polling real-world controls on its own.
It’s not quite as portable, but it smells a whole lot nicer and I’m actually enjoying working on it. Hopefully I’ll be out of this controller-related fog soon and will be able to get back to the game! Woo!