Project Description

Clockwise.Base is a library that introduces component based entity (CBE) systems into C#. Although the origin of this pattern is game programing, Clockwise.Base is universally applicable in any kind of program making use of modular objects.

The following is meant as an introduction to the most important concepts in the library, not a complete documentation.

Introduction

So, what are these components now and why should I use them? If you are already familiar with component based entities and able to answer this question yourself, you can skip right ahead to the next chapter. Otherwise, here is some brief introduction on the concept. Please refer to the external links section for more extensive explanations.

Every kind of simulation, may it be a game, physics simulation, visualizer for function graphs or even GUI systems tends to have some kind of main object with some consistent basic functionality. Then again, there are lots of variations that add and modify functionality of this base object.

Inheritance based class hierarchy

OOP provides us with a preferred way to deal with this - we are taught to build a class hierarchy. The root of our class tree is our main object, like a GameObject in a game or Widget in GUI systems. Our sub-objects implementation form branches and leaves below the root, as shown in this sample:

DeepHierarchy.png

As this hierarchy grows deeper, problems begin to arise. Say that our Player, NPC and Missile objects should be integrated into the physics engine, so we will derive them from a base class PhysicsBody. But what if we want a static mesh that does not interact with physics? A trigger that is also visible? A tree that is usally static because of performance reasons, but becomes animated at some point?

It becomes obvious that the inheritance based design is very bad in dealing with this kind of problem. You will find yourself refactoring the class tree regularily and making architectural flaws by copy-pasting around code or creating blob-objects that are neither maintainable nor reusable at all.

Aggregation of components

Okay, we got it that class trees are bad here, but how do we solve the dilemma?

We do it by breaking down all of the required functionality into (mostly) individual Components. A TransformComponent contains the 3D position, scale and rotation of a GameObject, the MeshComponent contains the mesh and material, a TimeTriggerComponent performs something every 5 seconds. A GameObject is then nothing more than an aggregation (= collection) of the components that sum up the specific functionality of this object. So the second thing we need is a container for our components, typically called an Entity. Some trivial implementation would be:
    public class Entity
    {
        public Entity()
        {
            Components = new List<Component>();
        }

        public void Add( Component c )
        {
            Components.Add(c);
        }

        public void Remove( Component c )
        {
            Components.Remove(c);
        }

        private List<Component> Components;
    }

    public class Component
    {
        public Component( Entity parent )
        {
            Parent = parent;
        }

        public Entity Parent
        {
            get;
            private set;
        }
    }
So you want a trigger that is also a mesh? Just combine a StaticMeshComponent with a TriggerComponent . You want a tree that is normally static and becomes animated? Just replace the StaticMeshComponent with an AnimatedMeshComponent . You don't want your Player class to have 50000 lines of code? Break it up into 20 simple components. Another cool thing about this idea is that you can - with some programming skill - make your components fully reusable in other applications. Although a 3D game seems to differ completely from a 2D game, the player character in a 2D game also has 1800 of 2000 hitpoints that are shown in some HealthBar class, which means you can fully reuse your HitpointComponent without making a single change to it!

Practical problems

While component based entity systems always sound great in theory, I found there was no implementation that deals with the practial problems that come up when using the pattern in practice.
  • Components are not as independent as we'd like them to be.
At some point, you will need to set the "Matrix" property of your Transform component or react the PerformLayout - event of your UI system's LayoutComponent . Few CBE systems deal with this problem at all and even fewer deal with it well - thus contributing to the bullet point below:
  • Coding comfort decreases.
Although the overall structure is greatly improved, just writing
    myObject.X = 123;
is still a lot more comfortable than something along the lines of:
    myObject.GetComponent(typeof(XComponent)).GetProperty("X") = 123;
Also, our beloved Intellisense and other IDE bells and whistles are not intended to be used with dynamically aggregated objects and therefore tend to malfunction.
  • Dependency problems:
Imagine some typical method like:
    // Inside Component
    void Update( float dt )
    {
        // ...
    }

    // Inside Entity
    void Update( float dt )
    {
        foreach ( Component c in Components )
        {
            c.Update(dt);
         }
    }
As long as the order in which components are updated is irrelevant, this does not yield any problems... but with the more more often case of the update order being completely fixed at compile time, you will need to make sure that the order of your Components list keeps up with that too. You've done that? Ok? Now try adding a similar "Render()" method that requires a different order of execution...
  • Performance:

Especially when working with systems that try to couple components lightly, there are often remarkable performance hits when calling methods between components.

You should be at least sceptical about components right now, but here is the relief - Clockwise.Base takes all of the pros from components (and even more) while tackling basically all of the cons noted above! Let's see how this is done.

The Clockwise.Base implementation

This chapter shall explain the design choices made when designing the Clockwise.Base library.

Composition

Experience shows that you will add or remove components from entities at runtime just occasionally. Most of the time you will find yourself wanting to predefine a composition of components and stick with it.

Therefore, our implementation concentrates on this use case. You first define a composition of Components as a so called EntityPreset , which is basically an list of System.Type objects with the entity's name tag on it. The entity preset somewhat equals the class declaration when speaking in OOP terms. Take the following UI sample:
    // This is the list of components we want to use
    Type[] components = new Type[] { typeof(BoxComponent), typeof(ColoredComponent), typeof(RectangularShapedComponent) };

    // Make a preset called "BoxWidget" that is a rectangular, colored box.
    EntityPreset myPreset = new EntityPreset( "BoxWidget", components );
Looks good? Fine you're happy. In case you miss a good old fashioned class declaration in a seperate C# file, we will cover this later. Anyways, now that we have a declaration, we can build an entity type. That's right, we actually build a .NET type derived from Entity with Reflection.Emit :
    // Make a preset called "BoxWidget" that is a rectangular, colored box.
    EntityPreset myPreset = new EntityPreset( "BoxWidget", components );

    // Build the type
    Type t = myPreset.BuildType();

    // Construct objects
    Entity myEntityA = Entity.Create(t);
    Entity myEntityB = Entity.Create(t);

    // Use the object
    // ...
Or shorter:
    // Make a preset called "BoxWidget" that is a rectangular, colored box.
    EntityPreset myPreset = new EntityPreset( "BoxWidget", components );

    // Construct the objects
    Entity myEntityA = myPreset.Instanciate();
    Entity myEntityB = myPreset.Instanciate();

    // Use the objects
    // ...
But why do we go through so much effort by building a whole new dynamic type if we can just add the components in an array list, like shown before? First, this opens up a whole new range of possibilities. The underlying EntityGenerator class does the whole job of adding together the components, resolving references, establishing and sorting event routes, modifying the entity preset with proxies and other features that are described later. These make the usage of the engine really comfortable, but require quite some processing time. In order to comply with the real time nature of simulations, we prefer to shift the performance overhead into the initialization phase rather than putting extra code in the actual Entity.

Second, to further improve performance, you can also save the dynamically generated assembly to a file and add it as a simple DLL reference in the final product, reducing the runtime overhead introduced by this library to virtually nothing.

Inter-component references

You can find quite a lot of articles on the internet that recommend the use of a CBE system over the traditional approach. You will find the introduction of breaking down functionality (also given in the first chapter here) over and over again, but one essential part is almost always left out: When it comes to dependencies between components (i.e. one component must call some method of another component), there's typically one of these three recommendations:
  1. Just don't do them.
  2. Go and implement some event system similar to the one in the Windows API, with event ids and everything. Then notice that it is frickin' slow. Then start to screw up the whole architecture by directly storing references to components in components and setting them manually.
  3. Okay, components are actually shit. Go for FRP.

While the above might be a little exaggerated, the core point should be clear: There seems to be no common agreement on how to deal with interactions between components.

Not caring about this would have been a no-go in the design of this library. In the end, this even became its biggest strength, and it is hereby encouraged to make components rely on each other since inter-component references in Clockwise.Base are:
  • Simple to establish
  • Simple to use
  • Fast
  • Consistent
  • Versatile

So how are they done? We can distinguish between three basic types of references:

Strong references

Usage of a strong or required reference is appropriate when you cannot use one component without another. This occurs when breaking down bigger classes into small components or when replacing inheritance with component references (you should not mix inheritance with components, described in Rules & Patterns).

For example, a component GridDebugComponent that shows the gridlines of a GridComponent is just useless without the latter. You can then declare a strong reference by adding a public field with the target reference as the field type and marking it with the [Required] attribute:
    // This is the component we want to reference
    public class GridComponent : Component
    {
        // Implementation details here ...

        public float[] ColumnSizes;
        public float[] RowSizes;

        public SizeF Size;
    }

    // This is the component that references the other one.
    public class GridDebugComponent : Component
    {

        // Implementation details here

        public void ShowGridlines()
        {
            float current = 0;
            foreach (float f in Grid.ColumnSizes)
            {
                PointF start = new PointF(current,0);
                PointF end = new PointF(current, Grid.Size.Height);
                MyGraphicsInterface.DrawLine(start, end);
                current += f;
            }

            current = 0;
            foreach (float f in Grid.RowSizes)
            {
                PointF start = new PointF(0, current);
                PointF end = new PointF(Grid.Size.Width, current);
                MyGraphicsInterface.DrawLine(start, end);
                current += f;
            }
        }

        [Required("To debug the grid, it must be referenced.")]
        public GridComponent Grid = null;
    }
Even though this snippet is reduced so much it is not even working, you should clearly see the use of the reference. You can use it just like any other field and be sure that it is set for you by some magical resolver class when building the entity. If you try to build an entity type that contains unresolved strong references, an Exception gets thrown.

The [Required] attribute has one optional string parameter that describes what this reference is used for. You can see it when programmatically retrieving the references in the DependencyTree class, but more on that later.

Weak references

Weak references are similar to strong references, just that they do not result in an error when staying unresolved. We'll start with an extension of the code snippet above:
    public class PositionableComponent2D : Component
    {
        // Implementation details here ...

        public Point Position
        {
            get;
            set;
        }
    }

    // This is the component we want to reference
    public class GridComponent : Component
    {
        // Implementation details here ...

        public float[] ColumnSizes;
        public float[] RowSizes;

        public SizeF Size
        {
            get;
            set;
        }

        [Optional]
        public PositionableComponent2D Positionable;
    }

    // This is the component that references the other one.
    public class GridDebugComponent : Component
    {

        // Implementation details here

        public void ShowGridlines()
        {
            Point position;
            if (Positionable != null)
                position = Positionable.Position;
            else
                position = Point.Empty;

            float current = 0;
            foreach (float f in Grid.ColumnSizes)
            {
                PointF start = new PointF(current,position.Y);
                PointF end = new PointF(current, position.Y + Grid.Size.Height);
                MyGraphicsInterface.DrawLine(start, end);
                current += f;
            }

            current = 0;
            foreach (float f in Grid.RowSizes)
            {
                PointF start = new PointF(position.X, current);
                PointF end = new PointF(position.X + Grid.Size.Width, current);
                MyGraphicsInterface.DrawLine(start, end);
                current += f;
            }
        }

        [Required("To debug the grid, it must be referenced.")]
        public GridComponent Grid;

        [Optional]
        public PositionableComponent2D Positionable;
    }
We added a new component that allows our grid to be positioned in 2D space and made some use of it. However, we made it optional by adding the [Optional] attribute (which can have a description too, of course). This means that this field will be set with the correct component if we create an entity type that contains a grid and a positionable component. If we do not add a positionable component, our grid stays in top left corner of the screen. Because our field is null by default, we can check whether our reference was resolved with a simple if (Positionable != null) condition.

If you create a reference without [Optional] or [Required] attributes, they become optional but a warning is displayed when building the entity type.

Loose references

Loose references or event routes are probably the most powerful concept in this library. They do not only serve as a way for inter-component communication, but are also used to couple entities with other systems, entities with their components and can also be used to establish event routes between in regular classes to remain consistency with the rest of the library. Still, they are extremely easy to use for the end user - the whole thing gets reduced to 2 attributes you can apply basically every, and it'll just work.

Again we will start out with a simple code snippet:
    public class Program
    {
        /// <summary>
        /// Updates all objects.
        /// </summary>
        /// <param name="dt">The elapsed time since the last update, in full and fractions of milliseconds.</param>
        public static void OnUpdate(double dt)
        {
            if (Update != null)
                Update(dt);
        }

        /// <summary>
        /// Gets invoked every update cycle.
        /// </summary>
        public static event Action<double> Update;

        public static void Main()
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            // Build & instanciate entities, perform initialization etc.

            while (true)
            {
                sw.Stop();
                double dt = sw.Elapsed.TotalMilliseconds;
                sw.Restart();
                OnUpdate(dt);
            }
        }
    }

    public class MovingComponent : Component
    {
        /// <summary>
        /// Updates the component.
        /// </summary>
        /// <param name="dt">The elapsed time since the last update, in full and fractions of milliseconds.</param>
        public void Update(double dt)
        {
            Location += (Velocity * dt);
        }

        public Vector Location;
        public Vector Velocity;
    }
Again the code is incomplete of course, but we don't want to bother with unneccessary details. You can see that we have a simple main loop that measures the time since the last iteration with a Stopwatch. Then we invoke an Update event to update all objects in our program. We also created a simple component that should move in a linear fashion every update.
But will it? Of course not, because we never connected our Update() method with the static event in the Program class. That's exactly where Clockwise.Base comes in.
        public void Update(double dt)
becomes
        [Event("Update")]
        public void Update(double dt)
and
        public static event Action<double> Update;
becomes
        [EventSource("Update")]
        public static event Action<double> Update;
And thats it! Now every MovingComponent you will ever create through an entity .ctor will be registered to the event Update in your Program class. This works because we added one event source and one event target to the event "Update", as denoted in the attribute parameter.
What we did here, more precisely, was routing a single static event source to a single instanced component target. As promised before, this is only one of many possible ways to route events. We can actually add as many event sources and targets to the "Update" event route as we like, with the basic rule being that every event source triggers every event target you add to an event route.

EventRoute.png

To support inter-component communication well, there are some exceptions for Component and Entity to make the routes as intuitive as possible. Static sources and targets always connect, instanced ones only connect if they are inside the same entity.

Instanced event endpoints in arbitrary classes (anything but Entity and Component) are also possible and even easy to set up, but cannot be done with attributes because of technical limitations. See the Documentation page for more information about the specifics of the EventManager class.

Exposed interfaces

Whilst writing of individual Components is quite comfortable with all the features of composition we discussed before, using and modifying a final Entity object is still quite annoying. When creating objects in a class hierarchy, you can have properties with getters and setters and methods to directly access and modify the object. In component based systems, you first have to retrieve the Component to modify these properties:
    using ( ClockwiseManager manager = new ClockwiseManager() )
    {
        EntityPreset preset = manager.GetPreset("MyEntity")

        // Instanciate the entity
        Entity myEntity = preset.Create()
        myEntity.GetComponent<ColorComponent>().Color = Color.White;
        myEntity.GetComponent<TransformComponent>().Transform = myEntity.GetComponent<Transform2DComponent>().Transform2D;

        // And so on ...
    }
as opposed to some classic code like:
     MyEntity myEntity = new MyEntity();
     myEntity.Color = Color.White;
     myEntity.Transform = myEntity.Transform2D;
Constantly having to retrieve components is slow, annoying and we lose the ability to see the actual functionality of our entity in IntelliSense. This is inevitable for actually dynamic entities, but as we discussed before, entities are actually mostly static at runtime. To account for this disadvantage, Clockwise.Base provides the ability to generate a preset interface. Once the interface is generated, you can code with entites almost the same way as you would with a derived class:
    using ( ClockwiseManager manager = new ClockwiseManager() )
    {
        IMyEntity e = EntityPreset<IMyEntity>.Instanciate();
        e.Color = Color.White;
        e.Transform = e.Transform2D;
        e.LoadModel("Whatever.mdl");

        // And you can still do:
        e.GetComponent<Transform2D>().X = 123;
    }
You will also have full support for documentation comments and only minimal performance impact.

The generation of the interfaces is preferrable done through a T4 script InterfaceGenerator.tt, which is included in the download and supposed to be added to the project once. The script will then simply generate an interface for every component you create in that project and add it to the project, so you have perfect visual studio integration.

So how exactly is it done?

The first step is to decide which methods and properties are exported from some component. Say you have two components name CompA and CompB which contain properties A and B, respectively. Again, attributes are used to mark these properties as exposed:
    public class CompA : Component
    {
        /// <summary>
        /// Description of A.
        /// </summary>
        [Expose]
        public int A
        {
            get;
            set;
        }
    }

    public class CompB : Component
    {
        /// <summary>
        /// Returns a random number.
        /// </summary>
        [Expose("PropertyB")]
        public int B
        {
            get { return new Random().Next(); }
        }
    }
You just write your components as you normally would. The only change is the [Expose] attribute you can apply to any property and method. By invoking the interface exposer, the following two interfaces are generated:
    /// <summary>
    /// Auto-generated interface for component CompA
    /// </summary>
    public interface ICompA
    {
        /// <summary>
        /// Returns a random number.
        /// </summary>
        int A
        {
            get;
            set;
        }
    }

    /// <summary>
    /// Auto-generated interface for component CompB
    /// </summary>
    public interface ICompB
    {
        /// <summary>
        /// Returns a random number.
        /// </summary>
        int PropertyB
        {
            get;
        }
    }
Now we create an entity preset that contains our two components, which shall be called MyEntity in our sample:
    /// <summary>
    /// Interface for entity MyEntity which contains a CompA and CompB.
    /// </summary>
    public interface IMyEntity : ICompA, ICompB, IEntity
    {
    }
We can now build a entity preset based on this interface declaration and instanciate it:
IMyEntity e = EntityPreset<IMyEntity>.Instanciate();
e.A = 10;
e.PropertyB = 20;
When building the preset's type, EntityGenerator automatically correlates the interfaces to the actual component types and ties all of them together in the generated entity type by implementing the interfaces types.
This works in a way there are additional members beeing added in the generated entity type which pass through the parameters to the correct component. A generated property implementation for the above components looks like:
    public class MyEntity : Entity, IMyEntity, ICompA, ICompB, IEntity
    {
        public CompA CompA;
        public CompB CompB;

        public int PropertyB
        {
            get { return CompB.B; }
        }

        public int A
        {
            get { return CompA.A; }
            set { CompA.A = value; }
        }
    }


See also:

External links

Evolve Your Hierarchy A good introduction on refactoring game objects with components
Game Objects In Dungeon Siege Popular GDC slides by Scott Bilasant
Component Based Entity System Design Some other ideas for implementation (C++)
Artemis Entity Framework Another good C# (originally Java) framework for CBE's
Entity Systems Wiki A site collection information on CBE's
Entity Systems Are The Future of MMOG Development Extensive description of entity systems and the connection to relational databases

Last edited Dec 10, 2013 at 2:42 AM by Gandi, version 41