Search code examples
c#unity-game-engineobservableunirx

How to remove items from the observed list in C#


When I try to remove some elements of a list using the UniRx library, I'm getting the following error:

InvalidOperationException: Collection was modified; enumeration operation may not execute.

This is the code responsible of the removal:

Observable
    .EveryUpdate()
    .SelectMany(_ => _gameState.enemies)
    .Where(enemy => enemy.x > 5)
    .Subscribe(enemy =>
    {
        _gameState.enemies.Remove(enemy);
    })

One possible solution is to generate a new List as result of SelectMany, such as _gameState.enemes.ToList(), but I was wondering if there's an allocation-free alternative.

In case there is not, what other approaches are there while using observables to achieve this?


Solution

  • If I understand correctly the _gameState.enemies is actually a plain List of some enemy instances.

    I think you just overcomplicated it by chaining the subscription that way.

    To me it looks like RemoveAll would be your best option

    Observable.EveryUpdate().Subscribe(() => 
    {
        _gameState.enemies.RemoveAll(enemy => enemy.x > 5);
    });
    

    Update as to the comment:

    Since _gameState.enemies is a RectiveCollection<Enemy> you could indeed use (from https://stackoverflow.com/a/15277219/7111561)

    Observable.EveryUpdate().Subscribe(() => 
    {
        for (int i = _gameState.enemies.Count - 1; i >= 0; i--)
        {
            if (_gameState.enemies[i].x > 5)
            {
                _gameState.enemies.RemoveAt(i);
            }
        }
    });
    

    or have this as extension method of course