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

本文关键字:用户 方式 界面 系统 组件 程度 隐藏 | 更新日期: 2023-09-27 18:34:54

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

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

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

还有其他理智的选择吗?

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

我在今年早些时候为此编写了一个解决方案: 组件和组件实体

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

// 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 项目包含将自身作为组件添加到自身或添加到其中的实体的集合,以避免全局单一实例。如果需要包含组件和组件测试(使用示例(项目的 VS 解决方案,请克隆捆绑存储库。

组件

的许可证是 LGPL,到目前为止我没有许可组件实体(我刚才将存储库设置为公共(,但如果您需要,您可以在大约 10 分钟内从我上面写的内容中编写等效的东西。

你可以用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;
}
相关文章: