Как Factorio умудряется работать без лагов с таким числом элементов на экране
Магия и никакого ECS.
Разработчик Factorio поделился некоторыми подробностями работы внутренних систем, в частности, рассказал про ECS.
Большая часть игры не использует никакого подобия entity component system. ECS отлично подходит, когда нужно применить некоторое преобразование к набору данных независимо от каких-либо других переменных. К примеру, добавить вектор движения к текущей позиции. Но если у вас 5-10 переменных связаны со сменой позиции, то толку от ECS не будет.
Примером этого являются логистические и строительные роботы. У них есть много разных условий:
- Хватит ли энергии у робота, чтобы совершить полное движение?
- Вышла ли цель за пределы зоны логистической сети, и робот должен отменить задание, которое ему было приказано?
- Есть ли вообще у него работа, которую он должен выполнять, или он просто ждёт команды?
Общая проблема такова: все эти проверки используют данные, характерные для логистических роботов. Если бы робот использовал «компонент положения/движения», этот компонент не имел бы понятия ни об одном из этих условий. Можно попытаться включить эти условия в сам компонент, но он вряд ли будет очень читабельным и, вероятно, будет не очень по производительности.
Боевая система использует два вида снарядов: хитсканы и проджектайлы.
Для отрисовки логика прогоняет видимую область экрана в несколько потоков, находя, что нужно отобразить, и собирая информацию, которая позже отправляется на GPU.
Основные моменты, благодаря которым в Factorio всё хорошо с производительностью:
- Система быстрого сна/пробуждения, когда сущностям не нужно выполнять работу. Когда объект «засыпает», то он полностью исключается из цикла обновлений, пока что-то внешнее снова его не включит. Время сна/пробуждения O(1). Большинство вещей большую часть времени в ожидании изменения состояния. Например: если в сборочной машине заканчиваются ингредиенты, она просто выключается. Как только что-то добавляет ресурсы, действие помещения предметов в инвентарь уведомляет машину о том, что они были добавлены, что «пробуждает» машину.
- В худшем случае никакая часть логики обновления не может превышать O(N); если обновление 5 000 машин занимает 1 миллисекунду, то 10 000 должно занять максимум 2 миллисекунды. В идеале менее 2 миллисекунд, но это редко возможно.
- Уменьшение работы с кусками оперативки, которые необходимо тыкать каждый тик. Процессоры очень быстрые в наши дни, и основными ограничителями в большинстве игр-симуляторов являются загрузка памяти в CPU и выгрузка обратно в ОЗУ.
Касательно пробуждения/засыпания, используют свою реализацию doubly linked circular intrusive list:
- Обновляемые объекты сами по себе являются нодами в списке, поэтому ноды не нужно аллоцировать или освобождать при добавлении или удалении объекта из списка.
- Поскольку это двусвязный список, объект может за константное время проверить, прилинкован ли он в данный момент, и может за константное время отлинковать себя (взять предшествующую ноду и линкануть на следующую, взять следующую и линкануть на предыдущую, а себя в nullptr).
- Поскольку список является закольцованным, «конец» всегда является самим списком, что означает, что вы можете добавлять и удалять во время итерации и всегда будете знать, когда дошли до конца.
Тестирование показало, что итерация связанного списка не медленнее, чем итерация вектора указателей.
Комментарий недоступен
Комментарий недоступен
Комментарий недоступен
Комментарий недоступен
Тебе не надо снова устанавливать факторио, если её не удалять.
Нет ты пойдешь в мультиплеер с дтф-чанами