C# 隐藏组件系统的详细信息,并以通用方式为用户提供更优雅的界面

C# 隐藏组件系统的详细信息,并以通用方式为用户提供更优雅的界面,c#,entity,components,C#,Entity,Components,我有一个实体组件系统,它允许我创建自定义实体并在运行时组装它们的功能。此过程包括创建新实体实例,然后向其中添加组件实例。缺点是,现在每次我想要修改我需要做的对象的X坐标时,obj.GetComponent().X,这很难看 当然,我可以创建一个扩展实体并添加一些固定组件的类,然后以属性的形式为这些组件添加缩写,这样当我想要更改X坐标时,我只需要执行obj.Transform.X。如果没有更好的解决方案,这将是我的选择,但是,如果有一种通用的方法将这些速记添加到实体的任何子类中,我会更喜欢。例如,

我有一个实体组件系统,它允许我创建自定义实体并在运行时组装它们的功能。此过程包括创建新实体实例,然后向其中添加组件实例。缺点是,现在每次我想要修改我需要做的对象的X坐标时,
obj.GetComponent().X
,这很难看

当然,我可以创建一个扩展实体并添加一些固定组件的类,然后以属性的形式为这些组件添加缩写,这样当我想要更改X坐标时,我只需要执行
obj.Transform.X
。如果没有更好的解决方案,这将是我的选择,但是,如果有一种通用的方法将这些速记添加到实体的任何子类中,我会更喜欢。例如,我可以创建一个名为ITransformable的接口来定义Transform属性,但是每个类都必须包含该属性的相同实现,这是冗余的

我考虑的另一个选择是使用接口,但仅将其用作扩展方法的标记。然后,我可以在ITransformable上实现一个名为
Transform()
的方法,作为一个扩展方法来获得正确的组件。这样做的问题是,我不能将接口仅限于实体类,因此我无法访问扩展方法中的GetComponent方法,而且,
Transform().X
看起来仍然很难看。我可以做一些类型铸造,但它严重成为一个黑客


还有其他明智的选择吗?

您可能可以使用DynamicObject执行类似的操作

以下是一个例子:

using System;
using System.Collections.Generic;
using System.Dynamic;

class Program
{
    static void Main(string[] args)
    {
        dynamic ent = new Entity();
        ent.Components.Add(new Transform() { X = 5, Y = 8 });

        Console.WriteLine(ent.Transform.X);
        ent.Transform.X = 12;
        Console.WriteLine(ent.Transform.X);
        Console.ReadKey();
    }
}

class Entity : DynamicObject
{
    public List<Component> Components = new List<Component>();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        for (int i = 0; i < Components.Count; i++)
        {
            Component component = Components[i];
            if (component.GetType().Name == binder.Name)
            {
                result = component;
                return true;
            }
        }

        result = null;
        return false;
    }
}

class Component
{

}

class Transform : Component
{
    public float X;
    public float Y;
}
使用系统;
使用System.Collections.Generic;
运用系统动力学;
班级计划
{
静态void Main(字符串[]参数)
{
动态ent=新实体();
Add(newtransform(){X=5,Y=8});
Console.WriteLine(ent.Transform.X);
ent.Transform.X=12;
Console.WriteLine(ent.Transform.X);
Console.ReadKey();
}
}
类实体:DynamicObject
{
公共列表组件=新列表();
公共重写bool TryGetMember(GetMemberBinder绑定器,输出对象结果)
{
对于(int i=0;i
今年早些时候,我为此编写了一个解决方案:和

组件之间的关系通过带注释的属性和方法定义,如图所示:

ComponentEntities项目包含将自己作为组件添加到自己或添加到自己的实体的集合,以避免全局单例。如果您想要一个包含组件和组件ST(使用示例)项目的VS解决方案,请克隆

Components的许可证是LGPL,到目前为止我没有许可ComponentEntities(我刚刚将存储库设置为public),但是如果您需要,您可能可以在大约10分钟内编写与我上面所写内容等效的内容。

请尝试阅读此内容,以进一步了解如何不回答。也就是说:“根本无法回答问题的答案”:仅仅是一个指向外部站点的链接
// Link to component of type B through a property.
// The name doesn't matter.
[ComponentLink]
B B { get; set; }

// Called when components are added or removed.
// The parameter type acts as a filter.
[NotifyComponentLinked]
void Added(object o)
{ Console.WriteLine(this.GetType().Name + " linked to " + o.GetType().Name + "."); }
[NotifyComponentUnlinked]
void Removed(object o)
{ Console.WriteLine(this.GetType().Name + " unlinked from " + o.GetType().Name + "."); }

// Attaches to events in compenents of type D and E.
// Rewriting this with Lambda Expressions may be possible,
// but probably would be less concise due to lack of generic attributes.
//
// It should be possible to validate them automatically somehow, though.
[EventLink(typeof(D), "NumberEvent")]
[EventLink(typeof(E), "NumberEvent")]
void NumberEventHandler(int number)
{ Console.WriteLine("Number received by F: " + number); }