Jump to content
• Advertisement

# About my component system implementation

This topic is 4492 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

## Recommended Posts

Hello everyone, I'm writing this post after my reply to the post "Shall entities know how to render itself?" I spoke of a component system that I use, and received a few pms from people curious about the system, and I promised I'd write it up, so here it is! I'll start by giving a brief overview of the system for people who are not familiar with it, and then I'll show how I implemented it. At the end of this post is a link to my source code - the way I'm doing it. So first, the intro. What is this? Essentially, the component system is a way of describing objects in a game engine, in a way that is reusable. It is similar to why we use inheritance, so we can extend. The component system works on the object level, rather than the class level. What I mean by this, is instead of extending functionality of an entire class, we can extend the functionality of a single object. This brings the benefits of very minimal bloat in places, and - in my opinion clarity. Here's a quick example of how it might work:
// First, we have to create the object.
ObjectID npc = ObjectManager.CreateObject("NPC #547");
ObjectManager.CreateComponent(npc, "/Common/Entity")
ObjectManager.CreateComponent(npc, "/Graphics/AnimatableMesh")
ObjectManager.CreateComponent(npc, "/Gameplay/Communicatable")
ObjectManager.CreateComponent(npc, "/Common/ScriptedInteraction")


About the example Ok, so that might not mean a lot to you, so I'll quickly go over the code presented above. The first thing that I do is create an "ObjectID." This is merily an index to the object, and ObjectID contains only 2 properties, ID and name. I request the object manager create an object, called "NPC #547" and it returns a unique id. The name part is just for scripts to find objects, btw. The lines after that are me constructing the object. I call the CreateComponent method of my object manager, tell it the object to add the component to, and the name of the component. To quickly sumarise the components above, entity provides the location of the entity, and its orientation. AnimatableMesh does, well, what it says on the tin, Communicatable means that the player can communicate with the object, and scripted interaction means that any interaction will be handled via a script. I've purposly left a lot of the details out in that example like what script to use, setting the entity properties, and stuff like that. I left them out simply for clarity. Components Every component in my system runs of an abstract class that is:
public abstract class Component
{
protected ObjectManager objMan;

private ObjectID obj;
public ObjectID Object
{
get { return obj; }
}

public virtual void Initialise(ObjectID objectId, ObjectManager manager)
{
...
}

public virtual MessageResult HandleMessage(Message m)
{
...
}
}


All components inherit this class. The initialise method initializes the component, and the contents of the method in this abstract class is just to set some variables. Other classes might require resources from the manager, and such. But, how does the object manager know about these components that we create? There are a few ways I could have tackled this problem. I'm currently doing it a very manual way, which is to simply call ObjectManager.RegisterComponent(Type, string, AddComponentDelegate). The Type parameter is a .NET thing, that is the type of the component. When creating the component I use reflection invokation, but in C++ you could use a function pointer or something (I don't use C++, sorry). The string parameter is the unique name of the component. In the example above, this might be "/Common/Entity". I will touch on the AddComponentDelegate later. Another way I am considering trying is to use attributes on each component, with the same parameters. This gives me the advantage of not having to explicitly add each component to the object manager, which will make the code flow more efficient for me. Using the components So far, you've got enough information to make the basics of a component system, but when actually "using" the components, it may prove difficult. This is because there is no easy way to access them. My solution to this problem is to introduce ComponentContainers. A component container is a class that is a way to store components. The AddComponentDelegate acts like a reference to a function that should add the component to it's required store. I currently use 2 component containers in my engine, the SoupContainer and the TreeContainer. A soup container has the main goal of storing entities in a 1D list, with little order. The TreeContainer was designed specifically to address the scene graph. When I create an Entity component, it is automatically added to the root node of the Entity tree (a static property if you take a peak at the code). These component containers give a nice way to work with components. For instance, lets assume we want to render the scene. What I do at the moment is run a Update visitor on the Entity TreeContainer, that traverses the tree, pushing and popping each node onto a matrix stack appropriatly. Then, I get all of my Visibility components from a soup collection, and check the volumes against the camera view frustum, with the location specified in the entity node. I now have a list of ObjectID's that are visible to the camera, so I go through my Mesh SoupContainer, and if it's ObjectID is one of the visible ones, it is rendered. As you can see, there is a lot of interaction between components, and I'm not sure whether it's totally a good thing, but for the most part now it works, and I'm not finished with this system yet. There's one more it's worth speaking about before I wrap this post up, messaging. Messaging Often, componentss will need to know information that isn't really their responsibility. Let's take a made up example of a car. The car could be made up of a mesh component, and a damagable component, amongst others. First of all, the mesh needs to be modified as the car takes damage, or maybe start a particle system to make some sparks. You get the idea. This is where messaging is useful. The Damagable component can simlply send a message to all components of the object saying "I've taken damage, if anyone needed to know that." Components subscribe to a specific type of message (maybe DamegeTaken, in this example) and when the receive a message, they can react accordingly. I use System.Guid to represent the type of a message, and all classes that can send messages expose public static properties of there Guid. There is a chance of overlapping message ids at the moment, but it won't take much to remedy that situation. Conclusion Ok, so that's a pretty long post for what seems like a small topic, but hopefully this has given an insight into the system. I just want to say, very importantly this is not my idea. The way I store components in containers is my idea, and I've adapted the system to work well in .NET, but the original concept was invented by Bjarne Rene. You can find a nice article that beats my explanation abilities by far, in Game Programming Gems 5. I highly recommend the book! As you can see, this system works nicely in the game scenario and gives us a way to represent objects without interfering with others. It is extendable, and modular, meaning all changes should be centralised to the component, and nothing more. You can get my code from: this lovely little link. It is actually the engine I am working on at the moment. I removed a bit of stuff from it, like the material Component I am working on at the moment, because it's incomplete. I really hope that this post has given all those who were interested the information they wanted to know, and if there is anything I have missed, ask! Thanks for reading (should I submit this as an article, btw?)

#### Share this post

##### Share on other sites
Advertisement
Wow. Thanks. I can't wait to try this out myself.

#### Share this post

##### Share on other sites
I am not able to get it to compile just yet, but I do find looking through your source code refreshing.

The way I am coding my engine right now I absolutely hate, and the way you seem to have done it is the way I previously wanted to do mine.

Thank you very much for posting this code.

#### Share this post

##### Share on other sites
Glad to see it's helping :)

#### Share this post

##### Share on other sites

• Advertisement
• Advertisement

• ### Popular Contributors

1. 1
2. 2
3. 3
Rutin
18
4. 4
JoeJ
14
5. 5
• Advertisement

• 14
• 10
• 23
• 9
• 34
• ### Forum Statistics

• Total Topics
632634
• Total Posts
3007548
• ### Who's Online (See full list)

There are no registered users currently online

×

## Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!