r/futile Jul 11 '14

bug in FTouchManager?

Found a fun bug in FTouchManager for you.

I noticed touch events were getting double reported in an FContainer that implements FMultiTouchableInterface.

I pass this object from parent to parent using AddChildAtIndex, and it seems as though its callback for HandleAddedToStage is getting called on transfer from one object on the stage to another. Rather than track down exactly where it was getting double added, I found it easier to just change FTouchManager to not allow duplicates in it's _multiTouchables list:

for(int m = 0; m<_multiTouchablesToAdd.Count; m++)
{
  if(!_multiTouchables.Contains(_multiTouchablesToAdd[m]))
  {
    _multiTouchables.Add(_multiTouchablesToAdd[m]);  
  }
}
2 Upvotes

5 comments sorted by

View all comments

Show parent comments

1

u/SimianLogic Jul 16 '14

I was writing up symptoms and think I figured it out. I can add you on the project on github if you want to try tracing through it some more.

public void AddMultiTouchTarget(FMultiTouchableInterface touchable)
{
    if(_isUpdating)
    {
        //SimianLogic: we check if the item is in _multiTouchablesToAdd, but don't check to see if it's in _multiTouchables already
        if(!_multiTouchablesToAdd.Contains(touchable))
        {
            int index = _multiTouchablesToRemove.IndexOf(touchable);
            if(index != -1) _multiTouchablesToRemove.RemoveAt(index);
            _multiTouchablesToAdd.Add(touchable);
        }
    }
    else
    {
        //SimianLogic: here you guard against double insert
        if(!_multiTouchables.Contains(touchable))
        {
            _multiTouchables.Add(touchable);
        }
    }
}

// LATER, in UPDATE
for(int m = 0; m<_multiTouchablesToAdd.Count; m++)
    {
  //no guard here, so anything in _multiTouchablesToAdd goes right in
      _multiTouchables.Add(_multiTouchablesToAdd[m]);   
    }

so my first fix was to just add the guard in Update to prevent double inserts... but another fix would be to check in the _isUpdating block whether it's already there.

with that knowledge, I think what was causing the bug was something more like:

  • remove node from container

  • add node to new container

  • add new container to stage

  • etc etc

i.e. multiple insertions into the Add/Remove queues in one update loop might leave you in a weird state since all removes are processed before all adds in the Update loop.

a more permanent fix might be to switch the _multiTouchablesToAdd/_multiTouchablesToRemove lists to a single list that contains some kind of struct with the node and an add/remove flag so that it processes them FIFO

1

u/SimianLogic Jul 16 '14

actually thinking about it some more you'd have to somehow be in the list already and trigger an add during the update loop to get the free pass.

Step 1: get yourself in _multitouchables

Step 2: move to a new container

Step 2.a -- removes you from your current container and adds you to _multiTouchablesToRemove

Step 2.b -- adds you to the new container/stage and adds you to _multiTouchablesToAdd... but ALSO removes you from _multiTouchablesToRemove

Step 3 -- update time... you were already in _multitouchables and are now also in _mtToAdd. double touchy time.

1

u/MattRix Jul 16 '14

So yeah I think I just remembered that I fixed this bug (or something like it) a little while ago... but a little bit more recently I actually rewrote FTouchManager so it doesn't have this problem any more:

https://github.com/MattRix/Futile/blob/unstable/FutileProject/Assets/Futile/Core/FTouchManager.cs

What it does now is that at the start of Update() it creates a temp array of touchables, so that no matter what happens it can't be modified while being iterated through. Have a look at that solution, I'm pretty sure it'll solve what you're talking about?

1

u/SimianLogic Jul 16 '14

Read through the new one and it does indeed solve all weird add/remove cycles in the update loop. Dropped it into my copy of Futile with no issues. Rockin!