Skip to content

juanarzola/entitas-unirx-additions

Repository files navigation

Entitas UniRx Additions

Entitas is an excellent ECS framework that works with Unity. UniRx is a reactive programming framework for Unity. These are simple extensions that I wrote in order to be able to use UniRx's reactive programming with Entitas.

They wrap Entita's built in C# events for changes in entities and groups. They use generics to limit changes to a component type.

With the Entity observables, you can react to component changes in an entity instance. They include:

  • OnComponentAddedAsObservable<Component> - A Component was added on the entity instance
  • OnComponentReplacedAsObservable<Component> - A Component value changed in the entity (it was replaced by another component of the same type)
  • OnComponentRemovedAsObservable<Component> - A Component was removed.

Group observables are similar to the Entity observables: you can react to component changes, but you do so on groups of entities that match a query. This has the advantage that you don't need the entity instances for the reactive code, so you can do the setup up-front on System initialization before entity instances are available. They include:

  • OnEntityAddedAsObservable<Component> - On an entity within the group, a component of type Component was added
  • OnEntityUpdatedAsObservable<Component> - On an entity within the group, a component of type Component was replaced by a component of the same type.
  • OnEntityRemovedAsObservable<Component> - On an entity within the group, a component of type Component was removed.

Extended additions

Entity's OnAnyChangeObservable<Component> and Group's OnAnyEntityChangeObservable<Component>

The OnAny extensions create observables for combinations of additions, removals and replacements. They generate AnyEntityChangeEventArgs objects with the data of the addition, removal or replacement - whichever happened.

Typical usage

The Entity extensions can be used anywhere you have an Entity instance (Like the execute method of a reactive system):

public class StepperSystem : IReactiveSystem, IEnsureComponents {
    
    public TriggerOnEvent trigger { get { return matcher().OnEntityAdded();  }}
    public IMatcher matcher(){return Matcher.AllOf(Matcher.SteppedMover);}
    public IMatcher ensureComponents {  get {  return Matcher.View; } }

    public void Execute(List<Entity> entities) {	
        foreach (var e in entities) {
            StartStepperTimer(e);
        }
    }
    private void StartStepperTimer(Entity e){

        // Add a timer after the stepper component is added. Timer is removed whenever the component is removed or replaced by another one.

        Observable.Timer(new DateTimeOffset(), new TimeSpan(0,0,1))
            .TakeUntil(e.OnAnyChangeObservable<Stepper>())
            .Subscribe(timerCount => {
                var position = e.position;
                var deltaAmount = 1.0f;
                Vector3 delta = Vector3.zero;
                switch(e.stepper.direction){
                    case stepper.Direction.Left:
                    delta = new Vector3(deltaAmount, 0, 0);
                    break;
                    case SteppedMover.Direction.Right:
                    delta = new Vector3(-deltaAmount, 0, 0);
                    break;
                    case SteppedMover.Direction.Up:
                    delta = new Vector3(0, deltaAmount, 0);
                    break;
                    case SteppedMover.Direction.Down:
                    delta = new Vector3(0, -deltaAmount, 0);
                    break;
                }
                e.ReplacePosition(position.x + delta.x, 
                                    position.y + delta.y, 
                                    position.z + delta.z);                                    
            }).AddTo(e.view.gameObject);
    }
}

The Group extensions are useful as the setup code of Initialize systems (Within SetPool):

public class CleanupOrphanedEntitiesSystem : IInitializeSystem, ISetPool {
    
    public void SetPool(Pool pool){
        pool.GetGroup(Matcher.View)
            .OnEntityAddedAsObservable<View>()
            .Where(evt => evt.component.entityIsDestroyedWithGameObject)
            .Subscribe(evt => {	
                evt.entity.view.gameObject.OnDestroyAsObservable().Subscribe(_ => {
                    pool.DestroyEntity(evt.entity);
                });
            });
    }
    
    public void Initialize(){}
}

About

UniRx extensions for Entitas

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages