Table of Contents

灵活处理

本文档假定读者熟悉 ECS,请先查看用法。

在某些情况下,通过 EntityProcessor 处理组件可能过于死板——例如,你试图处理的组件无法共享同一份基础实现。

Stride.Engine.FlexibleProcessing.IComponent<TProcessor, TThis> 提供了与 EntityProcessor 类似的功能,但在组件类型上更加灵活, 本文档介绍这个特定接口的一些用法。

IComponent 接口需要两个类型参数,

  • TProcessor 是你的处理器类型。
  • 以及 TThis 是你的组件类型。

尽管后一个类型看起来多余,但它是确保你的处理器与你实现的类型兼容所必需的。

一个满足这些类型约束的简要示例如下:

public class MyComponent : StartupScript, IComponent<MyComponent.MyProcessor, MyComponent>
{
    public class MyProcessor : IProcessor
    {
        public List<MyComponent> Components = new();

        public void SystemAdded(IServiceRegistry registryParam) { }
        public void SystemRemoved() { }

        public void OnComponentAdded(MyComponent item) => Components.Add(item);
        public void OnComponentRemoved(MyComponent item) => Components.Remove(item);
    }
}

与 EntityProcessor 的主要区别在于, IComponent 不限于具体类型,你的处理器也可以基于接口工作:

// 在这里声明接口,它将作为处理器接收到的类型
public interface IInteractable : IComponent<IInteractable.InteractableProcessor, IInteractable>
{
    void Interact();
    public class InteractableProcessor : IProcessor
    {
        // 在这里处理每个 IInteractable
        // 为简洁起见,省略了方法实现
    }
}

// 现在任何实现 IInteractable 的组件都会由 InteractableProcessor 处理
public class Button : StartupScript, IInteractable
{
    public void Interact(){}
}
public class Character : SyncScript, IInteractable
{
    public void Interact(){}
    public override void Update(){}
}

更新处理器

Processors 默认不会收到任何更新,你需要实现 IUpdateProcessor 或 IDrawProcessor 接口才能收到更新:

public interface ISpecialTick : IComponent<ISpecialTick.Processor, ISpecialTick>
{
    void Tick();

    public class Processor : IProcessor, IUpdateProcessor
    {
        public List<ISpecialTick> Components = new();

        public void SystemAdded(IServiceRegistry registryParam) { }
        public void SystemRemoved() { }

        public void OnComponentAdded(ISpecialTick item) => Components.Add(item);
        public void OnComponentRemoved(ISpecialTick item) => Components.Remove(item);

        // 该 Update 的执行顺序,与其他 IComponent 处理器相比,数值越小越先执行
        public int Order => 0;

        public void Update(GameTime gameTime)
        {
            foreach (var comp in Components)
                comp.Tick();
        }
    }
}

性能

虽然更加灵活,但以接口而非具体类来处理组件可能会带来一些额外开销。 如果你编写的系统对性能敏感,应当研究在热路径中消除或减少虚调用的策略。