Jump to content

Recent Comments

- - - - -

More on MonoGame/XNA Components

monogame xna components unity
4: Adsense

Have been slowly plugging away at my Combat Prototype for my game. I've kept a clean separation of the "Engine" and "Game", with each being in separate assemblies. The Engine code is the foundations - A Unity-like GameObject + component model that sits on top of MonoGame (or XNA). I'm not going to talk about the game part, but the continuation of the Engine core.


Lately, I've added in a Messaging system. This was primarily due to me needing to communicate between GameObjects. For component-component communication on the same object, I'm just referencing the components directly. I decided to go messaging for intra-object communication because I really didn't want to start tightly coupling other objects to each other. My messaging implementation is different to Unity's. I'll talk about that here.

When a component wants to hook a message, it must call "RegisterMessageHandler" on the GameObject it's attached to.

This has the following prototype:
void RegisterMessageHandler(string messageType, Action<IGameObject, IGameObjectMessage> handler);

As you can see, it takes a handler function as a parameter. The GameObject itself then listens to any messages hooked by the components and routes them to each component when received.

Each message must implement the interface IGameObjectMessage, which has a single required property - "MessageName". I'm tempted to remove this requirement entirely and make it more like how Components work - requiring the messages to be bound by the message Type. This would give me something such as:
void RegisterMessageHandler<TMessage>(Action<IGameObject, IGameObjectMessage>);
This feels more elegant. However, this may create an issue if the components are destroyed and don't unhook the messages first. I'm contemplating using C#'s event system and following a Weak Event Pattern. Thoughts are appreciated.

There's a few ways to send a message to other objects. I'll list them out:
  • SendMessage - Sends a message to a particular GameObject
  • BroadcastMessage - Sends a message to a GameObject and all its children
  • SendMessageUpwards - Sends the message to the GameObject's parent
  • BroadcastMessageUpwards - Sends the message to the GameObject's parent and it's ancestors.
One thing I'm debating with the Broadcast options is whether they should cascade all the way up and/or down the tree to children of children, etc.

I've also got a GameObjectGraph. Basically, a way of storing and accessing my "root" objects. I'm currently figuring out a nice way of exposing this to the world other than using a Singleton. It's likely to appear as a property on the GameObject in some way.

I need this because it acts as a sort of scene graph. It is the root object of the "world" and is called when I want to both Update() and Render() my scene. It also acts a place to fire global messages to notify all GameObjects in the world about something. At this level, I have:
  • BroadcastMessage - sends a message immediately to all objects, starting at the root and cascading downwards
  • QueueBroadcastMessage - drops a message onto a queue to be sent the next tick, before Update() is called
The message handlers themselves have the signature:
void SomeHandler(IGameObject sender, IGameObjectMessage message);
The first parameter is the GameObject which sent the message. The astute of you will realise that it's actually a Component which sends messages and not the GameObject. It's debatable whether the first parameter should reference the component instead of the GameObject, as this would open up component-component direct communications.


I've added a simple Tag collection to each object. These are text labels which can be searched on. A GameObject can have as many as needed. I currently use them for Linq queries over child objects:
foreach(var child in this.Children.Where( (o) => o.HasTag("sometag") )
   // do something with tagged object

I'm contemplating extending this system to become a Triple Tag, basically: namespace:predicate=value. This would make things nice and flexible, especially when combined with Linq queries. For example, if I had two sides in the game and I wanted to find all units of type "tank", I could write a Linq query such as:
foreach(var tank in this.Children.Where( (o) => o.HasTagNamespace("SideA") && o.HasTagPredicate("UnitType") && o.HasTagValue("Tank"))


That's about it for now. There's a few current niggles and areas I need to start looking into. These are:
  • Object creation via cloning (allows me to have Prefabs)
  • Object destruction (queue to kill next frame)
  • Object serialisation to JSON/BSON (allows me to save/load object definitions from files)
  • General object management and tracking.

The current systemis nice enough, I guess - it has quite a few rough edges and things I'm changing as I go on - I already plan on reusing this part of the system in other projects. I'm also contemplating open sourcing it on GitHub, I'm not sure though...

Apr 26 2013 07:24 PM

Note, combining the "HasTagX, Y and Z" method calls as you have shown doesn't do what you would want.  You don't want a "has SOMETHING with namespace X" and "SOMETHING with predicate Y" probably.  would want a tag row where all 3 are true for the same row.  So you need overloads that take multiple parameters, like "HasTagPredicate(namespace, predicate)" for a 2 parter and "HasTagValue(namespace, predicate, value)" for a 3 parter.


good luck.

Note: GameDev.net moderates comments.