1

我有一个实体组件系统,可以让我制作自定义实体并在运行时组装它们的功能。这个过程包括创建新的实体实例,然后向它们添加组件实例。缺点是现在每次想修改对象的X坐标都需要做,obj.GetComponent<TransformComponent>().X很丑。

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

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

还有其他明智的选择吗?

4

2 回答 2

2

今年早些时候我为此写了一个解决方案:Components and ComponentEntities

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

// 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); }

ComponentEntities 项目包含将自身作为组件添加到自身或添加到它们的实体的集合,以避免全局单例。如果您想要一个带有 Components 和 ComponentsTest(使用示例)项目的 VS 解决方案,请克隆bundle 存储库。

组件的许可证是 LGPL,到目前为止我还没有获得 ComponentEntities 的许可证(我刚刚将存储库设置为公开),但是如果你需要的话,你可能可以在大约 10 分钟内写出我上面写的东西。

于 2013-10-11T11:30:26.977 回答
0

你可能可以用 DynamicObject 做这样的事情。

http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

这是一个例子:

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;
}
于 2013-10-11T09:28:07.320 回答