Правильный способ справиться с уничтожением игровых объектов

10

Представьте себе игровой мир, в котором множество и все сущности загружаются динамически, я мог бы представить это как список сущностей, но как насчет их удаления?

Хотя при добавлении я мог отодвигать новую сущность, мне может потребоваться удалить ее в любом месте контейнера. Чтобы избежать поиска элемента, чтобы найти его позицию для удаления, какой выбор у меня есть?

Я подумал, что мог бы сохранить идентификатор объекта как его положение в контейнере, создавая путь для прямого удаления, но разве это не вызвало бы своего рода «беспорядок» взаимозависимости?

Я знаю, что правильный путь будет что-то вроде List.RemoveAt (whereToRemove); но что, если только сущность знает, когда она должна умереть?

Или я просто что-то упустил, и контейнер списка будет знать, когда объект разрушен, и уменьшит свой собственный размер?

Гримшоу
источник

Ответы:

10

Вот ваши условия:

  • Другие объекты могут по-прежнему зависеть от вашего удаленного объекта, после того как он удален.

  • Вы хотите, чтобы только объект указывал свое собственное удаление.

Вы не можете иметь оба. Почему? Поскольку код на более высоком уровне, чем сама ваша сущность (см. Примеры ниже), решает, когда эту сущность нужно использовать. Следовательно, только код на том же уровне может определить, подходит ли ваша сущность для удаления или нет.

Однако может случиться так, что объект может запросить собственное удаление, запустив событие, которое ожидает код более высокого уровня. Этот более высокий уровень затем сохраняет этот запрос на удаление в списке.


Пример 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. Не бойтесь искать в своем основном списке, чтобы сделать отдельные удаления. Это неотъемлемая часть управления сущностями, и даже массивные списки, как правило, очень быстро пересекаются - в конце концов, для этого они и созданы.

инженер
источник
0

Вы определенно ищете HashMap / HashTable . Хеш-таблица - это карта, которая соответствует ключу определенного значения. Ключ может быть любым (например, идентификатором сущности).

Setheron
источник
0

Я думаю, вы могли бы использовать идею smartpointer для обработки освобождения для вас, в этом случае не будет необходимости хранить список всех сущностей внутри вашего кода.

в некоторых случаях вам нужен список для перебора всех объектов в вашей игре. этот список может быть просто списком ссылок, где вставка и удаление объектов из него займет ровно O (1) времени.

даже для увеличения скорости вы можете использовать статический массив (возможно, вектор). в этом случае вам нужно будет отслеживать 2 связанных списка внутри одного вектора, один будет перебирать допустимые объекты, а другой - свободные объекты. всякий раз, когда smartpointer помечает место, которое нужно удалить, вы просто удаляете этот указатель и добавляете его место в список свободных мест. и всякий раз, когда вы добавляете какую-либо сущность, вам нужно только сначала удалить свободное пространство, заполнить его указателем сущности, а затем добавить в список допустимых объектов.

Ali1S232
источник