Entitas源码分析-Context

Context(上下文)

Context在Entitas中可以理解为一个世界、场景,它存放了当前所有Entity,并负责对Entity进行管理。
一般情况下是通过在EntitasJenny菜单的Contexts配置项自动生成。先来看看自动生成的Context是什么样的:

自动生成的代码

public sealed partial class GameContext : Entitas.Context<GameEntity> {
    public GameContext()  : base(
            GameComponentsLookup.TotalComponents,
            0,
            new Entitas.ContextInfo("Game",
                GameComponentsLookup.componentNames,
                GameComponentsLookup.componentTypes
            ),
            (entity) =>

#if (ENTITAS_FAST_AND_UNSAFE)
                new Entitas.UnsafeAERC(),
#else
                new Entitas.SafeAERC(entity),
#endif
            () => new GameEntity()
        ) {}
}

我们可以看到自动生成的Context实际上是调用了Entittas中的Context的构造函数。
totalComponents: 当前这个context全部组件数量。 运行时通过这个数字来开辟相对应的内存。 为了提高效率可以使用 ContextAttribute 特性来让组件只在指定的context中可。
startCreationIndex: 开始创建 Context 中的 Entity 时的下标, 一般为0不用动
ContextInfo:主要用于表述当前Context的信息。
aercFactory: 产生引用计数对象的工厂函数
entityFactory: 产生Entity的工厂函数。 先是从内部的对象池中获取,如果没有可用的Entity则会调用这个函数来产生一个新的Entity

注意:这个类添加了partial关键字。 当对Component使用 Unique 特性后会生成对应的代码。 就可以在对应的Context上直接添加对应的组件,而不仅限于给Entity添加组件。

管理Entity

我们可以从生成的GameContext看到,生成的Entity也是自动生成的GameEntity。并且通过工厂函数的方式供内部使用。那么Context对Entity提供了哪些操作呢?

// IContext.cs
public interface IContext<TEntity> : IContext where TEntity : class, IEntity {
    TEntity CreateEntity(); // 创建
    bool HasEntity(TEntity entity); // 查询
    TEntity[] GetEntities(); // 获取所有Entity
    IGroup<TEntity> GetGroup(IMatcher<TEntity> matcher); // 查找对应分组下的所有Entity
}

查看源码可以知道实际上只提供了简单的创建和查询的功能。
注意:Context中管理Entity内容较少, 但是会向创建出来的Entity注册对应的事件。 处理entity创建、销毁等事件。同时Context也根据Entity的事件派发对应的事件。

EntityIndex 查询

另外有时有通过Entity中某些字段来快速查找到对应的Entity。 这个时候我们就需要使用EntityIndex功能来实现了。通过在组件上的字段添加 AbstractEntityIndexAttribute 特性让代码生成工具生成对应的代码:

// 在组件上设置
public class IdComponent : IComponent
 {
    [PrimaryEntityIndex]  // <<-- 看这里
    public ulong value;
}

// 代码生成 注册
public partial class Contexts {

    public const string Id = "Id";

    [Entitas.CodeGeneration.Attributes.PostConstructor]
    public void InitializeEntityIndices() {
        game.AddEntityIndex(new Entitas.PrimaryEntityIndex<GameEntity, ulong>(
            Id,
            game.GetGroup(GameMatcher.Id),
            (e, c) => ((IdComponent)c).value)
        );

    }
}

// 代码生成 查询
public static class ContextsExtensions {
    public static GameEntity GetEntityWithId(this GameContext context, ulong value) {
        return ((Entitas.PrimaryEntityIndex<GameEntity, ulong>)context.GetEntityIndex(Contexts.Id)).GetEntity(value);
    }
}

EntityIndex的原理是通过设置给它的group获取对应的Entity,同时注册gourp中entity添加删除的事件来保持数据同步。当需要查询时直接通过存储好的字典进行处理。

管理Components

实际上Component是添加在Entity上的,需要管理组件相关的内容只有一个组件对象池。 在创建Entity的时候将组件对象池及组件相关信息传入。所有的Entity公用对象池。对象池的声明如下:

readonly Stack<IComponent>[] _componentPools;

通过组件的下标可以快速的在数组中索引到对应的堆栈。其他的操作就是简单的拿取放回。

猜你喜欢

转载自blog.csdn.net/qq_36433883/article/details/129391538
今日推荐