Advertisement Jump to content
Sign in to follow this  
skwee

Component entity system - create from template

This topic is 1876 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

Hi there!

 

I'm trying to implement Entity component system and I'm stuck with defining templates for entities.

 

My components are simply PODs (C++ structs/classes with public parameters).

Entity is simply uint-s.

 

Now I could do something like (pseudo-code):

Entity e = world.createEntity();
e.attach(new Component1(..));
e.attach(new Component2(..));
..etc 

But instead I want to define entities outside of the game code, probably inside JSON file, something like:

dog.json 
{
  "components":
  { 
    "sprite": .., 
    "anitmation": .., 
    ..etc 
  } 
} 

And then in the game (or scripting engine in JS) do something like

world.createEntity("dog", position); 

To do this, I need to have some sort of "Entity template". A list of all possible entities with all their components and their components initial data.

So at my games loading phase, I load all the needed entities and create templates from them, and then I can clone each template into its own instance of the entity.

 

One solution I could do, is to store the JSON in memory, and then on world.createEntity("name"); re-parse the json and create new entity with components.

But this would be inefficient (I guess) if I'm going to create many entities. I want to avoid parsing the JSON every time I create an entity.

 

I'm looking for some design pattern in C++ that would allow me to parse the JSON once, and store the parsed data somehow so that any next call to createEntity("name") would simply clone the already existing entity with as lower overhead as possible.

 

Unfortunately there is no information about entity templates/definitions in the web so I'm asking your help!

 

Thanks!

Share this post


Link to post
Share on other sites
Advertisement


I'm looking for some design pattern in C++ that would allow me to parse the JSON once, and store the parsed data somehow so that any next call to createEntity("name") would simply clone the already existing entity with as lower overhead as possible.

If you're after OOP patterns, then the Factory and the Prototype are possibilities. The entity services are asked for a new entity of type "dog". The services looks up "dog" in its entity prototype cache. If it is found, then the entity is cloned and returned. Otherwise the JSON reader is invoked, or perhaps the reader was invoked once at initialization time to fill up the services' cache a-priorily. However, the reader gets a map with all known components. The keys to the map are obviously the components' names. The values are factories for the belonging components, or else itself prototypes to the components. The reader builds a new entity accordingly to the JSON prescription and returns it to the entity services which itself place the result as entity prototype in its cache.

Share this post


Link to post
Share on other sites

Artemis uses entity templates, I think. At least the c# port example (Star Warrior) does. I haven't looked too closely at the implementation so I can't say much about it, but that might be a decent start if you want to see what other people are doing.

Share this post


Link to post
Share on other sites

I would do it this way:

std::vector< std::unique_ptr<Component> > prototype;
// ... parse JSON and create/add components to prototype
// store prototype somewhere

// create an entity from prototype
Entity e = createEntity();
for( auto &comp : prototype )
{
   e.attach( comp->clone() );
}

For this approach your components need a virtual clone function. With the use of CRTP u can automatically create it:


class Component
{
public:
   virtual ~Component() { }
   virtual Component* clone() = 0;
};

template <class Derived>
class TComponent : public Component
{
public:
   virtual Component* clone()
   {
      return new Derived(static_cast<Derived const &>(*this));
   }
};

class Position : public TComponent<Position>
{
    ...
};

 

Share this post


Link to post
Share on other sites

Thanks for the replies!

 

haegarr

Thanks for mentioning the Prototype pattern! I learned something new today!

 

jms bc

Thanks, I heard about Artemis, and as far as I remember it is written in Java. Ill take a look into it.

 

simber

Thanks a lot! I've already though about clone method and CRTP.

 

However I'm still missing a link. Assuming my code is similar to what simber wrote (with the exception that I do not have Entity per se, its just a typedef to uint). 

In that case, assuming the code looks like this

Entity e = entitySpawner().spawn();
for(auto &comp: prototype) {
    entitySpawner.attach(e, comp->clone());
}

And assuming EntitySpawner knows about all the Component Systems, how do I register a component within a specific system?

In component based entity system, there are systems (or processes) that updates the components, I'm still not sure how I can introduce the needed components to the correct system in an elegant way.

 

Any solutions?

Edited by skwee

Share this post


Link to post
Share on other sites

The way I understand this type of actor component system is to have a map structure that accepts the string name of the component type and then accesses a factory function to return a new instance of that component (with specified parameters). 

 

So you would have a base type of "Component" and all your components would derive from this single type. Now you don't need to work with templates. Then your map would look like

map< String, Component>

This way you could just access them in your factory with some sort of function that only accepted a string.

Component* createComponent(string jsonString){
Component *comp = new map[jsonString.name];

//... extra stuff goes here for each different component

return comp; // return a pointer the a component and not the exact type of component
}

Share this post


Link to post
Share on other sites

EDIT: Err, where is the main part of my answer gone? Dammit! Half an hour gone down the drain...

 


In that case, assuming the code looks like this
Entity e = entitySpawner().spawn();
for(auto &comp: prototype) {
    entitySpawner.attach(e, comp->clone());
}
Edited by haegarr

Share this post


Link to post
Share on other sites


And assuming EntitySpawner knows about all the Component Systems, how do I register a component within a specific system?

In component based entity system, there are systems (or processes) that updates the components, I'm still not sure how I can introduce the needed components to the correct system in an elegant way.

 

You can explicitly add entities to systems like this (assuming Entity is just an identifier):

class System
{
public:
   void add(Entity e);

protected:
   std::vector<Entity> m_entities;
};

// update example
void MoveSystem::update(EntitySpawner& spawner)
{
   for( auto &e : m_entities )
   {
      Position& position = spawner.get<Position>(e);
      Velocity& velocity = spawner.get<Velocity>(e);
      position += velocity;
   }
}

Or you let the system query combinations of Components, no adding needed:

void MoveSystem::update(EntitySpawner& spawner)
{
   std::vector<Entity> entities = spawner.getEntitiesWithComponents<Position, Velocity>();
   for( auto &e : entities )
   {
      Position& position = spawner.get<Position>(e);
      Velocity& velocity = spawner.get<Velocity>(e);
      position += velocity;
   }
   
}

I used EntitySpawner here like you did , which may not be the best name for what it does.

 

These are only two incomplete examples, there are dozens of design possibilities for components and systems. For the second approach I can suggest to have a look at entityx .

Share this post


Link to post
Share on other sites

Thanks for the examples and reference to entityx (which I already checked), simber. However, it still doesn't fix my issue: How components are stored inside the spawner (or whatever we call it)?

 

Going back to your previous example

Entity e = spawner.spawn();
for( auto &comp : prototype )
{
   spawner.attach(e, comp->clone());
}

Lets continue with spawner, even though the name is incorrect and Ill probably add another class that will be responsible for storing the components.

 

First of all, how would attach() be implemented?

Second of all, how would getEntitiesWithComponents<X, Y ..>() be implemented?

 

I'm pretty weak with templates this why I ask.

 

[Edit]

I looked a bit into entityx. I see how they implement the component storage. They provide a family for each component. This is an elegant solution, you then can store all components in one list, instead of separating each component into its own list. What do you think about this approach?

 

Thanks a lot!

Edited by skwee

Share this post


Link to post
Share on other sites

For sure there are many ways of implementing a CES...

 

... but IMHO there is a design flaw in the above concept. A (so far) unknown object asks the spawner to spawn a new entity which seems to be just a UID. The spawner is hence a generator for UIDs. The said unknown object then iterates the component prototypes which are obviously already restricted to those belonging to the requested kind of entity. This iteration triggers cloning of the prototypes, and invokes the UID spawner to attach them to the entity. The "UID generator" is then responsible to drive the component collection?!

 

Another thing is this: Before going any deeper in code, you have to tell / decide how the entire system should work. Do you have an explicit collection of components that make up an entity? OP's statements "Entity is simply uint-s" and "Entity e = world.createEntity(); e.attach(new Component1(..));" contradict themselves. You said also that components are just data containers, and sub-systems are responsible for updating them. That allows the component instances to be stored with the belonging sub-systems instead of in entity oriented collections. Your question "how do I register a component within a specific system?" points in this direction. However the code snippets with "MoveSystem::update(EntitySpawner& spawner)" points to something else.

 

Obviously, how components are updated depends heavily on whether the one or other (or third) concept is chosen.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!