Jump to content

  • Log In with Google      Sign In   
  • Create Account

Entity Component System questions/tips


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
21 replies to this topic

#1 AnEverydayGuy   Members   -  Reputation: 172

Like
1Likes
Like

Posted 25 March 2014 - 02:52 PM

Hey guys, I've been doing a lot of reading on Entity Component Systems and I figured I'd give it a go. I have a basic design layout and I was hoping to get some feedback, both to help out a beginer with this new design implementation and to so I can see people's thought processes.

 

Here's what I've come up with (sorry, no code right now):

 

 

Entities:

  • Just a Universally Unique ID (UUID).
  • Since an entity is a UUID, this will be implemented within an entity manager (see below).

 

Entity Manager:

  • Manages entity creation and removal.
  • Entities are stored in an array (maybe, this seems redunant as the UUID will act the array index but I will need someway to store created entities, right?).

 

  • Each entity has it's own creation method where an entity is created and components are created and assigned to the newly created enity. This is so it's a simple function call to create as many tanks, jets, unicorns, sharks with freaking lazer beams, etc as desired.
  • This means the entity manager will be keeping track of components and whom they belong to. To keep it fast and simple, I figure an array for each component where the entity's UUID can index into said array(s) to get it's components. This way systems can simply iterate over the array(s) it needs and to make use of pre-fetching and caches.

 

  • Entity removal will cause the UUID to be thrown into a list of some sort so that it can be recycled (on entity creation). This will prevent the UUID from becoming impossibly large should a large number of entities be created then destroyed.

 

Components:

  • Data only.
  • A list of components is held by the entity manager (see above).

 

Systems:

  • One system per aspect (physics, AI, etc). These are independed of each other so it should be trival to put them in different threads if desired.

 

System manager:

  • Primary use is to be a black box to hide the data structure containing the systems (array, vector, linked list, who knows).
  • This will also make it easy to have each system in a thread (if desired), in the add method just start a thread for the system, or add it to a data structure that is iterated over every frame, or whatever).
  • To keep it simple and easy for now, it'll be a vector.

 

  • This can also provide a way to prioritize systems, pause systems or outright remove them (though I'm thinking this is probably a stupid idea; I can't really think when I'd want to remove a system outright or even to just pause it).

 

  • I'm not even sure If need this. It's a 'nice-to-have' in that it helps seperate world functionality (see below) from system specific functionality. But this could be my OOP background nagging me.

 

World:

  • There's only one world so this will be an object (as in OOP).
  • Will contain an entity manager and system manager.
  • Will have methods to load & save the world.
  • Will contain the main loop.
  • Will behave as everyone elses world object (I'm sure).

 

 

 

I think this is a pretty decent design (to start with) but I'm curious as to what you guys think. After all I could be heading toward a world of hurt and not realize it or be on my way.

 

I do have one question though. My entity manager contains the list of components used by the entities. This is because I would like to go EntityManager.tank(...), EntityManager.SharkWithFreakingLaserBeams(...), etc rather than manually type: create entity; create componenets; assign components to entity; each time I want to create something (the only difference is what components are created because it depends on the entity, so why not automate it?). However, this leaves me in a bit of a pickle for systems. Since they are two are seperated objects, the system manager does not have access to the list of componenets that it needs to iterate over and do its thing.

 

What would be considered the best idea to solve this (yes, I know there's a hundred different ways I can solve it). I'm thinking of something like:

  • The entity manager has a 'get components' function(s).
  • The components are fed into the system manager's update function.
  • Each system takes the components it needs to work on and iterates though them, doing it's thing.

That's probably the easiest solution I have, for the design I have; but I don't think it's upgradable. IE: What if I want to change the system manager from a data structure to a thread creation implementation. Ideally I can simply make the change in the add/remove methods of the system manager, but now the solution to give the system manager the list of components goes out the window since the system manager no longer has an update function (each system is in it's own thread so it'll be best to let it deteremine when it needs to update since some systems will be likely to run at different times. EG: render all the time, update at the frame rate).



Sponsor:

#2 TheChubu   Crossbones+   -  Reputation: 4349

Like
0Likes
Like

Posted 25 March 2014 - 03:19 PM

It looks quite a bit like Artemis ECS Framework

 

You might want to check the sources, it can give you ideas on how to handle indexing, sending entities to each system, etc. Have in mind that most of it is quite thread unfriendly (ie, quite a bit of the World/Entity methods have lots of side effects).


"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

 

My journals: dustArtemis ECS framework and Making a Terrain Generator


#3 Irlan   Members   -  Reputation: 1494

Like
1Likes
Like

Posted 25 March 2014 - 05:25 PM

You have to remember the other systems that will be involved in your game like the AI System etc.
The simple case of Actor/Game Object/Component/ class is just a way to generalize the way you organize a Scene/GameWorld.
The book Game Engine Architeture goes in detail about that and if you've not read I recommend you do cool.png . 


#4 phil_t   Crossbones+   -  Reputation: 3915

Like
0Likes
Like

Posted 25 March 2014 - 06:03 PM


This is because I would like to go EntityManager.tank(...), EntityManager.SharkWithFreakingLaserBeams(...), etc rather than manually type: create entity; create componenets; assign components to entity;

 

There's no reason to clutter your EntityManager with these methods. Your EntityManager should lean more towards the engine side of things, while the game-specific code like assembling prefabs like tanks can exist somewhere else. Or you could make some simple text format that can be parsed to create prefabs.

 


However, this leaves me in a bit of a pickle for systems. Since they are two are seperated objects, the system manager does not have access to the list of componenets that it needs to iterate over and do its thing.

 

The systems can just request the component lists they need from the entity manager (or the code that creates the individual systems can pass the necessary component lists - but then changing the implementation of a system might requires code changes in two places).

 


each system is in it's own thread so it'll be best to let it deteremine when it needs to update since some systems will be likely to run at different times

 

Your systems will need to be updated in an explicit order, so I don't think you can just say "they will run at different times on different threads". If you end up putting some systems on a background thread, you'll need to think very carefully about how you do it. 

 

You might consider not building any general threading functionality into systems/component lists at all (it seems like this would require very complex and and potentially performance-impacting sync mechanisms), and instead make it an implementation detail of each system.



#5 Buckeye   Crossbones+   -  Reputation: 4918

Like
5Likes
Like

Posted 25 March 2014 - 06:13 PM

You shouldn't be too concerned about "recycling" UUIDs. One "popular" size for UUIDs is 128 bits which is something like 3*1038 numbers. Even a 32 bit id will provide 4 billion IDs. How big a game are you making, anyway?! biggrin.png


Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#6 AnEverydayGuy   Members   -  Reputation: 172

Like
0Likes
Like

Posted 27 March 2014 - 12:06 PM

Okay, so I've made some changes due to concerns that were brought up and that I thought of.

 

  • I've added a component manager. This makes sense because the entity/component/system managers ARE objects so they should adhere to OOP best pratices (specficly about Single Responsiblity). So now the entity manager only worries about entities, and the component manager only worries about components.
  • I've added a 'world' object whose concern is the world (go figure) and has instances of the various managers.
  • I have a 'build world' file where I create an instance of the world and inside this file holds the various 'create game objects' functions (create an entity and it's assosiated components).

This way instances of the various managers and the world can be reused from game-to-game and not have game specfic code in them. This is also in line of the Artemis framework (I learn best by doing, so if I can build my own framework, I'll have a better understanding of what is probably going on under the hood of other frameworks when I choose to use them; and so I can compare my framework to something else in case I get stuck on something).

 

I also changed entities from UUID to simple IDs. The reason I am recyling them is that I'm going to use the ID as an array index. So I'm worried about array sizes for all the components, not running out of numbers. IE: I'd rather not have a UUID of 3,000,000 because I would need to have an array with a size of at least 3,000,000 for each component. So, since I'm recylcing IDs, they should be IDs and not UUIDs.

 

 

 

2 questions has come up now that I'm starting to do some indepth desiging / initial coding.

 

1)

 

How do you guys handle the granularity of components? I'm thinking (for now) I'll have extremely rough granularity and break down components as required. What are your thoughts?

 

EG: Let's say I'm making an old school Rainbow Six game. So I have maps for various buildings with various levels each.

 

OOP states (at least for me) as a quick and dirty breakdown:

 

  • You have an object for a map (Map). It has a level, a heading (so the map can be rotated), a floorplan and a position on screen.
  • You have an object for a collection of maps (Atlas) that represents a building. It has a position on screen.
  • You have an object for a collection of atlases (Atlases) that represents the world (the collection of buildings). It has a position on screen.

ECS states (according to the extremely little experience I have with it):

 

  • You have 'x' number of entities, 1 for each level for each building, 1 for each building and 1 for the final map that shows all the buildings.
  • Components are: Position (used for everything) and a 'map' component that contains the map's level, heading and floor plan.

Now I know this sounds weird (at least to me) but I'm thinking of making compoments with low granularity then making them higher as needed. So the map component would have also had a position but since other objects have that component (and aren't a map of a specific level of a specific building), position has been broken out. If I make a new game object with a level and heading, I'd break those out of the map component so the map and the new game object can use those components.

 

Or do you guys program with high granularity right off the bat; so the list of components are: position, level, heading, floorplan; and a map entity has all of them and everything else just has position.

 

 

 

2)

 

My other question is what is the 'best' way to handle flags? For example, say I build a game with no health so to speak; things are either dead or alive. Should there be a component with an 'isAlive' flag; or does it make since to use the component itself as the flag; so if a thing has an 'alive' (empty) component, it's alive?

 

 

 

Again, I realizeI can program it in any way I want (and I will) but I'd like to know other people's thoughts and experiences so I can avoid any traps that might be lurking around.



#7 phil_t   Crossbones+   -  Reputation: 3915

Like
4Likes
Like

Posted 27 March 2014 - 01:59 PM


I also changed entities from UUID to simple IDs. The reason I am recyling them is that I'm going to use the ID as an array index. So I'm worried about array sizes for all the components, not running out of numbers. IE: I'd rather not have a UUID of 3,000,000 because I would need to have an array with a size of at least 3,000,000 for each component. So, since I'm recylcing IDs, they should be IDs and not UUIDs.

 

In my framework, I use both notions. Recyclable "live ids" (which are essentially array indices), and "unique ids". Unique ids are used whenever there are relationships between entities (visual hierarchy, team classifications, etc...) that need to be preserved across serialization/deserialization. I have an open world, so I need to be able to serialize "un-used" portions of the world as needed. When I deserialize them, the recycled ids would be completely different, so I can't use those to describe entity-entity relationships.

 

 

 


My other question is what is the 'best' way to handle flags? For example, say I build a game with no health so to speak; things are either dead or alive. Should there be a component with an 'isAlive' flag; or does it make since to use the component itself as the flag; so if a thing has an 'alive' (empty) component, it's alive?

 

I would have a component with an isAlive flag. I suspect as you work on your game, you'll find other things you might to throw in that component that would apply to all creatures/people/etc in the game.

 

 

 


ECS states (according to the extremely little experience I have with it):
 
You have 'x' number of entities, 1 for each level for each building, 1 for each building and 1 for the final map that shows all the buildings.
Components are: Position (used for everything) and a 'map' component that contains the map's level, heading and floor plan.

 

This sounds like a level description. This doesn't necessarily need to be expressed as entities. A level description could be used to drive the creation of entities though.

 

I don't know much about the Rainbow Six games though, so I could be off here. For example, I'm trying to think of reasons why you'd need to have a building be an entity (instead of just part of the level model file). Perhaps you want to be able to mark the building as "cleared of enemies", because that is somehow important to gameplay. Or an enemy needs to know which building it "belongs to" for some reason. Those would be valid reasons to have a building entity (and corresponding component that describes things unique to buildings, such as "isClearedOfEnemies").

 

I think a more interesting thing to think about is the characters in your game, and the actions they need to perform. Map out different scenarios you need to happen in your game, and figure out the necessary components/system logic/scripts to make those happen.


Edited by phil_t, 27 March 2014 - 02:02 PM.


#8 BeerNutts   Crossbones+   -  Reputation: 2944

Like
1Likes
Like

Posted 27 March 2014 - 03:44 PM

I'm not sure that "Levels" and "Buildings" should be considered entities.  I think that's trying to fit a square peg in a round hole.

 

You're going to get the best results using the entity/component system for game-objects.

 

If I'm writing a platformer, my level will probably be expressed as a tiled map, and the level itself won't be an entity.  Rather, within the level, I will have  objects that are entities.  Considering, most of my level will be "empty", the actual platforms and other objects that live within the level will be my entities.  So, the box that can be picked-up and moved, the gun that can be picked up, etc.

 

I wouldn't bother using ECS for your starting screen, for example.  I think that might not fit in real well either.

 

Don't try to fit every piece of your game into the ECS pattern, it will be too difficult.  


My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

#9 AnEverydayGuy   Members   -  Reputation: 172

Like
0Likes
Like

Posted 28 March 2014 - 10:10 AM

That was a bad example. I was using it to highlight the problem, not be the problem itself.

 

The question is how do you design components? Do you make them very small right off the bat? Or do you make them as big as you can and then break them apart as required?

 

IE: Do you make a component A with properties V, W, X, Y, Z; then later on find out that you need properties Y & Z for another object that is not the same 'type' so then you refactor so you now have component A with properties V, W, X and component B with Y & Z. Then later you need property X for another object not the same 'type' so you refactor such that component A has properties V, W, component B has Y & Z and component C has property X; and so on.

Or do you just make a new component for each property right off the bat and not refactor?



#10 phil_t   Crossbones+   -  Reputation: 3915

Like
0Likes
Like

Posted 28 March 2014 - 11:38 AM


Do you make them very small right off the bat? Or do you make them as big as you can and then break them apart as required?

 

Neither :-). Although I tend to think the latter would be the more common result (i.e. you end up having to break apart one component into many as a result of refactoring).

 

You should design the components so that a component represents a "concept" that is common across a range of entities, and that the logic for a particular scenario/system only needs to know about the data in that one particular component (and all the data in that component is relevant for the scenario). Obviously this doesn't work perfectly in practice, since you'll find that most code needs to know about position, for instance. So in that case position needs to be broken out into its own component.

 

 

(NB: I have seen frameworks described where there are no components, just individual properties. In that case though, the goal isn't to eventually combine the properties into components).



#11 haegarr   Crossbones+   -  Reputation: 4311

Like
0Likes
Like

Posted 29 March 2014 - 04:11 AM

Question is what a property means. Using a CES is a bit like programming. Do you want to use a vec3 or instead a float, another float, and a third float? Do you perhaps even want to use a Position instead a vec3? Do you perhaps even want to use a Placement instead of a Position and Orientation separately? Looking at DCC packages, animations can be modeled on each single component of position, Euler orientation, scaling, or whatever. That gives you best flexibility, but also burdens you to deal with them each separately.

 

I personally define data component (in the meaning of CES) as complete units with a semantic, e.g. I prefer a PlacementComponent. Such components provide properties, in the example a Placement with its own properties Position and Orientation, that can be accessed individually. Any client of the PlacementComponent can deal with the Placement property or, if knowing its composition, with Position and/or Orientation. The various manipulators like ParentingComponent, TrackingComponent, … do it this way.

 

So from a users point of view components are higher level constructs that may (depending on the component type) be configured to drive all or just a part of the target (e.g. the ParentingComponent should just drive the Position but not the Orientation). This allows for providing not so many component types and, due to the inherent semantic, does not demand a so deep abstract thinking as would be with two vec3 or even 6 floats.



#12 LoneDwarf   Members   -  Reputation: 262

Like
0Likes
Like

Posted 31 March 2014 - 03:28 PM

One part that I would spend more time on is determining how to build the objects (layout).  I know phil_t suggested using a text file and this answed your question but you need to have more questions in this area.  I see very little point to using an ECS if you're going to hard code how your objects are created.  You need somekind way to define your objects and then created them using that define / template.
Here is a really simple lua script I just rattled off, not how I would do it but it gets the point across.

 

defines =
{
    truck_heavy_red =
    {
        physics    = { weight = 10, max_speed = 25.0 },
        render = { model = 'trucka', texture = 'foo.dds' },
    }
}


game:loadDefines( defines )

game:createEntity( 'truck_heavy_red' )

 

Also the ids to index the array is fine and should be used in conjunction with somekind of weak reference system.  You will want some references to an object to get invalidated when they are destoryed.  Think of your tank having a reference to it's target.  I use something like the method described in Game Gems I


I would also have another class called Game that contains your World.  I put stuff like my modes in there (GameMode, PausedMode, HelpMode etc).  Also access to some systems like lua, game options and UI.  I treat the World as the simulation only.  Just a thought.

 


Edited by LoneDwarf, 31 March 2014 - 03:29 PM.


#13 AnEverydayGuy   Members   -  Reputation: 172

Like
0Likes
Like

Posted 01 April 2014 - 09:27 AM

Okay, thanks guys. I think I have a better understanding that will help me get started. I think now I'll have to start coding and allow myself to get dirty and make mistakes to make the next step in learning. Thanks a lot!



#14 AnEverydayGuy   Members   -  Reputation: 172

Like
0Likes
Like

Posted 09 April 2014 - 11:44 AM

Okay, I'm making some baby steps but now I've got a question. What are some of the ways I can select an entity based on the value of a component?

 

 

 

Example:

Say the user picks up a color bomb and uses it. They pick a color and all enemies with that color blow up.

Say I have a component (A) that has several properties, one of them is color.

Say I have a 'world' object responsible for the world and ideally, as game independant as possible.

Say I have a 'game' object that has the world and is responsible for game specfic logic.

 

My first thought is there's a function (J) responsible for impleting this task somewhere inside my game object and is called when nessessary. J calls a world method that returns a list of all entities with component A (function K). K queries the entity manager for said list and returns it (K is a middle man). Now J has a list of entities with component A and can filter out those that do not have the desired color and do its thing.

 

This seems either like an odd way to do it, or more complicated than it needs to be; so I'm curious as to the different ways to do this.



#15 phil_t   Crossbones+   -  Reputation: 3915

Like
0Likes
Like

Posted 09 April 2014 - 01:03 PM

Here's how I would do it, based on my ECS implementation:

 

I'd have some code in the bomb system that checks to see if a bomb has been "used". If so, and if it's a color bomb, then it would need to obtain the list of all entities that have component A with a matching color. So your ECS needs a good way of saying "enumerate the entities that have this component".

 

In my current implementation, systems support this functionality. My systems can declaratively state "I care about all entities with component A". The system would have a list of all entity ids that have component A, and this list is kept updated by the EntityManager automatically. So the bomb system can simply ask the "Component A system" to enumerate this list (this could be done by some messaging system, or more explicitly by giving the bomb system a reference to the "Component A system").

 

So the bomb system would simply enumerate this list, get the A component for each entity (which is guaranteed to be there), and check for a matching color. If a match, then it "does its thing" with that entity.

 

I'm interested to see how others would approach this.



#16 AnEverydayGuy   Members   -  Reputation: 172

Like
0Likes
Like

Posted 12 May 2014 - 02:00 PM

Alrighty, I have a question.

 

How do I make entities 'belong' to other entities? Such as 'this tire belongs to this car'.

 

In OOP:

Tires:
    class AllWeather....
    class Winter....
    class Slick....
    class Drag....

Car:
    tires = new Slick();

So if I want to get the tires the car is using I would do something like 'tires = car.tires'.

 

What are the ways I can do this in ECS? I'm thinking I should add a new component (belongsTo) that I can add to entities (such as tires) that contains the entity ID of the entity that the entity belongs to. Does anyone see any problems with me doing that or have any better ideas before I go to far down this path?

 

 

 

*** Edit ***

 

I have come up with another question (I'll use the same example as above, but I'd like to have answers to both questions).

 

Let's say rather than being entities, a tire is a component that is built from other components (this makes more sense as a tire isn't actually a game object per se but a component of a car). How do the various ECS implementation handle having multiple components that are the same (IE: a car has 4 slick tires installed)? And since we are on the subject of components made of components, is this a good idea or should it be avoided (IE: should I have a car entity make of a body & tires components, and each body and tire component is made of smaller components)? This seems like like a stepping stone toward OOP.

 

 

 

To sum up:

* What are the various ways to handle when an entity belongs to another entity? (This sounds to me like one of the entities should be a component, but the question stands.)

* What are the various ways to handle when an entity has multiple of the same component?

* Is having a component made from other components a good or bad thing?


Edited by AnEverydayGuy, 13 May 2014 - 10:51 AM.


#17 haegarr   Crossbones+   -  Reputation: 4311

Like
0Likes
Like

Posted 18 May 2014 - 10:26 AM

In OOP:

...

Well, it looks like using inheritance is the OOP way to distinguish different types of tires. That is possible, but necessary only if you need to use different code for different types of tires (especially if you want it being expandable later on). A better way (if possible at all) is to describe the features of the different types of tires by parameters (keyword "data driven"); e.g. you have a small couple of friction co-efficient for some grounds.

 

What are the ways I can do this in ECS? I'm thinking I should add a new component (belongsTo) that I can add to entities (such as tires) that contains the entity ID of the entity that the entity belongs to. Does anyone see any problems with me doing that or have any better ideas before I go to far down this path?

ECS is a fancy name for composition where the "top level" is a kind of game object. Hence it is possible to go several ways. For example (without claiming to be complete):

 

1a.) Making the wheels being entities on their own is of course a valid solution. It would require to express the attachment as you already have stated. In the given case a relational component may be used: A Parenting component with the wheel as child and the vehicle as parent. Because the relation has explicit links to the both entity roles, both the vehicle and the wheels as entities are stored side by side.

 

1b.) The wheels are entities by their own again, but the relation is expressed as in a scene graph: The wheel entities are arranged inside the vehicle entity (means entities can be components). Perhaps this approach has the advantage that the vehicle occurs as a unit. However, there are disadvantages:

 

* Although there is an implicit expression of the child and parent roles, there is still the need to store the local placement of the child. If a Placement component is used to express the global placement, then a child component needs a LocalPlacement in parallel, but if a Placement component is used either as global or as local component, then its meaning depends on the use case of the entity.

 

* Parenting is not the only relation you may want to express (I'm using a dozen or so). So why should parenting be implemented by nesting, while all other relations then need to be explicit and connect in a general graph like structure?

 

2.) Wheels are not entities at all: Assume that there is a component called Chassis. Adding a Chassis to an entity declares it being a kind of vehicle. Let's assume there is a derived component type like FourWheels, obviously supporting 4 wheel vehicles. It is parameterized with e.g. wheel base, track width, tire-to-ground friction, and perhaps other things.

 

3.) A mix of 1a and 2: Wheels are given as own entities side by side to the vehicle. They are related to the vehicle each by a Parenting component. The vehicle entity has a FourWheels component that is the reverse relation from the vehicle to the wheels, controls the wheels' local Placement components, defines the physical parameters and hence tags the entity as vehicle.

 

--

 

I personally prefer option #3. It does not enforce a special handling of a kind of relation, still allows each single wheel to have its own graphical components (for example), and encapsulates behavior in the form of Chassis.


Edited by haegarr, 18 May 2014 - 10:29 AM.


#18 AnEverydayGuy   Members   -  Reputation: 172

Like
0Likes
Like

Posted 10 June 2014 - 11:57 AM

More questions, yay.

 

I'm looking for a way to efficently implement 'nodes'. 'Nodes' being nodes in Ash, or Aspects in Artemis; that is to say, they are a collection of components an entiy must have for a system to affect said entity. EG: The movement system affects entities with position and velocity, so entities with those components have a 'movement' node which the movement system then effects.

 

 

 

Background:

So, my ES implementation is setup like so:

  • I have a World object that has an entity manager and a system manager.
  • The system manager keeps track of the various systems (that's about all I have right now, as I'm just starting to work on systems now).
  • My entity manager manages entities and their components. It has a hash that takes in a component name and returns a component manager. It also has another hash that takes in a component name and return's a component ID. A component manager manages its (one type of) component. Basically, it keeps it's component storage (an array) as densely packed as possible (to save memory) and translates a component ID to the actual component data structure. The end result is that entity #5 may have position #0 (which the position component manager may translate to be x=100, y=50) and velocity #8 (which the velocity manager may translate to be x=-3, y=10).

 

 

 

The problem:

I originally designed the component manager as I did to keep the array densly packed to save memory and to speed up system execution. However, system execution is now complicated because the components that belong to an entity can be spread throughout the various component arrays (as seen above). This means, as it stands, the movement system can't take velocity at index 1 and apply it to the position component at index 1 because they can belong to different entities.

 

However, I really like the space savings offered by my current implementation of my component manager. If I have 3,000 entities and each entity only has 3 components, then, on average, each array is 1,000 big rather than the more naive each array is 3,000 big (as an example, I'm just throwing out numbers).

 

 

 

My solution:

The solution I've come up with is to implement 'nodes', data structures that contain components and have a one-to-one relationship with systems. EG: The movement system requires movement nodes, that contain the position and velocity components; the render system requires render nodes, that contain position and sprite components; etc.

 

Every time an entity is created or changed (components added/removed) a 'updateNodes' function is called that will update the nodes belonging to that entity. This means if an entity has a position, it does not have a movement node (requires position and velocity); however, when the entity has a velocity component added, a movement node is created which is then used in the movement system. Likewise for velocity being removed, the movement node is removed/destroyed and is no longer affected by the movement system.

 

Components in a node are pointers. This way if a component is altered (such as by the movement system), the component data is altered and is correct for all the other nodes that use that component (such as the render node, which is used by the render system and has the updated position value).

 

The problem I have with this potential approach is that it destroys caching. No longer can systems run along an array and update components and have prefetching work (for lack of a better term), because of the indirection I am now jumping around in memory and have lost a key aspect of Entity Component Systems.

 

To get around that, I could have nodes have a copy of the data; but now I run into the problem of 'what if a system changes a node's component, it's no longer the same for the other nodes that use the same component'.

 

 

 

So, as always, I'm curious as to what other people have done.



#19 Randy Gaul   Members   -  Reputation: 437

Like
0Likes
Like

Posted 10 June 2014 - 07:39 PM

Hi there, I'll try sharing a little bit of experience I've had. Worrying about prefetching and cache coherency isn't really all that helpful for hobbyists. Generally bottlenecks for newer game developers come in the form of using graphics APIs poorly (draw calls usually), or using an N^2 collision detection broadphase, and one of these is a non-issue if Box2D (or Bullet) is used. If these two thing are taken care of many 2D games for PC can implemented in C++ in a pretty memory naive way before seeing any problems. I've seen some impressive looking 3D games come out of my university with fairly naive memory implementations.

 

So while it's fun to read popular blog posts about ECSs, the practicality of making an entire game engine with just components and entities gets pretty silly. Usually people end up using Box2D for physics, and this library for that. In the end a lot of components just end up as simple wrappers for pre-existing libraries anyway.

 

Usually the interesting parts of component based architecture are the ease of data driving and serializing things. Editors and the like become very game design friendly, and iteration times get pretty low. These aspects don't have much to do with performance, and usually middle-ware or libraries will have their own internal optimizations anyway.

 

Luckily I decided to pop into this forum for the first time today as I actually just finished writing an article you can take a look at for some further reading (it really just expounds upon what I've said here): http://www.randygaul.net/2014/06/10/sane-usage-of-components-and-entity-systems/


Edited by Randy Gaul, 10 June 2014 - 07:43 PM.


#20 AnEverydayGuy   Members   -  Reputation: 172

Like
0Likes
Like

Posted 11 June 2014 - 09:48 AM

I'm not actually worried about efficiency, it's simply a problem I came across and what curious as to what other's have done to remedy the situtation.

 

The reason I am implementing my own solution and not using a framework such as Artemis, is that I am learning about ES/ECS. I have a much better understanding of something when I implement it so that when I use it I know what is going on in the background; or so I can make a more informed decision between frameworks; or any number of situations that I could find myself in where that understanding could be helpful.

 

So, while I may not be worried about efficiency, this is still a 'design' decision that can have serious repercussions down the line (if this were a real framework that I were to use). As such, I'm curious to what other's that done to provide a broader understanding; after all, someone could have thought of a solution that I never would have thought of.


Edited by AnEverydayGuy, 11 June 2014 - 09:49 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS