BASeBlock was one of my first projects that I wrote in C#. I wrote a program that sort of worked like HijackThis and a INI file reader class- which I Discussed 5 years ago (That long? Amazing), But BASeBlock was my first attempt at creating a project using a language that wasn’t horribly lobotomized. (I refer to Visual Basic 6).
I’ve found myself avoiding it somewhat for quite a long time. It is using code that I have since extracted, repurposed, and improved (such as my update library) for other projects. Another problem is that there are some glaring architecture issues in it’s design (when isn’t there) which were because I was unfamiliar with certain design patterns. For example, my game state management is a switch in the drawing and game tick routines on a game state enumeration, whereas a better design is to use a gamestate interface of some sort and have your different game states compartmentalized better.
However I’ve more recently come to rather like one aspect of BASeBlock. I designed it. I wrote it. While I imagine there are some helper classes and such which I may have acquired elsewhere, the bulk of the implementation is me. There is an aspect of that that I find particularly tantalizing, especially compared to my work. Don’t get me wrong I do love what I do and I have a lot of input in engineering decisions that affect my work, but like any software it is designed to a certain requirement, and with a certain timeline, and a lot of that simply isn’t mutable.
This brought my personal projects into new light for me somewhat when I think of it this way. For some time I’ve only thought of them in the back of my mind as a burden- after working 10 hours dealing with invoice printing considerations, I’ll remember my personal projects and feel bad that they have fallen so far by the wayside they’re stuck in the radiator. But I also forget that, unlike my work- my personal projects have no external director. I can add, change, remove, refactor, and redesign anything I want, and I have to answer to nobody- I’m “in charge” of what they become and how they get there.
Which that in mind I’ve taken it upon myself to actually start progress on making BASeBlock more palatable for me to actually work on. The GameState oddity is like an unsightly mole or other minor annoyance- you don’t notice until you have it pointed out to you (or in my case, until I learned of the pattern, and used it successfully in my poorly named Prehender and BCDodger). It is a major change/refactoring that I wasn’t really keen on doing even when I was working on the game almost daily and had a fairly good understanding of it’s architecture and design, so trying it now is perhaps putting too much faith in not only my abilities but also in my abilities when I was writing it, but if I want to improve it, I need to eliminate that unsightly implementation or I’ll just avoid it until I do.
What is this “GameState” implementation?
In my haste, I did rather forget to explain the particulars of what I was talking about when I talk about “Game States”. Game states are basically what state a game is in and are rather commonplace. A Game will have a different “state” for being paused, showing a menu, showing an introduction sequence, etc. an “Enumeration-based” approach like the one I described might implement things like so (halfpsuedocode)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class Game { public enum GameState { Game_Running, Game_Paused } private GameState CurrentState; public void Tick() { switch(CurrentState) case GameState.Running: //play the game break; case GameState.Paused: //Do pause screen stuff, maybe animate the letters or whatever. } } public void Draw() { DrawBackground(); switch(CurrentState) case GameState.Running: //Draw Game Objects break; case GameState.Paused: //draw a pause logo. } } } |
The basic architecture is to have a switch or similar style of conditional processing within any of the routines which will act differently based on the games current state. This does the task and works as intended, but it tends to lead to long rambly routines, and then all your different states get mixed up in one function. The interface-based approach creates an interface and then each State will be a class that implements that interface. This can be implemented in a number of ways, but the effect is to separate the information and implementation required for each state to a separate class. This allows you to add new features to a state without affecting the “namespace” of other states or interfering with it’s variables, which is sort of the entire point of having separate scope abilities to begin with. It also allows some interesting Chaining abilities. If the Running State stores all the information about game objects, for example, and knows how to draw or tick those objects, a “Slow Motion” state could simply delegate to a provided standard State but only call the tick once for every two calls; a Pause screen could not call the Tick function of a provided composite class, and instead call the draw method and then render a 25% shaded box atop it, or apply a color transformation to wash out the result, or a pause logo of some sort on top to provide the “Pause” effect. An “introductionImage” type state may have a single purpose- you give it an image and a GameState, and it will fade the image in, wait a few seconds, fade it out, and then set the current state to the provided state. Games often show various startup logos, and this can be used to easily fade in and fade out through numerous images and then go to the main menu (presumably a Menu state), and so on and so forth. This can all be implemented, of course, with the enumeration method but it requires a lot of plumbing which also tends to get in the way of everyday development and iterative design.
Have something to say about this post? Comment!