Class Architecture of Llams and Egral
This article is a little documentation to introduce to the current (March 28th, 2011) architecture of Llams and Egral.
Main Concept
Core architecture
The very core of the architecture is based on a classical Model View Controller pattern :
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
The only difference is that here, the "controller" is not the classical human user, but the XNA Game class that control the whole thing
The class
Game executes the two main game loops : one to
Update the logic, and one to
Draw the actual scene as seen by the player. For this drawing,
GameGraphics needs to get the infos from the
GameLogic (for example, the position of the characters, etc... to know where to draw them)
This scheme, even if it's very simple, is the most important one. Note that in fact,
GameGraphics and
GameLogic are namespaces and not class. The actual classes involved here are
GameGraphics.Main and
GameLogic.Main, but I will keep this simplification for more clarity. (with the code, no confusion is possible, since the class
GameGraphics doesn't exist)
2D & 3D Together
From the architecture point of view, maybe the most specific feature of this game is to have a fully 2D logic (ie gameplay), but a 3D rendering. Therefore, the
GameLogic uses only internal 2D data, and the
GameGraphics 3D data, which are construct both with internal 3D contents and the 2D informations from the logic. This is emphasize by the following dependancies with the XNA Framework
Player Interactivity
When the Game call its
Update loop method, before updating the logic, it first check for input event, ie has the player done something with his
GamePad? For this, it invoke the handleInput method of the
InputHandler class, which will check for new input. The
InputHandler will then interpret these input, and delegate the corresponding action to the corresponding classes. For instance :
- if the player press the Jump button, it will call the GameLogic.Main.JumpPlayerRequest() method (which will decide if yes or no, the player can jump, and perform the jump if necessary)
- if the player press a button changing an option of the display (for instance, not display textures for better performances), it will call the corresponding method in the GameGraphics namespace.
Physics Engine
Physics pipeline
The logic has to control the position of objects/characters, depending on player actions. To move the objects, it relies on the
GamePhysics namespace.
For instance, when the player wants to jump, the
GameLogic decides which character should jump, and if it's possible (game paused, other constraints, etc...). If it's ok, it asks the
GamePhysics to actually perform the jump (class that doesn't care about the logic, and will do mechanically all the technical details to perform a jump)
Then, when an
Update of the Game, the
GameLogic can check the new positions from the
GamePhysics, to be up-to-date, and decides what should happen depending on this new positions. Then, when a new
Draw of the Game, the
GameGraphics will, as usually, get the infos from the
GameLogic, which now reflects the changements computed by the
GamePhysics.
Because we don't have the time, in the scope of this course, to implement a complete 2D rigid-body motion and collision engine, we rely on
Box2D, yet simple but efficient.
Thus, the
GamePhysics consists in an interface to abstract the
Box2D physical engine from the
GameLogic part. Indeed, the Logic doesn't care about the details on how to use the
Box2D library. He just wants to tell to someone "Llams have to jump!", and rely on someone else : the
GamePhysics. This latter knows about
Box2D, will instanciate the appropriate
Box2D world and objects, and apply the appropriate forces to perform the tasks asked by the Logic. (This way, if we change to another Physics engine, we only have to modify the implementation of
GamePhysics, but not at all
GameLogic)
The
Box2D objects have a pointer back to the logic objects. This way, when they receive physical significant informations (as collisions), they can inform the
GameLogic of this event. (note that this is the only cycle in the architecture graph dependancies. It is possible to break it, but at the price of loss of performance, clarity and implementing-time. For these reasons it has been kept)
Summary
Finally, the whole game architecture (without entering inside the namespaces) is the following: