Sign in to follow this  
GroZZleR

Unity Object Creation with Data-Driven / Component-Based Entities?

Recommended Posts

GroZZleR    820
Hey all, I've been doing some reading lately and noticed the new trend towards component-based entities and I definitely see the power behind making the switch. I have a lingering question though: How are the objects created? Say you define your entities as such (ala Trefall)
<object type="Robot">
  <components>
    <component>Examine</component>
    <component>Movement</component>
  </components>
  <properties>
    <property name="Description">It's a useless robot!</property>
    <property name="MovementSpeed">50.0</property>
  </properties>
</object>
You can't possibly parse the XML every time you want to create a new entity. The only thing that pops into my head is that you create a list of all possible entities with their base values and then deep-copy / clone those entities as you need to create new ones? This could become a problem with very large games though. Re-using entities also becomes a problem, but I imagine you could just store the original values and a reset() method goes back and changes them all? Any insights?

Share this post


Link to post
Share on other sites
chlerub    855
I too have been working on component based entities.
The way i handle this atm is through an intermediate object.
The XML is parsed into an intermediate data graph, which is basically a treemodel in the form of simple name/value pairs.

You can create this graph from either an object or from XML, and the graph can return an instance of the object or translate back to XML.

This is also how i handle deep copies. I first create the graph from the orig. object and then use it to return an instance.

With a little bit of work this could be used to persist the graph and incorporate it into a network layer or field based replication in an object database.

There are other benefits of this, for example handling circular references and reference sharing (both in the XML and in the graph).

Share this post


Link to post
Share on other sites
jyk    2094
Quote:
The only thing that pops into my head is that you create a list of all possible entities with their base values and then deep-copy / clone those entities as you need to create new ones? This could become a problem with very large games though.
This is basically what I do.

What sort of problems would you run into using this method for larger games? (I'm not saying there wouldn't be any - I'm just curious as to what sort of problems you have in mind.)

Share this post


Link to post
Share on other sites
Stani R    1070
Quote:
Original post by GroZZleR
I've been doing some reading lately and noticed the new trend towards component-based entities


This new trend is already around eight years old :D

Quote:
Original post by GroZZleR
The only thing that pops into my head is that you create a list of all possible entities with their base values and then deep-copy / clone those entities as you need to create new ones?


Pretty much exactly what I do. When I read in entity definitions, or "templates", I add them to a cache. When I need an entity, I deep-copy the template's components, but I give the new entity an empty property list which points to the original template's property list, thus making it possible to "inherit" properties and avoid property duplication. When an entity is asked for a property that doesn't exist in the list, it will ask the parent list if there is one.

Quote:
Original post by GroZZleR
This could become a problem with very large games though.


Only problem I can think of would be storage space for all the referenced data, such as textures and models. However, you can just lazy load expensive data like that. Currently I use proxy objects to load textures when they are first used, and will likely also do that for mesh data later on. If even keeping all the templates in memory is too expensive, you can also defer loading of templates themselves.

Share this post


Link to post
Share on other sites
GroZZleR    820
Looks like cloning is probably the way to go -- in hindsight I suppose keeping a few extra unused entities of a few kilobytes isn't such a big deal.

Thanks guys.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by GroZZleR
Looks like cloning is probably the way to go -- in hindsight I suppose keeping a few extra unused entities of a few kilobytes isn't such a big deal.

Thanks guys.


Especially if you compare the sizeof() an entity instance to, say, the length of the file that specified it. :)

Share this post


Link to post
Share on other sites
thefries    103
Making a clone of an entity doesn't sound like a good idea to me. The proper way to do this is using that good old idiom, instancing. Your xml file there defines an entity "Base" which contains everything about how that entity looks, acts, animates, sounds, etc. Then you create entity instances of that base. each instance doesn't need to store what models, sounds, etc. it uses, it just stores a pointer to the base object, and then has access to any information that it needs. The entity will also have to store any instance data that the base's components require. For example, if you have a "world object" base-component in the base type, then the entity needs a "world object instance" instance-component, which will store the current position of that entity instance.

So your entity has a component instance hierarchy that looks the same as the base, for every base component in the entity base, there is the equivalent instance component in the entity instance and any instance state data goes into the instance components, and any descriptor data goes into the base components.

Hope this makes sense and is somewhat useful.

Share this post


Link to post
Share on other sites
AverageJoeSSU    564
Quote:
Original post by thefries
Making a clone of an entity doesn't sound like a good idea to me. The proper way to do this is using that good old idiom, instancing. Your xml file there defines an entity "Base" which contains everything about how that entity looks, acts, animates, sounds, etc. Then you create entity instances of that base. each instance doesn't need to store what models, sounds, etc. it uses, it just stores a pointer to the base object, and then has access to any information that it needs. The entity will also have to store any instance data that the base's components require. For example, if you have a "world object" base-component in the base type, then the entity needs a "world object instance" instance-component, which will store the current position of that entity instance.

So your entity has a component instance hierarchy that looks the same as the base, for every base component in the entity base, there is the equivalent instance component in the entity instance and any instance state data goes into the instance components, and any descriptor data goes into the base components.

Hope this makes sense and is somewhat useful.


You use somewhat vague wording on a crucial spot "then the entity needs a "world object instance" instance-component". you mean copy it?

I do what people say, except i am not deep copying raw data, only references to raw data (i have a feeling the other people in this thread are doing that too, one would hope).

Also, why are people saying that memcpy is a bad idea? its ridiculously fast, way faster than parsing an xml file. if you load an asset into a class, which describes what makes the object, then clone the asset and add things like position and create instances of things that the object needs on its own (like a collision actor).




Share this post


Link to post
Share on other sites
thefries    103
Quote:
Original post by AverageJoeSSU
I do what people say, except i am not deep copying raw data, only references to raw data (i have a feeling the other people in this thread are doing that too, one would hope).

Also, why are people saying that memcpy is a bad idea? its ridiculously fast, way faster than parsing an xml file. if you load an asset into a class, which describes what makes the object, then clone the asset and add things like position and create instances of things that the object needs on its own (like a collision actor).


You're contradicting yourself, if you're using memcopy that implies copying all the data, not just using a reference to the data.

This is kinda how I envision the data layout, except it would be more dynamic, using arrays of components instead of the way im doing it here. I'm not using arrays so that you can see exactly what the entity has in it in terms of components.

class cComponentBase
{

};

class cComponent
{
cComponentBase *mMyBase;
};

class cWorldObjectBase : public cComponentBase
{
cModel *mMyModel;
};

class cWorldObject : public cComponent
{
// implicit-> cComponentBase *mMyBase; <- tells you what model the object uses
cVec3 mMyPosition;
cOrientation mMyOrientation;
}

class cPhysicsBase : public cComponentBase
{
float mMyWeight;
};

class cPhysics : public cComponent
{
// implicit-> cComponentBase *mMyBase; <- tells you what the weight is
cWorldObject * mMyWorldObject; // physics component REQUIRES the entity to have a world object component.
cVec3 mMyVelocity;
cVec3 mMyAcceleration;
cVec3 mForces;
void Update ( ); // Updates position, velocity and acceleration for the entity
}

// this is an entity base that has a world object and physics components (usually more data driven than this - using arrays of components etc.)
class cEntityBase
{
cWorldObjectBase *mWorldObject;
cPhysicsBase *mPhysics;
}

// this is the matching entity instance
class cEntity
{
cEntityBase * mMyBase;
cWorldObject *mWorldObject;
cPhysics *mPhysics;
}




this is just the rough idea and nothing too specific, but should show you how i separate bases and instances. You make 1 entity base to describe a type of entity, and MANY entity instances of the same base. So you can make a base entity called "tree" and then have 1000 instances of that tree. This is a very simple example.

Share this post


Link to post
Share on other sites
jyk    2094
Quote:
Making a clone of an entity doesn't sound like a good idea to me. The proper way to do this is using that good old idiom, instancing. Your xml file there defines an entity "Base" which contains everything about how that entity looks, acts, animates, sounds, etc. Then you create entity instances of that base. each instance doesn't need to store what models, sounds, etc. it uses, it just stores a pointer to the base object, and then has access to any information that it needs. The entity will also have to store any instance data that the base's components require. For example, if you have a "world object" base-component in the base type, then the entity needs a "world object instance" instance-component, which will store the current position of that entity instance.

So your entity has a component instance hierarchy that looks the same as the base, for every base component in the entity base, there is the equivalent instance component in the entity instance and any instance state data goes into the instance components, and any descriptor data goes into the base components.
Are you talking about flyweights?

If so, I imagine that would be a reasonable approach, but for a project of modest scope, I don't know that cloning of prototypes in full is a 'bad idea', per se.

Keep in mind that we're not talking about anything silly like duplicating shared resources here; if a component of a prototype holds a reference to a resource (such as a texture, model, or sound effect), then any clone of that component will just get a copy of that reference.

Applying the flyweight pattern will most likely make for a more complex implementation. As for whether there are measurable gains to be had (e.g. memory savings), I imagine that depends on multiple factors, such as how many entities are generally active at one time, and, on average, how much of the data for a single entity is 'static' and how much is 'dynamic'.

Anyway, in summary, I'm not entirely convinced that using flyweights (which I assume is what you're talking about here) is the only 'proper' solution to the problem. That's just my view of it though.

Share this post


Link to post
Share on other sites
AverageJoeSSU    564
I must not understand memcpy, because im copying an object that is full of pointers to data (render components and such)... and i would assume that those pointers would be copied and not the data they point to. (shallow copy instead of deep copy)

Honestly it looks like everyone is more or less talking about the same thing.

Share this post


Link to post
Share on other sites
thefries    103
Quote:
Original post by jyk
Are you talking about flyweights?

If so, I imagine that would be a reasonable approach, but for a project of modest scope, I don't know that cloning of prototypes in full is a 'bad idea', per se.


Yes, this is a type of flyweight. But if the project is large enough to warrant the complexities of a component based entity system, then I don't see the problem with using flyweights.

But this approach isn't only for memory efficiency; it helps to simplify and unify the data serialization process because everything becomes objects that you can tread equally, rather than objects that you have to treat differently, ie. with memcpy. When you're working with a data driven design, you don't usually want to treat any objects specially.

That said, you're probably right - the added complexities aren't worth the gain for a small project.

Share this post


Link to post
Share on other sites
thefries    103
Quote:
Original post by AverageJoeSSU
I must not understand memcpy, because im copying an object that is full of pointers to data (render components and such)... and i would assume that those pointers would be copied and not the data they point to. (shallow copy instead of deep copy)

Honestly it looks like everyone is more or less talking about the same thing.


Yes, you are correct, memcpy will only copy the references/pointers and not the data they point to. But from an OO point of view, you are better off passing your source object into the copy constructor of the newly cloned object.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this