Wednesday, February 19, 2020

c# - What designs are there for a component based entity system that are user friendly but still flexible?


I've been interested in the component based entity system for a while, and read countless articles on it (The Insomiac games, the pretty standard Evolve Your Hierarchy, the T-Machine, Chronoclast ... just to name a few).


They all seem to have a structure on the outside of something like:


Entity e = Entity.Create();
e.AddComponent(RenderComponent, ...);
//do lots of stuff
e.GetComponent(...).SetPos(4, 5, 6);


And if you bring in the idea of shared data (this is the best design I've seen so far, in terms of not duplicating data everywhere)


e.GetProperty("Name").Value = "blah";

Yes, this is very efficient. However, it isn't exactly the easiest to read or write; it feels very clunky and working-against-you.


I personally would like to do something like:


e.SetPosition(4, 5, 6);
e.Name = "Blah";

Though of course the only way to get to that kind of design is back in the Entity->NPC->Enemy->FlyingEnemy->FlyingEnemyWithAHatOn kind of hierarchy this design tries to avoid.


Has anyone seen a design for this kind of component system which is still flexible, yet maintains a level of user friendliness? And for that matter, manages to get around the (probably the hardest problem) data storage in a good way?



What designs are there for a component based entity system that are user friendly but still flexible?



Answer



One of the things that Unity does is provide some helper accessors on the parent game object to provide a more user friendly access to common components.


For example, you might have your position stored in a Transform component. Using your example you would have to write something like


e.GetComponent().position = new Vector3( whatever );

But in Unity, that gets simplified to


e.transform.position = ....;

Where transform is literally just a simple helper method in the base GameObject class (Entity class in your case) that does



Transform transform
{
get { return this.GetComponent(); }
}

Unity also does a few other things, like setting a "Name" property on the game object itself instead of in its child components.


Personally I don't like the idea of your shared-data-by-name design. Accessing properties by name instead of by a variable and having the user also have to know what type it is just seems really error prone to me. What Unity does is that they use similar methods as the GameObject transform property within the Component classes to access sibling components. So any arbitrary component you write can simply do this:


var myPos = this.transform.position;

To access the position. Where that transform property does something like this



Transform transform
{
get { return this.gameObject.GetComponent(); }
}

Sure, it's a little more verbose than just saying e.position = whatever, but you get used to it, and it doesn't look as nasty as the generic properties. And yes, you would have to do it the roundabout way for your client components, but the idea is that all your common "engine" components (renderers, colliders, audio sources, transforms, etc) have the easy accessors.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...