Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GroupEventType.OnEntityRemoved is also triggered when replacing a component #24

Closed
jraselin opened this issue Aug 12, 2015 · 4 comments
Closed
Labels

Comments

@jraselin
Copy link

Hi,

Below is the project configuration :

  • 2 components Position and PlayerSelectActionAttack
  • MonoBehaviour script AttackPointerController with 2 observers on Matcher.AllOf(Matcher.PlayerSelectActionAttack, Matcher.Position)
  • MonoBehaviour script AttackController to create / destroy the entity with the 2 components
  • Entitas System PlayerSelectActionAttackSystem with a group on Matcher.AllOf(Matcher.PlayerSelectActionAttack, Matcher.Position)

Position

public class PositionComponent : IComponent {
      public float x;
      public float y;
}

PlayerSelectActionAttack

public class PlayerSelectActionAttackComponent : IComponent {
}

AttackPointerController

public class AttackPointerController : MonoBehaviour {
    Vector3 position;
    GroupObserver onAdded;
    GroupObserver onRemoved;

    void Awake () {
        Pool pool = Pools.pool;
        Group group = pool.GetGroup(Matcher.AllOf(Matcher.PlayerSelectActionAttack, Matcher.Position));

        onAdded = group.CreateObserver (GroupEventType.OnEntityAdded);
        onRemoved = group.CreateObserver (GroupEventType.OnEntityRemoved);

        position = transform.position;
    }

    void Update(){
        foreach (Entity entity in onAdded.collectedEntities) {

            position.x = entity.position.x;
            position.y = entity.position.y;
            Debug.Log ("Show Attack Pointer Position To " + position);
            transform.position = position;
        }

        foreach (Entity entity in onRemoved.collectedEntities) {
            Debug.Log ("Hide Attack Pointer");
        }

    }
}

AttackController

public class AttackController : MonoBehaviour {
    Pool pool;
    Entity attackSelectedEntity;
    Toggle toggleView;


    void Awake () {
        toggleView = GetComponent<Toggle> ();
        pool = Pools.pool;      
    }

    public void onAttackCheckedValueChanged(){
        if (toggleView.isOn && attackSelectedEntity == null) {      
                attackSelectedEntity = pool.CreateEntity().IsPlayerSelectActionAttack(true).AddPosition(0,0);       
        } else if(attackSelectedEntity != null){
            Debug.Log("Destroy entity");
            pool.DestroyEntity(attackSelectedEntity);
            attackSelectedEntity = null;
        }
    }
}

PlayerSelectActionAttackSystem

public class PlayerSelectActionAttackSystem : IExecuteSystem , ISetPool {
    Group _group;

    public void SetPool(Pool pool) {
        _group = pool.GetGroup(Matcher.AllOf(Matcher.PlayerSelectActionAttack, Matcher.Position));
    }

    public void Execute() {
        foreach (Entity entity in _group.GetEntities()) {               
            Vector3 point = Camera.main.ScreenToWorldPoint (Input.mousePosition);
            entity.ReplacePosition (point.x, point.y);      
        }
    }
}

Expected behaviours

  1. User clicks on Attack button, AttackController is called ONCE and creates new Entity pool.CreateEntity().IsPlayerSelectActionAttack(true).AddPosition(0,0);
  2. AttackPointerController onAdded observer is updated with the created Entity and Console shows Show Attack Pointer Position To [Entity.position]
  3. PlayerSelectActionAttackSystem _group field is updated with the created Entity and entity position's is replace on each frame

Console Log

AttackPointerController onRemoved.collectedEntities must be empty but the console log shows :

Show Attack Pointer Position To (-1.3, -4.3, -4.1)
Hide Attack Pointer
Show Attack Pointer Position To (-1.3, -4.3, -4.1)
Hide Attack Pointer
Show Attack Pointer Position To (-1.3, -4.3, -4.1)
Hide Attack Pointer
Show Attack Pointer Position To (-1.3, -4.3, -4.1)
Hide Attack Pointer
...

It seems like observers ignores the GroupEventType and populate onRemoved = group.CreateObserver (GroupEventType.OnEntityRemoved); with the newly created entity

Another issue

When the Entity created in AttackController is destroyed (pool.DestroyEntity(attackSelectedEntity)), there are an Exception on AttackPointerController

EntityDoesNotHaveComponentException: Cannot get component at index 11 from Entity_2()
Entity does not have a component at index 11
Entitas.Entity.GetComponent (Int32 index) (at Assets/Lib/Entitas/Entity.cs:87)
Entitas.Entity.get_position () (at Assets/Sources/Generated/PositionComponentGeneratedExtension.cs:5)
AttackPointerController.Update () (at Assets/Scripts/AttackPointerController.cs:25)

Regards

@chrischu
Copy link
Contributor

The thing about groups (at least as far as I know) they do not really respond to the entity being added/removed but to each individual component.

So in your PlayerSelectActionAttackSytem you replace the position of the entity, therefore triggering all the groups again. In effect the replace triggers the remove event first (since the old position is removed) and then the add event (since the new position is added).

I hope that makes things a little bit clearer and helps you solve the problem.

@sschmid
Copy link
Owner

sschmid commented Aug 12, 2015

An entity is part of a group, when it fulfills the requirements of the matcher. In your case

Group group = pool.GetGroup(Matcher.AllOf(Matcher.PlayerSelectActionAttack, Matcher.Position));
onAdded = group.CreateObserver (GroupEventType.OnEntityAdded);
onRemoved = group.CreateObserver (GroupEventType.OnEntityRemoved);

an entity belongs to a group when it has a PlayerSelectActionAttackComponent and a PositionComponent.
Whenever you replace either of those it will be removed from the group (intentionally), because the idea is to remove the old component (=> entity doesn't match anymore) and the replace it with the new component (=> entity matches again). As a result e.ReplaceXyz will always trigger OnEntityAdded AND OnEntityRemoved

@sschmid
Copy link
Owner

sschmid commented Aug 12, 2015

Btw, AttackPointerController looks like it should be a ReactiveSystem rather than a MonoBehaviour. A ReactiveSystem is using a GroupObserver under the hood, so you don't have to mess with it. If you still want to use GroupObservers don't forget to call observer.ClearCollectedEntities()
You can get the most out of Entitas if you try putting all your logic into dedicated systems doing only one thing.

@jraselin
Copy link
Author

Thanks for yours responses

Now, I understand the concept of ReplaceComponent

You can get the most out of Entitas if you try putting all your logic into dedicated systems doing only one thing.

Ok, I will remove all UI Logic and create dedicated systems

Regards

@sschmid sschmid closed this as completed Aug 12, 2015
@sschmid sschmid changed the title Unity integration : GroupEventType.OnEntityRemoved is always fired even there is no Entity removed GroupEventType.OnEntityRemoved is always fired even there is no Entity removed Aug 23, 2015
@sschmid sschmid added question and removed invalid labels Aug 23, 2015
@sschmid sschmid changed the title GroupEventType.OnEntityRemoved is always fired even there is no Entity removed GroupEventType.OnEntityRemoved is also triggered when replacing a component Aug 23, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Archived in project
Development

No branches or pull requests

3 participants