mogate

Mogate is basic maze game developed for testing different approaches for entity system framework. The game part itself is based on MonoGame and CocosSharp frameworks and currently works under Windows, MacOS and iOS systems. CocosSharp framework is used only for IOS version because of it already contains fix for device rotation and binary plist format support. The project files are tested and developed in Xamarin Studio.

mogate_screen_01

Latest release can be downloaded from GitHub.

Entity framework

Everything in the game is an entity but the entity doesn’t use traditional objects oriented hierarchy. Instead of class inheritance programming model the enity can contain one or more behaviours, like:

  • Position – defines entity position in game world
  • Drawable – contains information required to render entity
  • Attackable – used to attack entity by others
  • Attack – entity uses the attack to take a damage to other attackable entities

The key point here is that behavior code doesn’t rely on fact that entity is monster or player. It just describes how specific aspect of entity behaves. For example our player contains next behavior:

Player.Register (new State (HeroState.Idle));
Player.Register (new Health (200));
Player.Register (new Attack (30));
Player.Register (new Attackable (OnAttacked));
Player.Register (new Position (mapGrid.StairDown.X, mapGrid.StairDown.Y));
Player.Register (new Execute ());
Player.Register (new Drawable (sprites.GetSprite ("hero"), "idle",
new Vector2(mapGrid.StairDown.X*32, mapGrid.StairDown.Y*32)));

But having only behaviors is noting without logic that enables it. This is a place where actions come to hands.

Actions

While behaviours are used to describe entity’s attributes an action is used to provide a logic on top of behaviours.

Since an entity contains only behaviours the action is also controlled by a behavior. It is called Execute.

This behavior contains queue of IAction objects and calls Execute function provided by IAction interface. Once Execute returns true the action is treated as completed and next one is dequeued for update.

Actions itself are divided into two groups:

  • Generic purpose actions
  • Gameplay actions

Generic actions

Generic purpose actions mostly designed to organize flow for other actions. For example:

  • Sequence – provide queue for set of actions
  • Spawn – allow to run one or more actions at the same time
  • Loop – run other action forever
  • Action – once run a function

Gameplay actions

Gameplay actions are focused on game aspects:

  • MoveSpriteTo – used to move sprite from Drawable behavior to new position
  • AnimSprite – enable animation
  • FollowSprite – link one sprite to another
  • AttackEntity – implement gameplay attack logic

Using gameplay actions outside of gameplay services allow to identify and isolate gameplay aspects and reuse it in the same way for different entities.

Example

For example we want to move entity to new position with animation:

var seq = new Sequence ();
var spawn = new Spawn ();
spawn.Add (new MoveSpriteTo (Player, new Vector2 (newPos.X * 32, newPos.Y * 32), 300));
spawn.Add (new AnimSprite (Player, "move", 300));
seq.Add (spawn);
seq.Add (new ActionEntity (Player, (_) => {
Player.Get ().MapPos = newPos;
}));
seq.Add (new ActionEntity (Player, OnEndMove));
Player.Get ().AddNew (seq, "movement");
Player.Get<State> ().EState = HeroState.Moving;

In example below we use Sequence to guarantee order of actions execution and Spawn to syncronize animation with sprite movement. Also we use ActionEntity to change map and state behaviours once visual part of movement is finished.

Statistics

Entity framework includes monitoring for behaviors to collect statistics data about their usage. The collected statistics as follows:

  • Total number of registered behaviors
  • Total number of fetched behaviors

Needless to say that there are two special behaviors on top of both lists. They are Sprite and Drawable. Both of them are registered for all visiual entities and fetched once per frame.

Regarding other behaviors the data the following.

registered_behaviors

As we can see the most registered behaviors are related to position, health and “is friend or foe” system.

fetched_behaviors

Most fetched behaviors are related to lighting, “is friend or foe” system and our special behavior Execute used for running actions where actually all gameplay is implemented.

As result most registered and used behavior is IFFSystem which is used by allmost all entites to detect if other entity is friend or foe.