首页 > 解决方案 > 使用结构的 ECS 中的组件实现

问题描述

目标:

我正在尝试实现一个实体组件系统,但我坚持使用我的组件实现。我打算有一个通用组件类型,其中包含每个组件的静态位,例如位置类型的组件有位 = 0,精灵类型的组件有位 = 1,等等。一个组件应该只包含它持有的值因此我从结构开始。以下是我对此的尝试(不工作的代码):

    struct Position : Component<Position> //this does not work in c#
    {
        public int x, y;
    }

    internal struct ComponentBit
    {
        public static int bitCounter = 0;

    };

    public struct Component<T>
    {
        public static readonly int bit;

        static Component()
        {
            bit = ComponentBit.bitCounter++;
        }

        public int GetBit()
        {
            return bit;
        }
    }

之后我发现无法继承结构,因此我尝试将结构更改为有效的类。

问题:

有没有办法像在 C++(模板)中那样使用结构来实现这些功能?出于以后的实现/性能原因,我想将它们保留为值类型而不是引用类型。

编辑1:

我想要的预期用途是:

Position pos = new Position(x, y);
int bit1 = pos.GetBit(); // or
int bit2 = Position.bit; // both should be possible

标签: c#genericsstatic-membersentity-component-system

解决方案


我的建议是不要尝试使用继承。

任何结构都是可能的有效组件,例如:

struct Position
{
    public int X, Y;

    public Position(int x, int y)
    {
        X = x;
        Y = y;
    }
}

现在,您仍然可以Component<T>作为 int 字典 ( Dictionary<Type, int>) 的类型工作。虽然,我会做最少的改变来完成这项工作:

internal static class ComponentBit
{
    public static int bitCounter = 0;

};

public static class Component<T>
{
    public static readonly int bit; // This is static, it has a value per type T

    static Component()
    {
        bit = ComponentBit.bitCounter++;
    }

    public static int GetBit()
    {
        // This method only accesses static members, it can be static
        // Thus, no instance of T is needed
        return bit;
    }
}

你会像这样使用它:

Position pos = new Position(x, y);
int bit1 = Component<Position>.GetBit();
int bit2 = Component<Position>.bit;

不知道为什么你想要两种方法来做到这一点,但你去了。


好吧,现在我将自由地做更大的改变......考虑到这一点,如果你想要类型推断,你可以这样做:

public static class Component
{
    internal static int bitCounter = 0;

    public static int GetBit<T>()
        where T : struct // We only accept structs here
    {
        return Component<T>.bit;
    }

    public static int GetBit<T>(this ref T value)
        where T : struct // We only accept structs here
    {
        // This is an extension method.
        // It will appear as a method on any valid T (which is all structs)
        // The type T will be infered from the instance.
        // Passing the struct as a reference to avoid a copy
        _ = value; // discard value
        return GetBit<T>();
    }
};

internal static class Component<T>
    where T : struct // We only accept structs here
{
    internal static readonly int bit;

    static Component()
    {
        bit = Component.bitCounter++;
    }
}

用法:

var pos = new Position(x, y);
var bit1 = Component.GetBit<Position>();
var bit2 = pos.GetBit();

是的,上面的代码编译并运行。在SharpLab中查看。

注意:我会考虑嵌套Component<T>Component.


推荐阅读