问题描述
我目前正在开发一个“实体组件系统”变体,其中实体了解其组件。通常,您会访问以下组件:
var camera = myEntity.Get<Camera>();
问题是,我希望某些对象始终具有某些组件,并以类型和null安全的方式访问它们。而不是这样做:
if( !myEntity.Has<Camera>() )
myEntity.Add<Camera>();
var camera = myEntity.Get<Camera>();
我宁愿使用:
var entity = World.CreateEntityWith<Camera,Position,...>();
var camera = entity.Camera;
var position = entity.Position;
我唯一想到的方法是使用接口并像这样实现:
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>()!;
}
这显然有一些缺点。如果有人删除了该组件怎么办?如果再添加第二个怎么办?
您能想到一种更聪明的方式或方式来实现我正在尝试的目标吗?是通过组成而不是继承?
感谢您阅读:)
解决方法
我对整个事情的含义不是100%清楚。
如果仍然可以基于属性在类设计中找到泛型,为什么必须明确提及泛型?
除了相应的模式之外,如果只涉及要最初创建的属性的爆炸命名,那么您今天更愿意在C#中使用流畅的代码。
例如:
var world = World.Create().With<Camera>.With<Position>();
public World With<T>(you need something here?) where T :ISomeCommonality
{
YourAdd<T>();
return this;
}
,
这真的是ECS吗?通常,您的大部分系统根本不必遍历实体,而只需查询数据库中可用的所有摄像头组件(与它们关联的实体在很大程度上无关紧要)。
基于继承的解决方案与ECS的距离非常远,并且失去了许多好处,如您的问题中所证明的那样,例如删除这些组件时该怎么办。
如果绝对必须在大量代码中获取以实体开头的组件,那么我在设计中想到的最接近的事情是存储具有特定组件的实体列表。与其遍历所有实体以检查它们是否具有摄像机,不如遍历预先存储的,具有摄像机的实体列表。随着添加和删除摄像机组件,您可以使ECS管理和更新具有摄像机的实体的列表。