In the game I’m currently working on, it appears that I’m slowly drifting towards a design that’s a close resemblance of the Model-View-Controller (MVC) pattern, despite originally rejecting the idea because I believed it would require my game world to expose too much of its internal data just so the view could keep track of things.
Because I originally believed to be building a very simple game with very simple logic, I chose a design that would create a nice, non-fractured interface to the world so I would have an easier time building the AI and player controls on top of it:
In this design, everything could access everything else – a monolithic world component where the public interface was well encapsulated, but that allowed the implementation to take the most direct path possible.
"Everything could access everything else" doesn’t mean my
objects directly modified each other’s state, but it meant, for example, that
a building had a reference to the island it was placed on and that it could
call an internal method in the Island
class to inform it when
the building was destroyed or moved.
A full design, in contrast, would give the buildings an interface through which they determined properties about the ground (is it too rough? underwater?) and some events so its owner would know when the building was destroyed.
If I had only taken game logic into account, this all would have worked out very well. But there were some things that added a lot of complexity…
Lessons Learned: Complexity
Back when I created above design, XNA had just reached its 1.0 release.
One still had to cope with lost devices (that means at any random point,
all your graphics resources like VertexBuffers
or Texture2Ds
would go bang and you had to dispose and recreate them, something
that was later hidden from the programmer with XNA
2.0’s virtualized GraphicsDevice), so I did the only sane thing
I could do and built a layer for the visuals which would hide that little
inconvenience from the game logic (you can see it at the bottom of my UML
diagram, the Asset
class).
The flaw that made it all come down was that the game logic objects
owned the Asset
s. And because I wanted to be able
to unit test my game logic without graphics resources, I designed my
Building
, Unit
, etc. classes to make
the Asset
optional.
Asset
s were created through the AssetManager
.
But how would a Unit
or Building
obtain a reference
to the AssetManager
? Simple, I thought: the World
owns an AssetManager
. As soon as a Unit
or
Building
is added to the World
, it would set up
its Asset
s.
Can you smell the problem already? Let’s see what logic each building has to incorporate now, just to function properly within the system I set up:
-
A building can be constructed and added to an island that is part of
a world with an
AssetManager
. -
A building can be constructed and added to an island that is part of
a world with no
AssetManager
-
A building can be constructed and added to an island that does not
belong to a world. The island can then be added to a world with
an
AssetManager
-
A building can be constructed and added to an island that does not
belong to a world. The island can then be added to a world without
an
AssetManager
Now duplicate these 4 cases for when the AssetManager
is
added to the world after the islands and buildings have been created.
And get everything to works right in reverse: the building could be
removed from the island again, the island could be removed from the world
and the world could loose its AssetManager
(in order to
avoid imposing a destruction order on the game’s shutdown process)
The result is that each game logic object in the nice tree I built needs to be informed of any ownership changes to its parent, its parent’s parent and so on. And that’s what finally kicked this design out of the door for me.
MVC to the Rescue
To get rid of this complexity, I am currently removing all graphics code
from my game logic classes and writing external Renderer
classes that contain the graphics code.
The game objects will have to provide additional detail, for example,
I’m not sure yet how I handle turrets: they will need to expose their
orientation, elevation and either hand over the bullets they’re spewing
into the air to another manager or (if I decide to make bullets
instantaneous hits/misses) provide at least a list of vectors of
the bullets that were fired in the last Update()
cycle
so the renderer can draw the appropriate streaks.
As it turns out, this more an more resembles the MVC pattern:
I was a bit skeptical as to whether MVC makes any sense as a tool in game programming (for example, see my reply on Doolwind’s blog post "Model View Controller (MVC) Game Engine"), but now I believe that it’s generally a good idea to design the game logic without mixing any graphics code into it. I would select a radically different design for a game with a larger scale, but even then, keeping the graphics code separate from the game logic code seems to be a good idea.
All my problems are nails and MVC is my hammer!
That’s of course not what I’m proclaiming here, but if this turns out well, MVC will probably my preferred architecture for future games :)