У меня есть готовая игра, от которой я хочу отказаться в других версиях. Это были бы похожие игры, с более или менее одинаковым дизайном, но не всегда, в основном все может измениться, иногда мало, иногда крупно.
Я бы хотел, чтобы основной код создавался отдельно от игры, так что если, скажем, я исправлю ошибку, обнаруженную в игре A, то исправление будет присутствовать в игре B.
Я пытаюсь найти лучший способ справиться с этим. Мои первоначальные идеи таковы:
- Создайте
engine
модуль / папку / что угодно, что содержит все, что может быть обобщено и на 100% не зависит от остальной части игры. Это будет включать в себя некоторый код, а также общие ресурсы, которые используются в играх. - Поместите этот движок в собственный
git
репозиторий, который будет включен в игры какgit submodule
Часть, с которой я борюсь, это как управлять остальным кодом. Допустим, у вас есть сцена меню, этот код является специфичным для игры, но также большинство из них имеет общий характер и могут быть повторно использованы в других играх. Я не могу поместить это в engine
, но перекодировать это для каждой игры было бы неэффективно.
Может быть, использование какой-то разновидности веток git может быть эффективным для управления этим, но я не думаю, что это лучший путь.
У кого-нибудь есть какие-то идеи, опыт, которыми можно поделиться или что-нибудь об этом?
Ответы:
Это именно то, что я делаю, и это работает очень хорошо. У меня есть прикладная среда и библиотека рендеринга, и каждый из них рассматривается как подмодуль моих проектов. Я считаю, что SourceTree полезен, когда дело доходит до подмодулей, поскольку он хорошо управляет ими и не позволит вам ничего забыть, например, если вы обновили подмодуль движка в проекте A, он уведомит вас о необходимости внести изменения в проект B.
С опытом приходит знание того, какой код должен быть в движке, а какой должен быть для каждого проекта. Я полагаю, что если вы даже немного не уверены, что вы держите это в каждом проекте на данный момент. Со временем вы увидите среди своих различных проектов, что остается неизменным, и затем вы можете постепенно учитывать это в коде вашего движка. Другими словами: дублируйте код до тех пор, пока вы не будете почти на 100% уверены, что он не изменяется дискретно для каждого проекта, а затем обобщите его.
Примечание о контроле исходного кода и двоичных файлах
Просто помните, что если вы ожидаете, что ваши двоичные активы будут часто меняться, вы, возможно, не захотите помещать их в текстовый контроль исходных текстов, такой как git. Просто скажу ... есть лучшие решения для двоичных файлов. Самая простая вещь, которую вы можете сделать сейчас, чтобы поддерживать чистоту и производительность вашего репозитория «engine-source», - это иметь отдельный репозиторий «engine-binaries», который содержит только двоичные файлы, которые вы также включаете в свой проект в качестве подмодуля. Таким образом, вы уменьшаете ущерб производительности, нанесенный вашему репозиторию «движок-источник», который постоянно меняется и требует быстрых итераций: коммит, push, pull и т. Д. Системы управления исходным кодом, такие как git, работают с текстовыми дельтами. и, как только вы вводите двоичные файлы, вы вводите огромные дельты с точки зрения текста, что в конечном итоге стоит вашего времени разработки.Приложение GitLab . Google твой друг.
источник
В какой-то момент движок ДОЛЖЕН специализироваться и знать материал об игре. Я пойду по касательной здесь.
Возьмите ресурсы в РТС. Одна игра может иметь
Credits
иCrystal
другуюMetal
иPotatoes
Вы должны использовать концепции ОО правильно и идти на макс. кода повторного использования. Понятно, что
Resource
здесь существует понятие .Поэтому мы решили, что ресурсы имеют следующее:
int
)Обратите внимание, что это понятие
Resource
может представлять убийства или очки в игре! Это не очень сильно.Теперь давайте подумаем об игре. Мы можем иметь валюту, имея дело с копейками и добавляя десятичную точку к выводу. Чего мы не можем сделать, так это «мгновенных» ресурсов. Мол, скажем "генерация электросети"
Допустим, вы добавили
InstantResource
класс с похожими методами. Вы теперь (начинаете) загрязнять свой двигатель ресурсами.Проблема
Давайте снова возьмем пример RTS. Предположим, игрок что-нибудь пожертвует
Crystal
другому игроку. Вы хотите сделать что-то вроде:Однако это действительно довольно грязно. Это общее назначение, но грязное. Уже, хотя это налагает,
resourceDictionary
что означает, что теперь ваши ресурсы должны иметь имена! И это на игрока, поэтому вы не можете больше иметь командные ресурсы.Это «слишком большая» абстракция (я не признаю блестящий пример), вместо этого вы должны достичь точки, когда вы признаете, что в вашей игре есть игроки и кристалл, тогда вы можете просто иметь (например)
С классом
Player
и классом ,CurrentPlayer
гдеCurrentPlayer
«Scrystal
объект будет автоматически показывать материал на ИЛС для передачи / отправки пожертвований.Это загрязняет двигатель кристаллом, пожертвованием кристалла, сообщениями в HUD для текущих игроков и всем этим. Это быстрее и проще для чтения / записи / обслуживания (что более важно, так как это не значительно быстрее)
Заключительные замечания
Случай с ресурсами не блестящий. Я надеюсь, что вы все еще можете увидеть суть. Во всяком случае, я продемонстрировал, что «ресурсы не принадлежат движку», поскольку то, что нужно конкретной игре и что применимо ко всем представлениям о ресурсах, это ОЧЕНЬ разные вещи. Обычно вы найдете 3 (или 4) «слоя»
creature
илиship
илиsquad
. Использование наследования вы получите классы , которые охватывают все 3 слоя (например ,Crystal
этоResource
который являетсяGameLoopEventListener
скажет)Создание новой игры из старого движка
Это ОЧЕНЬ распространено. Фаза 1 состоит в том, чтобы вырвать слои 3 и 4 (и 2, если игра ПОЛНОСТЬЮ другого типа). Предположим, мы делаем RTS из старой RTS. У нас все еще есть ресурсы, только не кристаллы и прочее - поэтому базовые классы в слоях 2 и 1 все еще имеют смысл, все кристаллы, на которые есть ссылки в 3 и 4, могут быть отброшены. Так и делаем. Однако мы можем проверить это как ссылку на то, что мы хотим сделать.
Загрязнение в слое 1
Это может случиться Абстракция и производительность - враги. Например, UE4 предоставляет множество оптимизированных вариантов компоновки (поэтому, если вы хотите, чтобы X и Y написали код, который действительно быстро выполняет X и Y - он знает, что выполняет оба), и в результате ДЕЙСТВИТЕЛЬНО довольно большой. Это не плохо, но это отнимает много времени. Уровень 1 будет определять такие вещи, как «как вы передаете данные в шейдеры» и как вы анимируете вещи. Делать это наилучшим образом для вашего проекта ВСЕГДА хорошо. Просто попробуйте и спланируйте будущее, повторное использование кода - ваш друг, наследуйте там, где это имеет смысл.
Классифицирующие слои
ПОСЛЕДНО (обещаю) не надо слишком бояться слоев. Движок - это архаичный термин из старых дней конвейеров с фиксированной функцией, когда двигатели работали в основном графически (и в результате имели много общего), программируемый конвейер перевернул это с ног на голову, и как таковой «слой 1» стал загрязненным с любыми эффектами, которые разработчики хотели достичь. ИИ был отличительной чертой (из-за множества подходов) двигателей, теперь это ИИ и графика.
Ваш код не должен храниться в этих слоях. Даже знаменитый движок Unreal имеет МНОЖЕСТВО разных версий, каждая из которых специфична для отдельной игры. Есть несколько файлов (отличных от структур данных), которые остались бы без изменений. Это отлично! Если вы хотите создать новую игру из другой, это займет больше 30 минут. Ключ в том, чтобы планировать, знать, какие биты копировать и вставлять, а что оставлять.
источник
Мое личное предложение о том, как обращаться с контентом, который является смесью общего и особенного, состоит в том, чтобы сделать его динамичным. Я возьму ваш экран меню в качестве примера. Если я неправильно понял, что вы просили, дайте мне знать, что вы хотели знать, и я адаптирую свой ответ.
Есть 3 вещи, которые (почти) всегда присутствуют на сцене меню: фон, логотип игры и само меню. Эти вещи обычно отличаются в зависимости от игры. Что вы можете сделать для этого контента, это сделать MenuScreenGenerator в вашем движке, который принимает 3 параметра объекта: BackGround, Logo и Menu. Базовая структура этих трех частей также является частью вашего движка, но ваш движок на самом деле не говорит о том, как эти детали генерируются, а о том, какие параметры вы должны им дать.
Затем в вашем реальном игровом коде вы создаете объекты для BackGround, логотипа и меню и передаете их в MenuScreenGenerator. Опять же, ваша игра сама не обрабатывает то, как генерируется меню, это для движка. Ваша игра должна только сказать движку, как она должна выглядеть и где она должна быть.
По сути, ваш движок должен быть API, чтобы игра показывала, что отображать. Если все сделано правильно, ваш движок должен выполнять тяжелую работу, а ваша игра должна только сообщать движку, какие активы использовать, какие действия предпринять и как выглядит мир.
источник