我所理解的Entitas——ReactiveSystem<Entity>(七)

在上一章已经可以通过IInitializeSystem系统在游戏中创建我们的实体了,但是还不能在Game视图看到任何东西。这一张我们通过ReactiveSystem系统将Entity上组件的数据和GameObject联系起来。

ReactiveSystem

ReactiveSystem和其他System不同的是它继承类而不是实现接口。Entitas为每个Context生成Entity类型,例如GameEntity,InputEntity。ReactiveSystem只对指定的Entity类型产生响应。但是同一种类型的Entity还是有很多,我们并不希望处理每一个,而是处理某些Component发生变化的Entity。所以ReactiveSystem必须重写三个方法GetTrigger(),Filter(),Execute()。

  • GetTrigger() 返回一个ICollector对象用来收集ReactiveSystem需要处理的那一部分Entity
  • Filter() 对ICollector返回的实体进行再一次检查确保被Execute()方法处理前已经添加了需要的Component。
  • Execute() 需要对Entity执行的逻辑

RenderSpriteSystem.cs ReactiveSystem

首先需要将SpriteComponent组件上图片名称赋值给SpriteRenderer。要实现这个功能我们使用IInitializeSystem系统也可以实现,但是之后我们还需要在按下键盘上左右键的时候切换图片,所以需要ReactiveSystem系。
RenderSpriteSystem将收集那些SpriteComponent发生变化的Entity,将图片赋值到SpriteRenderer。

    using Entitas;
    using System.Collections.Generic;
    using UnityEngine;

    /// <summary>
    /// RenderSprite系统
    /// </summary>

    public class RenderSpriteSystem : ReactiveSystem<GameEntity>
    {
        public RenderSpriteSystem(Contexts contexts) : base(contexts.game)
        {

        }

        protected override void Execute(List<GameEntity> entities)
        {
            foreach (var item in entities)
            {
                //为每个符合条件的Entity的SpriteRenderer赋值
                SpriteRenderer sr = item.view.gameObject.GetComponent<SpriteRenderer>();
                if (sr == null) sr = item.view.gameObject.AddComponent<SpriteRenderer>();
                sr.sprite = Resources.Load<Sprite>(item.sprite.value);
            }
        }

        protected override bool Filter(GameEntity entity)
        {
            //再次确定Entity是否有SpriteComponent和ViewComponent
            return entity.hasSprite && entity.hasView;
        }

        protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context)
        {
            // 创建一个ICollector用来收集所有SpriteComponent变化的GameEntity
            return context.CreateCollector(GameMatcher.Sprite);
        }

    }

RenderPositionSystem.cs ReactiveSystem

还需要一个RenderPositionSystem用来为那些PositionComponent发生变化的Entity刷新位置。

    using Entitas;
    using System.Collections.Generic;

    /// <summary>
    /// RenderPosition系统
    /// </summary>

    public class RenderPositionSystem : ReactiveSystem<GameEntity>
    {
        readonly GameContext _context;
        public RenderPositionSystem(Contexts contexts) : base(contexts.game)
        {
            _context = contexts.game;
        }

        protected override void Execute(List<GameEntity> entities)
        {
            foreach (var item in entities)
            {
                //为每个符合条件的Entity刷新位置
                item.view.gameObject.transform.position = item.position.value;
            }
        }

        protected override bool Filter(GameEntity entity)
        {
            //再次确定Entity是否有PositionComponent和ViewComponent
            return entity.hasPosition && entity.hasView;
        }

        protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context)
        {
            // 创建一个ICollector用来收集所有PositionComponent变化的GameEntity
            return context.CreateCollector(GameMatcher.Position);
        }

    }

RenderDirectionSystem.cs ReactiveSystem

最后还需要一个用来处理DirectionComponent,逻辑和上面的基本相同。只是在逻辑执行时因为我们让小熊转向就是将小熊的图片切换成对应朝向的图片的逻辑,
所以RenderDirectionSystem就是根据DirectionComponent的数据切换SpriteComponent的数据。然后就交由RenderSpriteSystem来处理图片切换的逻辑了。

    using Entitas;
    using System.Collections.Generic;
    using UnityEngine;

    /// <summary>
    /// RenderDirection系统
    /// </summary>

    public class RenderDirectionSystem : ReactiveSystem<GameEntity>
    {
        public RenderDirectionSystem(Contexts contexts) : base(contexts.game)
        {

        }

        protected override void Execute(List<GameEntity> entities)
        {
            foreach (var item in entities)
            {
                //为每个符合条件的Entity改变SpriteComponent数据
                string spritename = "";
                switch (item.direction.value)
                {
                    case DirectionComponent.EDirection.stand:
                        spritename = "monkey_stand";
                        break;
                    case DirectionComponent.EDirection.left:
                        spritename = "monkey_left";
                        break;
                    case DirectionComponent.EDirection.right:
                        spritename = "monkey_right";
                        break;
                    default:
                        break;
                }

                if (item.sprite.value != spritename) {
                    item.ReplaceSprite(spritename);
                }
            }
        }

        protected override bool Filter(GameEntity entity)
        {
            //再次确定Entity是否有DirectionComponent和ViewComponent
            return entity.hasDirection && entity.hasView;
        }

        protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context)
        {
            // 创建一个ICollector用来收集所有DirectionComponent变化的GameEntity
            return context.CreateCollector(GameMatcher.Direction);
        }

    }

最后不要忘了将我们新创建的三个系统添加到GameSystems中,并在GameController的Update()方法中每帧执行我们的系统

    public class GameSystems : Feature
    {
        public GameSystems(Contexts contexts) : base("Game Systems")
        {
        ...

            ///* -- Execute System -- */
            Add(new RenderPositionSystem(contexts));
            Add(new RenderDirectionSystem(contexts));
            Add(new RenderSpriteSystem(contexts));

        }

    }
public class GameController : MonoBehaviour
{
    ...
    void Update()
    {
        _systems.Execute();
        _systems.Cleanup();
    }
}

现在在编辑器中运行一下就可以在Game视图中看到小熊的

但是现在按键盘上任何案件小熊还不会有反应,但是我们可以在Hierarchy面板中选中这个Entity。然后调整DirectionComponent和PositionComponent的数值就可以看到小熊会有响应了。




总结: ReactiveSystem就是实时收集一些自己感兴趣的组件发生变化的Entity,并执行相应的逻辑。

猜你喜欢

转载自blog.csdn.net/u010020342/article/details/109898785
今日推荐