In what follows, I will describe my design for the model portion of VASSAL 4.
In a model-view architecture, the model holds data, while views provide displays of that data. (There’s also the controller, which handles input and notifies the model of changes, but for present purposes, you can think of that as part of any view which responds to user input.)
Anything which is relevant for the game state—i.e., anything which you would need to record in order to set up the game again after tearing it down—is a datum which should be represented in the model. Game data are essentially bundles of properties: Pieces have names, locations, angles, sides which are up, and possibly ownership, visibility, etc. Maps are similar. There might also be some global properties which aren’t attached to physical objects, which one might say are properties of the Game, e.g., which player’s turn it is. Call things like pieces, maps, and the game as a whole “game objects”.
Capabilities we need in the model:
-
getting/setting properties on game objects: Without these, we can interact with the model.
-
the ability to add/remove property change listeners to objects: When data changes in the model, we want to be able to react to those changes.
There are at least two kinds of thing I’m envisioning as being change listeners: Views, and Scripts.
Views need to be notified when properties change, as views are responsible for displaying those changes in some way. The GUI is a view for each game object that it will be displaying. If a piece’s location changes, the GUI needs to be told that so it can update itself.
Scripts are something new, but are in some ways similar to triggers in V3. Suppose that we have a control marker, which, when flipped over, should cause another marker on a victory point track to be moved. This could be accomplished by having a change listener on the control marker’s “visible face” property which then modifies the location of the marker on the victory point track.
A property change listener might be something which we’d like to have fire just before or just after a property is changed—hence, property change listeners can be pre- or post-change listeners. It might also prove useful to have a way of “freezing” game objects so that their properties can be changed without triggering any of their property change listeners, or to defer all listener notifications until after a particular listener has finished, in order to prevent loops or cascades.
In V3, a trait can cause an entry to show up in a piece’s context menu, or make some hotkey active for that piece. I’d like to generalize this to what I’m calling Action objects. An Action is an object consisting of:
- a hierarchical key
- a keycode (opt)
- a short text (opt)
- a description text (opt)
- a script
Game objects can have Actions attached to them. The hierarchical key, the keycode, the short text, and description text are intended to have a particular interpretation in the standard GUI view, namely:
- the hierarchical key is a branch in a context menu
- the keycode specifies a hotkey for triggering the action
- the short text is for the text in a context menu
- the description text is for something like a tooltip or status bar
The script attached to an Action is what lets an Action have effect. For example, a piece which can be rotated by a hotkey would have an Action with the appropriately set keycode and a script which adjusts the Piece’s angle.
The model needs to provide a way of retrieving game objects by property. For example, if I want a list of all of the Pieces which are on a particular Map, I should be able to retrieve this. This capability is needed in modules which have automation which applies to groups of pieces. E.g., the module for The Longest Day has a button which flips all fired artillery back to its unfired side.
(Implementation note: We do this in V3 by iterating over all pieces to find the ones which meet the given criteria, which is embarrassingly inefficient. We could instead do this in (amortized) constant time by keeping an index after the first query, and using change listeners to maintain that index thereafter.)
There isn’t much more to the model than this. The model is for storing data and managing the relationships among game objects.
Comments?