The development has reached this point:
Now we want to add a Level class. A level object reads in data from a level file, and acts as a driver for all the non-graphics aspects of the game.
Which way round should the dependencies go? Should Entity
depend on Level
, or vice versa? It seems natural to make the
Level
class into a controller, telling the entities when to
act:
On the other hand, entity classes are presumably custom classes defined for a
specific game, whereas the Level
class could usefully be part of
the framework. A framework class should not depend on a custom class, so maybe
we should rethink.
The approach taken here is to define a Cell
class as a base
class for custom entity classes, to have it be a framework class, and to allow
the Level
class to control cells:
Besides looking after the grid, one of the things a level object needs to do
is to keep track of global variables such as a score. But to keep the
Level
class general, it should be the entities which change the
global variables, according to their game-specific details. A generic class
State
can be separated off from the Level
class to
handle state variables.
Similarly, a level object needs to keep track of a queue of entities, to
control what order they act in. And again, to keep Level
general,
it should be entities which queue themselves up. A generic Queue
class can be separated out. That leads us to a picture like this:
Two aspects of the wanderer game are a little unusual. First, instead of an entity such as an arrow moving autonomously, it moves by triggering the space in front of it. This allows entities to act as stationary booby traps, only starting to move when the player or another entity moves nearby. The other unusual aspect is that the original program used recursion to deal with the way in which one event triggers another.
For example, if you move near two objects, say an arrow and a boulder, and set them going, the entire flight of the arrow and everything it triggers, happens before the boulder moves. In other words, the program is doing a depth-first search for things to do. It is more normal to keep a queue of things to do, and to use it to give a more concurrent, breadth-first physics.
The reconstruction uses a double ended queue, and allows entities to be added at either end. By adding entities at the start instead of the end, the original game is reproduced as accurately as possible.
There is one more thing a level needs to be able to do. That is to create
entities of different types, according to the data from a level file. Entities
may also need to spawn other entities. The creation of new entities is
something that can only be carried out when full knowledge of all the custom
entity classes is known. So a custom factory object of some kind will need to
be passed to the level, and an interface or base class will need to be provided
for it, accessible both by the level object and entities. Let's give the name
Hatchery
for such a factory interface and add it to the
diagram:
This is a reasonable design for the model. The way custom classes are intended to be designed is something like this:
There may be many specific entity classes, all inheriting from the
Entity
class. Each entity interacts with other entities, but only
knows that they have class Entity
, nothing more specific, to avoid
dependencies between the classes. A Program
class knows about all
the various entity classes, and can provide a factory for them.