Wartbed:Architecture/MVC

From Dark Omen Wiki

Jump to: navigation, search

Model-View-Controller ("MVC") is a software design architectural principle (sometimes also considered a design pattern) that defines how system components and responsibilities are separated and intended to interact. The main principle is that system "logic" (rules or inner mechanics), user input (system-user interaction), and sensory representation (GUI, sounds, etc) are separated from each other. The purpose is to loosen couplings and promote modularity. The WARTBED system architecture follows this design architecture.

Contents

WARTBED's Model-View-Controller Design

Everything that can interact in a game world is a "game object" (or an "entity"). The WARTBED game objects exists in a virtual universe solely defined by its own logic and knows or cares nothing about their representation - they are pure Models. In principle, since all game logic takes place in the Model layer, a WARTBED game can run completely in the abstract without any graphical or auditory output at all. Every entity have one or more corresponding representations (views) that may read "their" entity but not change it. However, as is common in games software, the models CAN communicate with their views(s) by sending messages.

In the conventional interpretation of MVC, the model and views are completely separated and only communicate through a controller. Sometimes, for reasons of efficiency, the view can observe the model. Though this observer pattern design is frowned upon or rejected by purists, it is common in computer game programming.
+------------+     +------------+     +------------+
|            |     |            |     |            |
|            |     |            |     |            |
|   Model    |<=== | Controller | ===>|    View    |
|            |     |            |     |            |
|            |     |            |     |            |
+------------+     +------------+     +------------+
      ^                                      |
      +--------------------------------------+
WARTBED assumes a pragmatic stance and though using a strict division of responsibilities between models, views and controllers, also accepts that architectural fundamentalism is not in the best interest of game development. The WARTBED MVC structure allows view entities to observe (though not change) model entities, and models can signal events by broadcasting messages to observers subscribing to it. Models still know nothing about the functionality of any subscribers, who are responsible for processing and responding to messages.
    +-----------------------------------+
    |               Model               |
    +--------------+---------------+----+
                 ^ ! The model can ! ^
                 | ! send messages ! |
                 | !               ! | 
The controller   | !               ! | The View can
issues orders to | !               ! | read the Model
model entities   | V               V |
  +--------------+----+        +-----+------------+
  |   Controller      | -----> |      View        |
  +-------------------+        +------------------+
                    The controller can
                    direct the view
The controller module is essentially a game session. It ties together a set of participants (agents that wish to interact with the game world) with the models and views.
                                       Models

                                       +---+     
Players                             >  |   |-+   
                                   /   +---+ |-+     
    +---+             +---------+ /      +---+ |                 
    |   |-+   <-----  |         |          +---+ 
    +---+ |-+ ----->  | Session |         
      +---+ |         |         | \    +---+     
        +---+         +---------+  \   |   |-+   
                                    >  +---+ |-+ 
* Humans                                 +---+ | 
* AIs                                      +---+ 
* Observers            Controller
                                       Views

Model and View

As example, assume a space game, where the main Model will be the class "Ship".

//-------------------------------------------------------------------------
// Basic classes: f.i. in (made-up file) "MVC_base.h" 
//-------------------------------------------------------------------------
 
typedef shared_ptr<Message> MESSAGE;
typedef std::set<View *> VIEW_SET;
 
 
struct Model
{
    mutable VIEW_SET views;
 
    virtual ~Entity() {}
 
    void registerView( View *pView ) const
    {
        views.insert( pRep );
    }
};
 
 
struct View
{
    virtual void receiveMessage( MESSAGE &msg ) {} = 0;
 
    View( Model const &rEntity ) { init(rEntity); }
    virtual ~Representation() {}
 
    void init( Model const &rEntity )
    { 
        pEntity->registerView( this );
    }
};

The Model and View classes: Notice that the Model interface (abstract base class) doesn't know anything about the specifics of its views. Also notice that it is required of any View to register itself with its Model.


//-------------------------------------------------------------------------
// Example model class, f.i. in "Ship.h"
//-------------------------------------------------------------------------
 
#include "MVC_base.h"
 
struct Ship : Model
{
    VECTOR3 position;      // Example game 
    long    hull_points;  // object data
};

The Ship class: As can be seen, for a Model-layer class, in this instance "Ship", being an Model is fully non-intrusive. The effect is that it can now send messages to any registered representations.

//-------------------------------------------------------------------------
// Example view class, f.i. in "game_display.h"
//-------------------------------------------------------------------------
 
#incluide "Ship.h"
 
struct ShipView : View
{
    Ship const *pShip;
    OgreSceneNode *pNode;
 
    ShipView( Ship const *pShip ) : View(pShip), pShip(pShip) {}
    void receiveMessage( MESSAGE &msg ) {}
 
    void update() { pNode->setPosition( pShip->position ); }
};

A View of the Ship: A specialised view needs, however, to implement the receiveMessage() function, and must pass an Model to the superclass constructor. Also note that the ShipView stores a (const) pointer to its associated Ship object: Views can see and read its Model (but not alter it).

Example representations

View objects are similar to the Observer design pattern and hooks a model. Typical representations are

  • The graphical model (3D model, each individual unit)
  • An iconic representation (regimental banner, attached to formations rather than individuals)
  • Audio (a helicopter constantly playing Ride of the Valkyries)

Controller

In real-time tactics games, no units are directly controlled by the player. Instead, all game objects are interacted with through orders. Therefore, the task of the Controller layer is to read input (from players, network or AI) and dispatch orders. In the very simplest terms the Controller is an order-dispatcher that is aware of the Model layer, but cares nothing about the View aspects. (This is however a little to clean to be practical since GUI interfaces bridge the distinction View and Controller).

Personal tools
communication