Component Game System - Object Examples

Started by
17 comments, last by Zakwayda 14 years, 4 months ago
Personaly, I find it easier to seperate logic and data into components and properties, and make the choice that both are owned by the entity. You're not forced to do it this way, the way you've set it all up works perfectly as well, it just makes it all work more logically in my brain that way.

So, how I'd think when solving your problem would be something like:
- Planet has a logic module that allows only one team to own it.
- When a team owns a planet, the team can extract resources.
- When a team owns a planet, the team can build space stations in it's orbit.

Planet thus needs to hold a component that allows a team to own it. For this, the logic require that the planet has a property on who owns it. Let's say it's the ID of the team.

Planet would also need a resource component, that holds the logic that defines the planet as an extractable resources. If nothing else, to initialize such properties as resource type, and extraction-rate modifiers.

A team needs a resource extractor component, that holds the logic to deal with extracting resources from a resource. It doesn't "have" to be a planet. Let's say that the planet resource component holds a special logic that checks for the ownerId property, and if the resource extractor is not of this id, then it won't allow resources to be extracted. This component could also check item stats and whatnot, to check the capabilities of the team to extract resources.

A team also needs a space station builder component, which would allow a team to build space stations. Let's say that building one in the orbit of a planet makes the component logic check that the planet's ownerID is equal to the team's id. If it isn't, they won't be able to build there.

I think it's a good idea to use messaging between entities. Myself, I found that doing messaging within entities too, between components and all that, got a little messy for me. I, instead, let components share common properties instead, and react with logic on properties changing. Also, I'd suggest that you consider extactly what you benefit from your component system. Do the rendering, physics and sound really need to be a component? Is there a point of making something a component if most every single entity will share that logic and capability? This might be a way to simplify your component domain, and make designing and seperating your components easier.

Myself, I've made the decision that my components were only to be used for gameplay logic. Every entity in my engine has rendering, physics and sound capabilities hardcoded in there.
Advertisement
I think it is interesting just how many people are advocating using an Object wrapper for components and applying properties to it. It tends to make the concept easier to deal with in your mind, but I think overall it is less efficient (haven't tested or analyzed, I just have a hunch) as it adds another layer of complexity to the organization.

But I wanted to talk more about the implementation of component objects and less about how they communicate.
The thing is, the implementation is totally dependent on how the components communicate with each other. Once the interface between components is defined, the internal workings are totally up to the component. The tricky part of component-based design has always been, IMO, getting the components to work together.
Quote:
I think it is interesting just how many people are advocating using an Object wrapper for components and applying properties to it. It tends to make the concept easier to deal with in your mind, but I think overall it is less efficient (haven't tested or analyzed, I just have a hunch) as it adds another layer of complexity to the organization.


I have this hunch as well, and its a fair point after all, when you consider how much more work happens in my system when I was to do basic tasks such as get the position of an object, in the classic inheritance model it comes down to an inlined function call:

object->Position();

In my system I have to first lockup a map for a string to see if it exists, I then have to retrieve the property, and dynamic_cast it to the correct type, and then return it.

Another example: Renderable component creating a mesh inside Ogre:

Using the inheritance model we would simply say something along the lines of:

object->AddToRenderer(mRenderer);

In my model, here are the steps that are taken:
- Renderable component sends a message to GRAPHICS_SUBSYSTEM asking for the renderer.
- PostOffice receives message and forwards it to all Messengers that are listning in on GRAPHICS_SUBSYSTEM.
- The renderer receives this message and posts a message back to the agent that has the Renderable component with a pointer to itself.
- The Agent forwards the message to the Renderable component.
- The Renderable component receives this void pointer, casts it to a Renderer and creates the correct mesh (after using the above property system to get the mesh name ofc).

So yes, this is going to be very slow, and can only be optimized so far, without tightly coupling the components and property's. However it does allow maximum flexibility and the ability to combine any components and properties without things breaking (as in crashing).

So what am I going to do about it? I've dubbed it the "Lego and glue philosophy", I build my masterpiece out of Lego bricks (components and property's), this way I can switch bricks in and out as I please until the structure is perfect. Afterward I will glue the bricks together (start tightly coupling components and creating dependency for the sake of efficiency) to make sure the structure doesn't fall apart over time.
Game development blog and portfolio: http://gamexcore.co.uk
In my component system, I don't lookup every time I use a property. Since the components know which properties they need in order to perform their logic, each component store a reference to that property instance at construction. Since, in my system, the properties are shared among components inside their respective entities, and since all logic lies in the components, I hardly ever have to do a lookup in the map.

Also, what I've concluded with and have spoken of in the past for how I feel about approaching components, is that overusing components can have more bad than good with it. Do you really need the flexibility of having a rendering component, or physics component? Won't every game object in your world need both anyway? So, why overly complicate this core functionality of the game object? Myself, I focus components on the gameplay logic. Keep the core optimized and hardcoded, but keep the gameplay logic flexible, that's the part of a game object's code that your designers will care about and want to "lego" brick for brick anyway. Complicating the requirements of your core engine pipeline because you want to use components... just makes the whole component approach that much more complex and difficult to integrate in your game engine imo.

Also, since my "Components and how they communicate" post over a year back, I had the personal realization that using events as the means of communication between components inter-entity made the actual flow of logic more complicated than necessary. Yes, it solved coupling, but I found myself in situations where ping-ponging between components would some times occure, or where logic would jump between different components, to make each component cover their responsibility domain during the execution of some gameplay logic.

In the end, what I realized, was that in most situations, if not all, the communication between components inter-entity was based on changing properties. Thus, making properties the "glue" between components inter-entity simplified everything. When a component can listen to a property that change, and perform some kind of logic when it do, you achieve much the same as you'd get with inter-entity component communication via events, but with a lot more independent and seperate relationship between the execution in components.

I still use events to communicate between entities however. So if there's a component who performs some kind of logic towards another entity, like a "target", it would send an event to that target, not start accessing it's properties directly.

Of course, this is a solution I find to be working really well in my own project, it might not fit as well in yours, or might not ring as clear in your mind as in my mind. A different approach might be better for you. There's a win/lose for every decision though. Optimalization and flexibility are kind of "opposites" like that...
Quote:Also, what I've concluded with and have spoken of in the past for how I feel about approaching components, is that overusing components can have more bad than good with it. Do you really need the flexibility of having a rendering component, or physics component? Won't every game object in your world need both anyway?
I don't think that's a given - it really depends on the game.

I use a component system in my game, and there are many game entities that don't have physics and/or rendering components. Many entities (static obstacles, stationary powerups, UI elements, menu items, some background design elements) are non-mobile and therefore don't require a physics component. Other entities (triggers, sound sources) don't have a visual component. In fact, although I agree with you that you can take it too far, I've felt at times that even having a transform component built in to each entity was less flexible than I wanted. (There are some entities in the game that don't have a spatial configuration of any sort.)

My ideal component system would make no assumptions about what components an entity should or should not have. However, the more abstract the component system gets, the harder it becomes to design (IMO), and of course there can be performance implications as well.

There's certainly no 'one size fits all' solution, and sometimes it's best to favor practicality over elegance and flexibility. However, I think the question of whether one needs the flexibility of an entity not having this component or that component really depends on the programmer and on the project.
Most certainly, which is why I've been very careful to point out that the way I'm speaking of may certainly not be the best way for someone else.

I do think, however, that many who start adapting their engine/game to the component-based approach, don't focus enough on the problems they try to solve, or the flexibility that their game requires. The question of "optimal" solution or is this approach "efficient" is too commonly asked imo, because it all depends on the requirements of your project and the problem-domain your components are there to solve.
Yeah, we had that same design decision to make, "well all entitys are gonna need a position, so why dont we just put that in the base class" but in the end this project is one very big experiment (uni project, and are the first "team" to be doing it, its always been done seperatly as well as trying to get people from other courses (art, sound eng etc) to work with us) so we figured why not tackle another experiment at the same time, "Can we make everything out of interchangable components and have it work".

So far were going strong, but were very early on, the only thing that isn't a component at the moment is the Team that the entity belongs to, but afterall, asteroids in the background and the sun dont belong to anyone, so maybe this should go aswell.

As for the events when a property changes, this was one of the thins that clicked in my head as well, so I implemented an OnChange event so that components will be notified when the property changes.
Game development blog and portfolio: http://gamexcore.co.uk
Quote:I do think, however, that many who start adapting their engine/game to the component-based approach, don't focus enough on the problems they try to solve, or the flexibility that their game requires. The question of "optimal" solution or is this approach "efficient" is too commonly asked imo, because it all depends on the requirements of your project and the problem-domain your components are there to solve.
Agreed :)

This topic is closed to new replies.

Advertisement