Вот ваши условия:
Другие объекты могут по-прежнему зависеть от вашего удаленного объекта, после того как он удален.
Вы хотите, чтобы только объект указывал свое собственное удаление.
Вы не можете иметь оба. Почему? Поскольку код на более высоком уровне, чем сама ваша сущность (см. Примеры ниже), решает, когда эту сущность нужно использовать. Следовательно, только код на том же уровне может определить, подходит ли ваша сущность для удаления или нет.
Однако может случиться так, что объект может запросить собственное удаление, запустив событие, которое ожидает код более высокого уровня. Этот более высокий уровень затем сохраняет этот запрос на удаление в списке.
Пример 1: без событий
Вы проверяете столкновения между сущностями в вашем мире. Это обрабатывается выше, обычно в вашем основном игровом цикле, который проверяет каждую сущность против любой другой. В частности, в этом примере, когда объект сталкивается с другим, только внутренняя логика этого объекта может определить, какой ущерб он получил, и истек ли срок его действия. Итак, давайте следовать логике для столкновений, когда у вас есть четыре сущности в вашем мире, A, B, C и D. A - наша сущность, с которой мы имеем дело.
Мы проверяем A на столкновение с B. Есть столкновение. А получает урон 50%.
Мы проверяем A на столкновение с C. Есть столкновение. А получает урон 50%. Поскольку урон достигает 0, А определяет, что он "умер". Он удаляет себя из списка.
Мы проверяем A на столкновение с D. Не было бы никакого столкновения, но вы никогда не доберетесь до этого: вы получите исключение во время выполнения, потому что ваш список сущностей был изменен во время операции перемещения.
Пример 2: с событиями
Та же настройка, что и раньше.
Мы проверяем A на столкновение с B. Есть столкновение. А получает урон 50%.
Мы проверяем A на столкновение с C. Есть столкновение. А получает урон 50%. Поскольку урон достигает 0, А определяет, что он "умер". Он запускает событие в коде управления сущностью, чтобы сказать: «Убери меня как можно скорее». Код управления сущностью просматривает ссылку на сущность, отправленную как часть события, и сохраняет эту ссылку в списке сущностей, которые необходимо удалить.
Мы проверяем A на столкновение с D. Нет столкновения, и проверка работает просто отлично.
Теперь, в самом конце текущей итерации игрового цикла , просмотрите список сущностей, которые нужно удалить, и удалите каждую из них из списка основных сущностей.
Вы можете видеть, как это полностью исключает проблему. Вам не нужно использовать события, вы можете использовать сигналы или что-то еще, но принцип тот же - не удаляйте объекты, пока вы не можете безопасно это сделать. Обратная сторона этого подхода, чтобы сохранить вещи в чистоте и порядке, делает то же самое с добавляемыми сущностями - убедитесь, что вы сохраняете ссылки на них и добавляете их только в начале следующей итерации игрового цикла.
И наконец, не забывайте очищать списки удаления и удаления, каждый раз, когда вы используете их для добавления / удаления в основной список сущностей.
PS. Не бойтесь искать в своем основном списке, чтобы сделать отдельные удаления. Это неотъемлемая часть управления сущностями, и даже массивные списки, как правило, очень быстро пересекаются - в конце концов, для этого они и созданы.