Saturday, March 10, 2012

The Components and Systems of Morgan's Raid

I've written before about the entity system architecture of Morgan's Raid. I am just now polishing a paper on the topic which I will present at the FDG conference in May. I contacted Adam Martin to get his feedback on the paper, and he was very helpful. He made a few suggestions that I simply did not have space to address in the eight-page conference paper, but since Blogger has no page limit, I would like to address one of them here: what are the actual components and systems of Morgan's Raid?

By way of simple introduction, an entity system architecture is a software architecture in which game object data is stored in simple objects called "components" and these are processed by "systems." Game objects then are simply unique identifiers that aggregate components. This approach favors delegation over inheritance. It proves useful in game development due to the highly experimental nature of such systems: the domain model itself is subject to dramatic change during practically every stage of development. For further discussion, check out the entity systems project wiki.
Numbers of components and systems during development
The figure above shows the growth of the number of systems and components during the development of Morgan's Raid. This figure appears in the paper with a brief interpretation. I provided the small initial set to help bootstrap the students, but most of the rest were written by them—the 25 developers who worked in Fall 2010 and eight who worked in the Spring 2011. I am very proud of the team, don't confuse my pride in their achievement with any claims of elegance and beauty. Indeed, there are quite a few smells in our implementation.

Without further ado, tearing into the source code of Morgan's Raid, we can see how the systems and components are related. (It appears that Blogger automatically scales large images down. You can grab a full-size PDF here.)
System-Component Dependencies
The systems are on the left and components on the right, with edges showing system-component dependencies. As evidenced by the diagram, there are a few components which are heavily used throughout the implementation. OnScreenBoundingBox, for example, is used by anything that involves bounding boxes. (This was originally called Position, but that caused serious confusion when dealing with world vs. screen coordinates. After refactoring, we ended up with OnScreenBoundingBox and GPSPosition, the latter because world coordinates were actual GPS coordinates.) There are a few systems that have no out-edges because they use no components at all. For example, FadingSystem handles the fading of the screen based on time of day, but it does not deal with a component explicitly: it is passed a long integer that represents the current time of day and performs its computation from that.

Several of the components have no in-edges. A handful of them are, sadly, rotten code that was never removed. In fact, some are added to game objects and never accessed by anything else. Others of these disconnected nodes are used directly by the non-system game code. The Morgan's Raid implementation reifies the state design pattern, and there are many places where critical game logic was done directly within these classes rather than delegating to explicitly named and tested systems. This is not ideal, and I ascribe it to the novice level of many of the developers. Ask anyone on the team what they think about the 1700-line behemoth InGameState and they will cringe and tell you it should have been done better, but at the time, they did not know how to actually make it better.

In the diagram above, I have hidden the inter-system and inter-component dependencies for one very good reason. When they are shown, the diagram becomes a bit of a mess. Check it out (or full-size PDF here).
System-System, System-Component, and Component-Component Dependencies in Morgan's Raid

Ignoring for the moment the fact that you cannot discern the system-component dependencies, this diagram does show that the number of system-system and component-component dependencies is relatively low. However, if I were to throw InGameState into the mix, it would have its fingers in practically everything.

The diagrams were generated with dot, and you can download the graph file here. (Note that Google Docs thinks this is some kind of Microsoft file due to naive handling of file extensions. Just download the original and open in your favorite plain-text editor.) I created that file manually by inspecting the Morgan's Raid source code, and so it may contain minor errors.

For your reading convenience, here's a simple tabular view of the systems and components as well.


SystemsComponents
BackgroundTileSystem
CityNameSystem
DestinationSystem
FadingSystem
GPSToScreenSystem
HoverableSystem
ImageRenderingSystem
IntInterpolationSystem
MinimumSleepTimeSystem
MorganLocationSystem
NightRenderingSystem
OnClickMoveHereSystem
OnScreenBoundingBoxSystem
RaidSoundSystem
RailwaySystem
ReputationSystem
RevealingTextSystem
SpeedSystem
StepwisePositionInterpolationSystem
SunSystem
TimePassingSystem
TimeTriggeredSystem
TownArrivalSystem
TownArrowSystem
TownUnderSiegeSystem
AnimationRenderable
ArrivesAtTownIndex
BackgroundTile
BeenRaided
CentersOnGPS
CityData
CityImages
CityName
CityPopulation
CityTargets
CommandPoint
Destination
DoesCityHaveMilitia
DoesCityLoseGame
DoesCityWinGame
GPSPosition
GPSPositionList
HasMorganGPS
Hoverable
ImageRenderable
ImageRenderLayer
InGameTime
IntInterpolated
MinimumSleepTimeOverride
Morgan
MorganLocation
MovesOnClick
OnClickMoveHere
OnScreenBoundingBox
OnScreenBoundingBoxList
PositionInterpolated
Raidable
Raider
Railway
Reputation
ReputationValue
RevealingText
Road
RoadsToCity
RouteTaken
Speed
Sun
Terrain
TimeToRaid
TimeTriggeredEvent
TownAdjacency
TownArrow
TownUnderSeige