Как проектировали Navigation Server для Godot 4.0
В 2020 году команда Godot описала новую архитектуру навигации для Godot 4.0. Материал помечен устаревшим: это разбор замысла, а не инструкция по актуальному API.
Мир собирался из регионов, которые можно добавлять и перемещать во время работы. NavigationAgent получал цель, возвращал следующую достижимую точку и перестраивал путь после изменения регионов, цели или движущихся препятствий. Навигационную сетку разрешалось пересчитать после добавления геометрии.
NavigationObstacle отмечал движущееся тело как препятствие и автоматически определял его размер, скорость и положение. Агент рассчитывал безопасную скорость с учётом препятствий. Статья Godot Engine «Navigation Server for Godot 4.0» показывает механизм на 3D-сцене; тот же подход автор предлагал для 2D.
В 2020 году команда Godot описала новую архитектуру навигации для Godot 4.0. Материал помечен устаревшим: это разбор замысла, а не инструкция по актуальному API.
Мир собирался из регионов, которые можно добавлять и перемещать во время работы. NavigationAgent получал цель, возвращал следующую достижимую точку и перестраивал путь после изменения регионов, цели или движущихся препятствий. Навигационную сетку разрешалось пересчитать после добавления геометрии.
NavigationObstacle отмечал движущееся тело как препятствие и автоматически определял его размер, скорость и положение. Агент рассчитывал безопасную скорость с учётом препятствий. Статья Godot Engine «Navigation Server for Godot 4.0» показывает механизм на 3D-сцене; тот же подход автор предлагал для 2D.
❤2
Как генерировать высоты и биомы карты с помощью шума
Red Blob Games показывает генерацию данных карты без отрисовки. Каждой координате присваивают значение шума от 0 до 1 и трактуют его как высоту. Слои с разной частотой смешивают крупные холмы с мелкими деталями, а возведение результата в степень опускает средние высоты и формирует плоские долины.
Если выбирать биом только по высоте, леса, пустыни и снег выстраиваются полосами. Второе поле шума задаёт влажность: вместе с высотой она позволяет распределять биомы разнообразнее.
В интерактивном разборе Red Blob Games есть C-подобный код, слайдеры и приёмы для островов, хребтов, террас и бесконечных карт. Пороги придётся подбирать под библиотеку шума и способ смешивания слоёв, зато базовый генератор данных карты укладывается менее чем в 50 строк.
Red Blob Games показывает генерацию данных карты без отрисовки. Каждой координате присваивают значение шума от 0 до 1 и трактуют его как высоту. Слои с разной частотой смешивают крупные холмы с мелкими деталями, а возведение результата в степень опускает средние высоты и формирует плоские долины.
Если выбирать биом только по высоте, леса, пустыни и снег выстраиваются полосами. Второе поле шума задаёт влажность: вместе с высотой она позволяет распределять биомы разнообразнее.
В интерактивном разборе Red Blob Games есть C-подобный код, слайдеры и приёмы для островов, хребтов, террас и бесконечных карт. Пороги придётся подбирать под библиотеку шума и способ смешивания слоёв, зато базовый генератор данных карты укладывается менее чем в 50 строк.
❤2
Как Binding of Isaac генерирует подземелья
Сначала генератор строит план на сетке 9×8, затем назначает особые комнаты и выбирает содержимое обычных. Стартовая комната попадает в очередь. Алгоритм проверяет четыре направления и с шансом 50% добавляет свободного соседа, если тот не создаст петлю.
Из тупиков выбираются специальные комнаты: босс получает одну из самых дальних от старта. Для секретной комнаты ищут пустую клетку рядом как минимум с тремя комнатами; после 300 и 600 неудачных попыток требования ослабляют.
Разработчику пригодится разделение плана и наполнения: форму уровня можно менять независимо от наборов комнат. В статье «Dungeon Generation in Binding of Isaac» есть демо на JavaScript и разбор того, как Rebirth расширила алгоритм крупными комнатами неправильной формы.
Сначала генератор строит план на сетке 9×8, затем назначает особые комнаты и выбирает содержимое обычных. Стартовая комната попадает в очередь. Алгоритм проверяет четыре направления и с шансом 50% добавляет свободного соседа, если тот не создаст петлю.
Из тупиков выбираются специальные комнаты: босс получает одну из самых дальних от старта. Для секретной комнаты ищут пустую клетку рядом как минимум с тремя комнатами; после 300 и 600 неудачных попыток требования ослабляют.
Разработчику пригодится разделение плана и наполнения: форму уровня можно менять независимо от наборов комнат. В статье «Dungeon Generation in Binding of Isaac» есть демо на JavaScript и разбор того, как Rebirth расширила алгоритм крупными комнатами неправильной формы.
❤6
Как сервер засчитывает точный выстрел при сетевой задержке
В быстрой сетевой игре ваш клиент показывает собственного персонажа в настоящем, а противников в недавнем прошлом. Поэтому при выстреле в голову сервер может получить команду уже после того, как цель сместилась.
Компенсация задержки меняет момент проверки. Клиент отправляет точное время выстрела и направление оружия. Сервер по входным данным восстанавливает мир таким, каким его видел стрелок, проверяет попадание в том состоянии и рассылает результат.
Цена подхода: игрок может успеть спрятаться за стеной и всё равно получить урон, потому что для стрелка цель ещё была открыта. В разборе Gabriel Gambetta механизм показан на живой демонстрации. При проектировании сетевого шутера закладывайте этот компромисс: точные попадания для стрелка ценой позднего урона для цели.
В быстрой сетевой игре ваш клиент показывает собственного персонажа в настоящем, а противников в недавнем прошлом. Поэтому при выстреле в голову сервер может получить команду уже после того, как цель сместилась.
Компенсация задержки меняет момент проверки. Клиент отправляет точное время выстрела и направление оружия. Сервер по входным данным восстанавливает мир таким, каким его видел стрелок, проверяет попадание в том состоянии и рассылает результат.
Цена подхода: игрок может успеть спрятаться за стеной и всё равно получить урон, потому что для стрелка цель ещё была открыта. В разборе Gabriel Gambetta механизм показан на живой демонстрации. При проектировании сетевого шутера закладывайте этот компромисс: точные попадания для стрелка ценой позднего урона для цели.
❤2
Как пул объектов защищает эффекты от фрагментации памяти
Один взмах посоха порождает сотни частиц. Если каждую создавать и удалять отдельно, свободное место в памяти постепенно дробится: суммарно его хватает, а цельного блока нужного размера уже нет.
Пул объектов заранее резервирует один блок и хранит в нём готовые экземпляры. Система частиц берёт свободный, помечает его занятым и возвращает после анимации. Выделять память для каждой искры во время эффекта больше не нужно.
Цена предсказуемой работы: ёмкость пула фиксирована. Когда свободных слотов нет, можно пропустить новую частицу, заменить самый тихий из играющих звуков или расширить пул. В разборе Object Pool на Game Programming Patterns показано, как выбрать стратегию переполнения, подобрать размер слотов и не оставить в повторно используемом объекте старые данные.
Один взмах посоха порождает сотни частиц. Если каждую создавать и удалять отдельно, свободное место в памяти постепенно дробится: суммарно его хватает, а цельного блока нужного размера уже нет.
Пул объектов заранее резервирует один блок и хранит в нём готовые экземпляры. Система частиц берёт свободный, помечает его занятым и возвращает после анимации. Выделять память для каждой искры во время эффекта больше не нужно.
Цена предсказуемой работы: ёмкость пула фиксирована. Когда свободных слотов нет, можно пропустить новую частицу, заменить самый тихий из играющих звуков или расширить пул. В разборе Object Pool на Game Programming Patterns показано, как выбрать стратегию переполнения, подобрать размер слотов и не оставить в повторно используемом объекте старые данные.
❤1👍1
Как подготовить генератор гекс-карт Unity к задачам Burst
Одинаковые настройки и начальное значение не гарантируют одинаковую карту. В Unity 6000.3.20f1 Mono при вычислениях переводит
Перед переходом к Burst автор оставляет старый генератор, выносит настройки в сериализуемый класс и подключает экспериментальный через переключатель. Затем выделяет этапы с конца в структуры с методом
В туториале Catlike Coding показан рефакторинг и объяснено, почему результат IL2CPP выбран базой для сравнения. Так можно подготовить код к задачам Burst и отдельно отслеживать расхождения генерации.
Одинаковые настройки и начальное значение не гарантируют одинаковую карту. В Unity 6000.3.20f1 Mono при вычислениях переводит
float в double и обратно. Малой разницы хватает, чтобы изменить пороговую проверку: в примере IL2CPP строит другие реки, чем редактор и сборка Mono.Перед переходом к Burst автор оставляет старый генератор, выносит настройки в сериализуемый класс и подключает экспериментальный через переключатель. Затем выделяет этапы с конца в структуры с методом
Execute. Тип ландшафта обрабатывается циклом, создание рек остаётся последовательным. После каждого шага обе реализации должны выдавать одинаковые карты.В туториале Catlike Coding показан рефакторинг и объяснено, почему результат IL2CPP выбран базой для сравнения. Так можно подготовить код к задачам Burst и отдельно отслеживать расхождения генерации.
Как строить фрактальные берега с многоуровневой диаграммой Вороного
В диаграмме Вороного со случайно смещёнными центрами на каждую клетку сетки приходится одна псевдослучайная точка. Для заданной координаты алгоритм проверяет центры 25 ближайших клеток, поэтому не строит бесконечную диаграмму целиком.
Автор добавляет уровни. На каждом следующем сетка становится вдвое мельче, а новый центр связывается с ближайшим центром предыдущего уровня. Цепочка до нулевого уровня определяет область. С каждым уровнем её граница получает более мелкие изломы, похожие на береговую линию.
Для процедурной генерации полезен адаптивный вариант. Расчёт прекращается, когда все центры, способные повлиять на координату, ведут к одной исходной ячейке: дальнейшее дробление не изменит результат. Код для фиксированной глубины и ранней остановки есть в статье Fractal Jittered Voronoi Partitions.
В диаграмме Вороного со случайно смещёнными центрами на каждую клетку сетки приходится одна псевдослучайная точка. Для заданной координаты алгоритм проверяет центры 25 ближайших клеток, поэтому не строит бесконечную диаграмму целиком.
Автор добавляет уровни. На каждом следующем сетка становится вдвое мельче, а новый центр связывается с ближайшим центром предыдущего уровня. Цепочка до нулевого уровня определяет область. С каждым уровнем её граница получает более мелкие изломы, похожие на береговую линию.
Для процедурной генерации полезен адаптивный вариант. Расчёт прекращается, когда все центры, способные повлиять на координату, ведут к одной исходной ячейке: дальнейшее дробление не изменит результат. Код для фиксированной глубины и ранней остановки есть в статье Fractal Jittered Voronoi Partitions.
❤1
Как сваривать вершины меша за линейное время
В процедурной генерации части геометрии удобно строить независимо, а затем сливать близкие вершины. Перебор всех пар требует квадратичного числа сравнений.
Пространственный хеш делит плоскость на ячейки. Для новой точки он проверяет её ячейку и восемь соседних; в 3D получается 27 проверок. При ослабленном правиле сварки сложность снижается до O(n).
Ячейки размером 2r и сдвиг сетки хранения на r сокращают поиск до четырёх обращений к словарю в 2D и восьми в 3D, но охватывают большую область. Хеш подходит для примерно равномерных точек; для библиотеки общего назначения kd-дерево безопаснее. В статье Mesh Welding with Spatial Hashing есть псевдокод и объяснение смещённой сетки.
В процедурной генерации части геометрии удобно строить независимо, а затем сливать близкие вершины. Перебор всех пар требует квадратичного числа сравнений.
Пространственный хеш делит плоскость на ячейки. Для новой точки он проверяет её ячейку и восемь соседних; в 3D получается 27 проверок. При ослабленном правиле сварки сложность снижается до O(n).
Ячейки размером 2r и сдвиг сетки хранения на r сокращают поиск до четырёх обращений к словарю в 2D и восьми в 3D, но охватывают большую область. Хеш подходит для примерно равномерных точек; для библиотеки общего назначения kd-дерево безопаснее. В статье Mesh Welding with Spatial Hashing есть псевдокод и объяснение смещённой сетки.
❤2
Forwarded from Типичный программист
Как передавать Minecraft-сервер между компьютерами игроков
Экзамены одного игрока выключили Minecraft-сервер для всей компании на неделю: мир работал только на его компьютере. В ответ появился Nomad, который позволяет запускать тот же мир у любого участника.
Проект выбирает хоста через файл
В разборе Nomad есть жизненный цикл хоста, схема защиты от одновременного запуска и ссылка на код проекта.
Экзамены одного игрока выключили Minecraft-сервер для всей компании на неделю: мир работал только на его компьютере. В ответ появился Nomad, который позволяет запускать тот же мир у любого участника.
Проект выбирает хоста через файл
lease.json в общем хранилище. Если два игрока запускают сервер одновременно, условная запись разрешает это только одному. Хост подтверждает работу каждые 20 секунд, а после сбоя право запуска переходит другому игроку, когда истекают пять минут аренды. Перед передачей Nomad загружает сохранение мира в Cloudflare R2, Git или совместимое с S3 хранилище.В разборе Nomad есть жизненный цикл хоста, схема защиты от одновременного запуска и ссылка на код проекта.
❤2✍1
Как синхронизировать физику сетевой игры без передачи состояния объектов
При детерминированной синхронизации lockstep по сети отправляют только действия игрока, а не позиции и скорости тел. Поэтому миллион объектов требует столько же трафика, сколько один. Но одинаковые данные и команды должны давать побитно одинаковый результат на каждом кадре.
Получатель ждёт ввод для кадра n, а буфер выравнивает приход пакетов ценой задержки. TCP при потере пакета останавливает симуляцию до повторной доставки. Альтернатива: UDP повторяет неподтверждённые команды.
Схема с буфером и сжатием команд упирается в вычисления с плавающей точкой: результат может различаться между компиляторами, ОС и архитектурами. Подход годится для множества объектов и малого ввода, если совпадение подтверждено на целевых сборках.
При детерминированной синхронизации lockstep по сети отправляют только действия игрока, а не позиции и скорости тел. Поэтому миллион объектов требует столько же трафика, сколько один. Но одинаковые данные и команды должны давать побитно одинаковый результат на каждом кадре.
Получатель ждёт ввод для кадра n, а буфер выравнивает приход пакетов ценой задержки. TCP при потере пакета останавливает симуляцию до повторной доставки. Альтернатива: UDP повторяет неподтверждённые команды.
Схема с буфером и сжатием команд упирается в вычисления с плавающей точкой: результат может различаться между компиляторами, ОС и архитектурами. Подход годится для множества объектов и малого ввода, если совпадение подтверждено на целевых сборках.
❤2
Как сжать снимки сетевой физики и сократить задержку
10 снимков состояния в секунду дают до 150 мс задержки интерполяции, а защита от потери пакетов поднимает её до 250–350 мс. При 60 снимках задержка ниже, но трафик достигает 17,37 Мбит/с вместо бюджета в 256 кбит/с.
Схема сжатия снимков сокращает кватернион поворота со 128 до 29 бит, позицию с 96 до 50 бит, а скорость при 60 Гц можно не передавать. Состояние куба уменьшается с 321 до 80 бит.
Затем снимок кодируется относительно последнего подтверждённого состояния. В покое трафик падает примерно до 15 кбит/с: сначала убираем лишние поля, затем измеряем точность и вводим дельта-сжатие.
10 снимков состояния в секунду дают до 150 мс задержки интерполяции, а защита от потери пакетов поднимает её до 250–350 мс. При 60 снимках задержка ниже, но трафик достигает 17,37 Мбит/с вместо бюджета в 256 кбит/с.
Схема сжатия снимков сокращает кватернион поворота со 128 до 29 бит, позицию с 96 до 50 бит, а скорость при 60 Гц можно не передавать. Состояние куба уменьшается с 321 до 80 бит.
Затем снимок кодируется относительно последнего подтверждённого состояния. В покое трафик падает примерно до 15 кбит/с: сначала убираем лишние поля, затем измеряем точность и вводим дельта-сжатие.
❤2
Как компонентный паттерн развязывает код игровых сущностей
Когда ввод, физика, рендеринг и звук живут в одном классе персонажа, правка затрагивает сразу несколько систем. Если эти системы разнесены по потокам, общий объект ещё и повышает риск взаимных блокировок.
Компонентный паттерн выносит каждую систему в отдельный класс, а сущность оставляет контейнером. Для декорации подключают графику, для зоны физику, а для интерактивного объекта оба компонента. Получается конструктор сущностей без сложной иерархии наследования.
Схема паттерна и пример кода показывают цену решения: компоненты нужно создавать, связывать и учить общаться. Дополнительный переход к компоненту может замедлить критичные циклы. Подход уместен, когда класс соединяет несколько систем или уже стал слишком большим; для простой сущности это лишняя сложность.
Когда ввод, физика, рендеринг и звук живут в одном классе персонажа, правка затрагивает сразу несколько систем. Если эти системы разнесены по потокам, общий объект ещё и повышает риск взаимных блокировок.
Компонентный паттерн выносит каждую систему в отдельный класс, а сущность оставляет контейнером. Для декорации подключают графику, для зоны физику, а для интерактивного объекта оба компонента. Получается конструктор сущностей без сложной иерархии наследования.
Схема паттерна и пример кода показывают цену решения: компоненты нужно создавать, связывать и учить общаться. Дополнительный переход к компоненту может замедлить критичные циклы. Подход уместен, когда класс соединяет несколько систем или уже стал слишком большим; для простой сущности это лишняя сложность.
❤1