This is the documentation for the underlying framework that powers The Legend of Mazzeroth.
LoM's underlying framework (tentatively titled NAS2D)
There's a 'Game' object that is instantiated in 'src .cpp'. When it's created it initializes several service utility classes. These are the Filesystem, Configuration, Renderer, Mixer, Event (input and message) System, Gui, Lua Environment (incomplete) and StateManager.
Assuming all of that went smoothly, the Game::go() function is called which starts the main game loop. It also enters into the first 'State' called SplashScreenState. Eventually there will be a few changes so that the 'client' (user of the code) can specify an initial State through either the Game::go() function or from another function like Game::setInitialState(State* state) (I'm leaning toward the setInitialState() route). But for now it starts in SplashScreenState (code can be found in 'src/Game/').
The framework runs as a hybrid event-driven application (hybrid in that it doesn't wait for events but responds to them). The Event System (implemented as an Observer Pattern loosely modeled on Qt's signals/slots implementation) handles all events that the game might encounter including all input events (keyboard/mouse/joystick), window manager events (gained focus, lost focus, minimized, maximized, etc.) and any low-level system events (namely quit requests). These events are 'pushed' through the Gui if it has focus and then to the current State if the Gui isn't in focus.
Any object that wants to receive events must inheirt from a Listener object. This requires that the object implement the push(Event* event) function. All GUI Controls (known as widgets for anybody familiar with Apple/Linux lingo) inherit from Listener as do all State objects.
As the whole system is implemented as a hybrid event-driven system, even if there are no events in the event queue the program will continue to run by calling the update() function of all objects that are in memory (states, GUI Controls, etc.). This is handled automatically and should not be called explicitly by the programmer.
The Finite State Machine Model is a commonly used model to control logical states in games. They can be implemented in many different ways and in the frameworks case the states are used to organize game logic into distinct units. In the initial code for the framework, SplashScreenState is an example of a Finite State which handles a 'splash screen' of sorts. It draws a background image on the screen, draws some text and adds some Windows to the GUI (the windows are built-in UI types.)
To that end, all game states should be implemented as an object that derives from State (defined in src/Utility/StateManager.h). Derived states are generally stored in the src/Game/ folder to make it easy to find them.
When a State object is derived, it needs to implement the following four virtual functions:
The initialize() function is used to initialize any member variables that the state declares (such as Image, Font, Sound, Music, etc.). initialize() can be though of as the Constructor for a state. States should not use a Constructor or Destructor to initialize/free member variables as the services such as the Renderer, Mixer, GUI, etc. are not yet initialized until the State is added to a StateManager.
The update() function is called every frame by the state manager. This is the function where game logic should be implemented. It must return a pointer to a State object. Generally the 'this' pointer is returned. A new State can be returned (e.g., return new GameState()) or NULL can be returned. Returning NULL will cause the game to shut down and quit.
The push(Event* event) function is the function where event's are passed through. This is where responses to input events should be handled. SplashScreenState responds to several event messages and can be used as a simple example.
The Filesystem in LoM is implemented virtually. This means that we define where the program will look for its files, where it's allowed to write files and how the filesystem appears to the program. It also lets us pack all the files up into ZIP archives and load them dynamically that way -- it's all transparent to the user and to the program.
The service is started by the Game object as a Singleton. Whenever Filesystem services are needed one should request a reference to it using the Singleton object: Singleton<Filesystem>::get()
NOTE: The Filesystem expects file paths to use the forward slash '/' character instead of the backslash '\' character that's used in Windows. This is to keep things portable.
All art assets like sound, music, images, fonts and animated sprites are called Resources. They are all derived from a Resource object.
All resources can be initialized as a copy of another resource:
1.7.1