Быстрое итерационное время - ключ к разработке игр, гораздо больше, чем, на мой взгляд, прикольная графика и движки с множеством функций. Неудивительно, что многие маленькие разработчики выбирают языки сценариев.
Способ Unity 3D, позволяющий приостановить игру и изменить ресурсы и код, а затем продолжить и сразу же вступить в силу, абсолютно подходит для этого. Мой вопрос: кто-нибудь реализовывал подобную систему на игровых движках C ++?
Я слышал, что это делают действительно супер-мощные движки, но мне больше интересно узнать, есть ли способ сделать это в отечественном движке или игре.
Очевидно, что будут компромиссы, и я не могу себе представить, что вы можете просто перекомпилировать свой код, пока игра находится в режиме паузы, перезагружать его и работать при любых обстоятельствах или на любой платформе.
Но, возможно, это возможно для программирования ИИ и простых логических модулей уровня. Это не так, как если бы я хотел сделать это в любом проекте в краткосрочной (или долгосрочной) перспективе, но мне было любопытно.
источник
Горячая замена - очень и очень сложная проблема, решаемая с помощью двоичного кода. Даже если ваш код помещен в отдельные библиотеки динамических ссылок, ваш код должен гарантировать, что в памяти нет прямых ссылок на функции (так как адрес функций может изменяться при перекомпиляции). По сути, это означает, что не нужно использовать виртуальные функции, а все, что использует указатели функций, делает это через какую-то таблицу диспетчеризации.
Волосатые, стеснительные вещи. Лучше использовать язык сценариев для кода, который нуждается в быстрой итерации.
На работе наша текущая кодовая база представляет собой смесь C ++ и Lua. Lua тоже не маленькая часть нашего проекта - это почти 50/50 раскол. Мы осуществили перезагрузку Lua на лету, так что вы можете изменить строку кода, перезагрузить и продолжать работу. Фактически, вы можете сделать это, чтобы исправить ошибки сбоев, возникающие в коде Lua, без перезапуска игры!
источник
(Возможно, вы захотите узнать о термине «исправление обезьяны» или «штамповка утки», если не по каким-либо иным причинам, кроме юмористического образа мыслей.)
И это в стороне: если ваша цель - уменьшить время итерации для изменений «поведения», попробуйте несколько подходов, которые помогут вам в этом, и хорошо сочетаются, чтобы в будущем это стало возможным.
(Это будет немного касательно, но я обещаю, что это вернется!)
Многие из этих моментов полезны, даже если вы не полностью перезагрузите данные или код.
Вспомогательные анекдоты:
На большом ПК RTS (команда ~ 120 человек, в основном C ++) существовала невероятно глубокая система сохранения состояния, которая использовалась как минимум для трех целей:
С тех пор я использовал детерминированную запись / воспроизведение в C ++ и Lua карточной игре для DS. Мы подключились к API, который мы разработали для AI (на стороне C ++), и записали все действия пользователя и AI. Мы использовали эту функциональность в игре (чтобы обеспечить воспроизведение для игрока), но также и для диагностики проблем: когда происходил сбой или странное поведение, все, что нам нужно было сделать, это получить файл сохранения и воспроизвести его в отладочной сборке.
С тех пор я также использовал оверлеи несколько раз, и мы объединили их с нашей системой «автоматически разбрасывать этот каталог и загружать новый контент в карманный компьютер». Все, что нам нужно сделать, это оставить кат-сцену / уровень / что угодно и вернуться обратно, и будут загружены не только новые данные (спрайты, разметка уровней и т. Д.), Но и любой новый код в оверлее. К сожалению, с более новыми карманными компьютерами становится все труднее из-за механизмов защиты от копирования и защиты от взлома, которые обрабатывают код специально. Мы все еще делаем это для сценариев Lua, хотя.
И последнее, но не менее важное: вы можете (и я имею в виду, в различных очень маленьких особых обстоятельствах) сделать небольшую пробивку утки, непосредственно исправляя коды операций. Это работает лучше всего, если вы работаете на фиксированной платформе и компиляторе, и, поскольку он почти не поддерживается, очень подвержен ошибкам и ограничен в том, что вы можете быстро выполнить, я в основном использую его только для перенаправления кода во время отладки. Тем не менее, он очень быстро научит вас многому об архитектуре набора команд.
источник
Вы можете сделать что-то вроде горячей замены модулей во время выполнения, реализуя модули в виде динамических библиотек (или общих библиотек в UNIX), и используя dlopen () и dlsym () для динамической загрузки функций из библиотеки.
Для Windows эквивалентами являются LoadLibrary и GetProcAddress.
Это метод C, и у него есть некоторые подводные камни при использовании его в C ++, вы можете прочитать об этом здесь .
источник
Если вы используете Visual Studio C ++, вы можете приостановить и перекомпилировать ваш код при определенных обстоятельствах. Visual Studio поддерживает редактирование и продолжение . Присоединитесь к своей игре в отладчике, остановите ее на точке останова, а затем измените код после точки останова. Если вы хотите сохранить, а затем продолжить, Visual Studio попытается перекомпилировать код, повторно вставить его в работающий исполняемый файл и продолжить. Если все пойдет хорошо, внесенные вами изменения будут действительны и будут применяться к запущенной игре без необходимости выполнять весь цикл компиляции-сборки-тестирования. Тем не менее, следующее остановит это от работы:
Я использовал Edit и Continue, чтобы значительно улучшить скорость таких вещей, как итерация пользовательского интерфейса. Допустим, у вас есть работающий пользовательский интерфейс, полностью построенный на коде, за исключением того, что вы случайно поменяли порядок прорисовки двух блоков, чтобы вы ничего не видели. Изменяя 2 строки кода в реальном времени, вы можете сэкономить себе 20-минутный цикл компиляции / сборки / тестирования, чтобы проверить тривиальное исправление пользовательского интерфейса.
Это НЕ полное решение для производственной среды, и я обнаружил, что лучшее решение - это перенести как можно большую часть вашей логики в файлы данных, а затем сделать эти файлы данных перезагружаемыми.
источник
Как уже говорили другие, это сложная проблема, динамически связывая C ++. Но это решенная проблема - вы, возможно, слышали о COM или одном из маркетинговых имен, которые применялись к нему на протяжении многих лет: ActiveX.
С точки зрения разработчика, COM имеет немного дурную славу, потому что может потребоваться много усилий для реализации компонентов C ++, которые раскрывают их функциональность, используя его (хотя это облегчается с помощью ATL - библиотеки шаблонов ActiveX). С точки зрения потребителя у него плохое имя, потому что приложения, использующие его, например, для встраивания электронной таблицы Excel в документ Word или диаграммы Visio в электронную таблицу Excel, имели тенденцию довольно часто падать в тот же день. И это сводится к тем же проблемам - даже несмотря на все рекомендации, которые предлагает Microsoft, COM / ActiveX / OLE было / трудно сделать правильно.
Подчеркну, что технология COM сама по себе не является плохой по своей сути. Прежде всего, DirectX использует COM-интерфейсы для демонстрации его функциональности, и это работает достаточно хорошо, как и множество приложений, которые встраивают Internet Explorer, используя его элемент управления ActiveX. Во-вторых, это один из самых простых способов динамического связывания кода C ++ - интерфейс COM по сути является просто виртуальным классом. Хотя у него есть IDL, такой как CORBA, вы не обязаны его использовать, особенно если определенные вами интерфейсы используются только в вашем проекте.
Если вы не пишете для Windows, не думайте, что COM не стоит рассматривать. Mozilla повторно реализовала его в своей кодовой базе (используемой в браузере Firefox), потому что им нужен был способ компонентизировать свой код C ++.
источник
Там же реализация выполнения скомпилированных C ++ для игровой код здесь . Кроме того, я знаю, что есть по крайней мере один проприетарный игровой движок, который делает то же самое. Это сложно, но выполнимо.
источник