Today I received an e-mail from technorati which said that my blog claim process was now complete. That's nice except for the fact I claimed it a week ago. Looks like everything in Technorati is slow.

0 Hansel Script

This is one of the first (if not the first) script I wrote using GuayScript instead of MonoBehavior. It wasn't created for anything in particular, but it'll surely end up being part of some enemy's behavior.

It keeps track of its GameObject position, and will send a notification every time it's has traveled a certain distance. The interesting part about it it's that it shows how notifications can be edited by the level designer for maximum flexibility.

/// <summary>
/// Hansel script will drop a pebble (trigger an event) whenever a certain distance has been covered
/// </summary>
public class HanselScript : GuayScript
{
    /// <summary>
    /// Distance between pebbles
    /// </summary>
    public float DistBetweenPebbles;
 
    /// <summary>
    /// Event notified everytime the distance is covered
    /// </summary>
    public Notification DropPebbleEvent = "pebbleDropped";
 
    /// <summary>
    /// Ctor,
    /// </summary>
    public HanselScript()
    {
        var lastPosition = new Vector3();
        var accDistance = 0f;
 
        OnAwake  = _properties => lastPosition = GameObject.transform.position;
        
        OnUpdate = _deltaTime =>
        {
            accDistance += (GameObject.transform.position - lastPosition).magnitude;
 
            ifaccDistance >= DistBetweenPebbles )
            {
                accDistance -= DistBetweenPebbles;
                NotifyDropPebbleEvent );
            }
 
            lastPosition = GameObject.transform.position;
        };
    }
}

0 The Message System

Messaging is at the core of any component-based system. Rather than directly calling other component's methods, you send messages to a postal address instead. If there happens to be a component listening to these messages from that address, it will receive them.

All this functionality is offered by the PostOffice class. This class works at a very low level. It doesn't know about the Guay Framework or Unity. It just knows about addresses and message ids.

To listen to a specific message, you provide an address, a message identifier and a message callback. The callback will be called whenever someone sends that message to that address.
public void Subscribe( object _address, string _message, MessageCallback _callback )
{
    ....
}

Likewise, to send a message you call the following method specifying an address, a message id and a list of parameters:
public void Send( object _address, string _message, params object[] _params )
{
    ...
}

You can also can broadcast a message through the method:
public void Broadcast( string _message, params object[] _params )
{
    ...
}

Let's see an example:
public class Player
{
    public Player()
    {
        ExampleApp.PostOffice.Subscribe( 
            "gameAddress",
            "gameStart",
            ( _event_params ) =>
            {
                Debug.WriteLine"The game has started!!" );
            } );
    }
}
 
public class Game
{
    public void Start()
    {
        ExampleApp.PostOffice.Send"gameAddress""gameStart" );
    }
}
 
public class ExampleApp
{
    private static PostOffice mPostOffice;
    
    /// <summary>
    /// Retrieves the post office
    /// </summary>
    public static PostOffice PostOffice
    {
        get { return mPostOffice ?? (mPostOffice = new PostOfficefalse )); }
    }
 
    public ExampleApp()
    {
        // a game is created
        var game = new Game();
        
        // player is created. it will subscribe to the "gameStart" message
        var player = new Player();
        
        // the game starts, sending the "gameStart" message to the address "gameAddress",
        // the message will be queued.
        game.Start();
    }
 
    public void Update()
    {
        // once per frame, the post office is updated, delivering all queued messages.
        // Player will get the "gameStart" message
        PostOffice.Update();
    }
}

This example shows what working with the typical message system looks like. However, this class is not directly exposed to the game code. Instead, the Guay Framework makes use of the PostOffice class internally, presenting a Unity-friendly interface which makes messaging really easy to use from scripts. You can find more information about this in the description of the GuayScript script.


0 The Guay Framework explained

I'm preparing a series of articles about each of the important aspects of the Guay Framework, namely:
  • The messaging system.
  • The GuayScript.
  • Sending/receiving messages.
  • Dynamic Properties.
These form the core of the framework. I think they cover most of the aspects you'd expect to find in a component-based system. Keep in mind that it's still a work in progress, so some things could eventually change from one day to the next (though it's not likely). I'll try to maintain articles as concise as I can since my intention is not to bore people explaining every class or method (unless I'm asked otherwise), but to explain the rationale behind. I'll include code snippets where I feel it's needed.


0 A quick glance at GuayScript

GuayScript is the of the central piecea of the Guay Framework. Its main goal is to provide your scripts a clean and very intuitive API to interface with a real component-based environment. The example below shows how simple is to communicate with the system. There's no need of looking for specific components, thus avoiding the creation of ugly dependencies.

I'll explain it all in detail in future posts.

Example of a typical GuayScript script
    //
    // Health script. Makes a GameObject to have 'life'
    // 'Implements' the HealthInterface interface
    //
    public class Health : GuayScript
    {
        GameObject OtherGameObject;
        public float MaxCapacity;
        public float Amount;

        public Health()
        {
            var dead = false;
            var currentHealth = Amount;

            OnAwake = _properties =>
            {
                Messages[ HealthInterface.CmdIncrease ] = ( _id, _args ) => currentHealth += _args.Get();
                Messages[ HealthInterface.CmdDecrease ] = ( _id, _args ) => currentHealth -= _args.Get();
                Messages[ HealthInterface.CmdRefill   ] = ( _id, _args ) => currentHealth = MaxCapacity;
                Messages[ HealthInterface.CmdDie      ] = ( _id, _args ) => currentHealth = 0;
            };

            OnUpdate = _deltaTime =>
            {
                if( dead )
                    return;

                if( currentHealth <= 0 )
                {
                    dead = true;

                    // components say interesting things through the Notify function 
                    Notify( HealthInterface.EvDead );

                    // components can also say interesting things to other objects
                    OtherGameObject.Send( HealthInterface.EvDead );
                }
            };

        }
    }


0 Unity and The Component-Based Model

When I began fiddling with Unity I found that everything looked pretty familiar to me. Almost every game we've done in the past at my company has used an in-house component-based model. You don't get this model right away, specially if you've been writing games in a more traditional way. Getting it right requires a good understanding of some of the most important pillars of OOP:  AbstractionStrong cohesion and Loose Coupling to name a few. If you aren't familiar with these concepts I strongly recommend you to have a look at them.

To make the most out of a component-based approach, there's a few things to keep in mind:

You want each component to dedicate to a single and simple task. You want each component to just operate on a single problem domain. You want them to be as independent and self-sufficient as possible, and at the same time you want to design them in a way that lets you place them together seamlessly to work for a higher cause. The benefits of designing components like this are pretty obvious. They can be added, removed, changed or tweaked without causing much trouble to other components around them, if at all.

However, there's still an important aspect about them: Some of them talk. Some of them listen. Some say things about interesting events happening to them and some listen to these events and do interesting things in turn; or they simply ask other components to do something for them. What does this mean? If they communicate, they must use some kind of channel to do so. In 99% of the examples on the internet, this channel is a specific method call made to a specific component, found by any of the GetComponent() family of methods. This means that the caller has to know about the recipient's components. This means that a programmer has to know what components a level designer has put within the GameObject, thus creating not only a dependency in source code, but an inter-departmental dependency! Well, this is pure evil and actually defeats the whole purpose of the component-based model itself. There's a reason you design your classes using abstraction and encapsulation. Why wouldn't you do the same with your components?

So, how do we communicate to other components then? Through messaging. Messaging provides us a decoupled channel for communication. The responsibility of the sender is just to send a message through the proper channel. Sender does not need to know about the recipient's identity. Likewise, the responsibility of the recipient is to subscribe to the messages it wants to handle, without knowing about the sender identity.

Unity's Monobehavior does, in fact, support a half baked way to communicate to other components through messaging, but it's not to be trusted. It uses reflection which means it's incredibly slow. Yes, it's incredibly slow. If you go the messaging way, you'd be using messages for everything. Don't buy the "Ok, it's slow but it's meant to be used just here and there" argument. There's also strange methods like "SendMessageUpwards" which basically invites you to create a dependency within the lovingly-crafted-by-a-level-designer object hierarchy.

I honestly think Unity 3D has no real support for messaging, and out of the box, it's certainly near to impossible to take advantage of the many cool features that real component-based systems offer. That's why I decided to write this lightweight framework called "The Guay Framework".

I'll write more about this in future posts.

0 It won't happen to me!

I was googling about the percentage of newly created blogs that are abandoned. It looks like most of them don't get past their first month, which is really sad.

0 Man at work

As I said, maintaining a blog is definitely hard work. But the hardest part is setting it up. Still writing things I feel are needed in order for this blog to make sense. Tempted to press the 'Publish' button a couple times!