Polymorphism with Entity Component Systems in C#

632 views Asked by At

I am currently developing an Entity Component System variant where entities know about their components. Usually you access components like this:

var camera = myEntity.Get<Camera>();

The problem with this is, I want some objects to always have certain components and access them in a type and null safe way. Instead of doing this:

if( !myEntity.Has<Camera>() )
    myEntity.Add<Camera>();
var camera = myEntity.Get<Camera>();

I'd rather use:

var entity = World.CreateEntityWith<Camera,Position,...>();
var camera = entity.Camera;
var position = entity.Position;

The only way I could think of was using interfaces and implementing this like:

public interface ICameraHoldingEntity
{
    Camera Camera { get; }
}

public interface IPositionHoldingEntity
{
    Position Position { get; }
}

public class CameraEntity 
    : Entity, ICameraHoldingEntity, IPositionHoldingEntity
{
    public World World { get; }

    public CameraEntity( World world )
    {
        World = world;
        Add<Camera>();
        Add<Position>();
    }

    public Camera Camera => Get<Camera>()!;
    public Position Position => Get<Position>()!;
}

This obviously has some drawbacks. What if somebody removes this component? What if a second one is added?

Can you think of a more clever way or pattern to achieve what I am trying to do? Rather by composition than by inheritance?

Thank you for reading : )

2

There are 2 answers

2
PeterLiguda On

I am not 100% clear about the meaning of the whole thing.

Why do the generic types have to be mentioned explicitly, if they can be found in the class design anyway based on the properties?

Apart from a corresponding pattern, you would rather use a fluent code in C# today, if it is only about the exploded naming of the properties to be created initially.

ex:

var world = World.Create().With<Camera>.With<Position>();

public World With<T>(you need something here?) where T :ISomeCommonality
{
   YourAdd<T>();
   return this;
}
3
AudioBubble On

Is this really an ECS? Typically the bulk of your systems should not have to go through entities at all, and instead, just query all camera components available in the database (the entities associated with them should largely be irrelevant).

The inheritance-based solution is moving very, very far from the ECS, and loses many of its benefits as exemplified in your questions like what to do if such components are removed.

The closest thing I can think of to do in your design if you absolutely have to fetch components starting with an entity in a whole lot of code is to store lists of entities that have particular components. Instead of iterating through all entities checking to see whether they have a camera, iterate through the list of entities stored in advance that are guaranteed to have a camera. And you make your ECS manage and update those lists of entities that have a camera as camera components are added and removed.