美文网首页Entitas Cookbook
Entitas CookBook 翻译 - 108_reacti

Entitas CookBook 翻译 - 108_reacti

作者: SkyrimWu | 来源:发表于2018-04-24 17:39 被阅读0次

    Reactive System 响应式系统

    Reactive System是一个当有需要我们处理Entity才会被调用的system。Reactive System在内部使用了一个Collector的实例来实现(更多的信息可以查看Collector这个章节)。你需要继承ReactiveSystem这个抽象类来使用它,下面是一个MatchOne里面的ReactiveSystem例子:

    using System.Collections.Generic;
    using Entitas;
    
    public sealed class DestroySystem : ReactiveSystem<GameEntity> {
    
        public DestroySystem(Contexts contexts) : base(contexts.game) {
        }
    
        protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context) {
            return context.CreateCollector(GameMatcher.Destroyed);
        }
    
        protected override bool Filter(GameEntity entity) {
            return entity.isDestroyed;
        }
    
        protected override void Execute(List<GameEntity> entities) {
            foreach (var e in entities) {
                e.Destroy();
            }
        }
    }
    

    这个系统是用于销毁那些用DestroyedComponent标记的Entitiy。你能看到我们在GetTrigger方法中返回了一个监测了DestroyedEntity的Collector。在context.CreateCollector(GameMatcher.Destroyed) 中,我们不需要指定当一个Entity何时应当被收集的事件,因为默认就是会收集在Added情况下被通知到的Entity。所以当我们增加一个Destroyed组件到一个Entity上时,这个Entity会添加Destroyed的group里面,并因此被对应的collector收集到对应的reactive system里面。

    响应式的系统就像执行式系统一样,会每隔一段时间或是在每一个Update中被触发,然而Execute(List<GameEntity> entities) 方法只会在收集器距离上一次Execute收集到新的Entity才会被执行。

    你可能会在猜想Filter方法是用于干什么的。就像之前在收集器章节提到的那样,如果一个Entity被收集器收集了的话,即时有些事件像是第一次事件的复原,这个Entity依然会保持被收集。在我们上面说到的例子中,我们收集所有被销毁的entity。所即使Destroyed组件别被移除了来复原被销毁这个状态,这个Entity已经会被收集着而且会传入Execute方法中,除非我们把它过滤掉。在Filter方法中,我们可以决定这个被收集的Entity是否可以被传入Execute方法。如果你你没有特殊的规范,你可以直接返回true,不然就像上面的例子,你应该检查收集到的entity是否依然拥有Destroyed组件。

    Careful with AnyOf based collector 小心使用AnyOf的收集器

    当你创建了一个观察基于AnyOf匹配器的组合的收集器时,你可能会得到一些意料之外的结果,就像你拥有组件AB,并且你有一个AnyOf(A,B)的组合。一个Entity只有当其中一个组件被添加的时候才会进入这个组合。当我们添加第二个组件时,这个entity因为已经在组合中了,所以不会触发Added事件而被收集到。你可能不是你想要的情况。一般来说人们会想看见不管哪个组件被添加这个Entity都要能被收集到。在这种情况下,你应该设置一个分别针对这两种组件的组合而不是使用AnyOf。这是在MatchOne中的例子:

    using System.Collections.Generic;
    using DG.Tweening;
    using Entitas;
    using Entitas.Unity;
    using UnityEngine;
    
    public sealed class RemoveViewSystem : ReactiveSystem<GameEntity> {
    
        public RemoveViewSystem(Contexts contexts) : base(contexts.game) {
        }
    
        protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context) {
            return context.CreateCollector(
                GameMatcher.Asset.Removed(),
                GameMatcher.Destroyed.Added()
            );
        }
    
        protected override bool Filter(GameEntity entity) {
            return entity.hasView;
        }
    
        protected override void Execute(List<GameEntity> entities) {
            foreach (var e in entities) {
                destroyView(e.view);
                e.RemoveView();
            }
        }
    
        void destroyView(ViewComponent viewComponent) {
            var gameObject = viewComponent.gameObject;
            var spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
            var color = spriteRenderer.color;
            color.a = 0f;
            spriteRenderer.material.DOColor(color, 0.2f);
            gameObject.transform
                      .DOScale(Vector3.one * 1.5f, 0.2f)
                      .OnComplete(() => {
                          gameObject.Unlink();
                          Object.Destroy(gameObject);
                      });
        }
    }
    

    在这个响应式系统中,当我们移除Asset组件或者添加Destroyed组件到Entity上时,我们会移除掉这个Entity的视图,

    然而这种解决方案也有要注意的地方。虽然收集器可以设置多个组合,但是这些组合必须基于同一个上下文中的组件。所以当你需要设置一个响应式系统收集来自不同上下文的Entity时,你需要扩展MultiReactiveSystem类来达到这个目的。在这个类中GetTrigger方法会返回一组收集器。

    相关文章

      网友评论

        本文标题:Entitas CookBook 翻译 - 108_reacti

        本文链接:https://www.haomeiwen.com/subject/ufnjlftx.html