Структурирование игрового движка на основе состояния, а структура Makefile поможет? - PullRequest
6 голосов
/ 24 июня 2011

Я работаю над игровым движком, основанным на состоянии, и у меня есть для начала кое-что, чем я доволен.

Есть абстрактный класс GameState.hpp с виртуальными методами, которые я использую (init, run, pause и т.д ...).

Есть GameEngine.cpp / hpp, который является классом, который содержит стек объектов GameState и устанавливает игровой цикл, выполняя соответствующие методы текущего состояния.

Моя тестовая игра TestGame.cpp создает объект GameEngine, отправляет экземпляр TestState и запускается, и т. Д. ... Все работает, как я ожидаю.

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

src/
  +Engine/
    +GameEngine.cpp
    +GameEngine.hpp
    +GameState.hpp
  +TestGame/
    +States/
      +TestState.cpp
      +TestState.hpp
    +TestGame.cpp

При сборке я не уверен, понимаю ли я, что и с чем нужно компилировать и куда должны идти скомпилированные объекты.

Пока что мои первые мысли:

  1. Компиляция GameEngine.cpp / hpp с GameState.hpp, дает GameEngine.o

  2. Скомпилируйте каждое игровое состояние, например. TestState.cpp / hpp с GameState.hpp, выдает TestState.o

  3. Компиляция TestGame.cpp / hpp с GameEngine.o / hpp, GameState.hpp, TestState.o / hpp (и любыми другими состояниями), дает TestGame.bin

Я на правильном пути? Должен ли GameEngine создать lib или обычный .o ок? Я все еще немного сомневаюсь, нужно ли мне включать заголовки в каждую компиляцию. Кроме того, выходные файлы для каждой компиляции находятся в том же каталоге, что и исходный код, или они должны находиться в структурированном каталоге bin /? *

Я поиграю и опубликую несколько попыток Makefile и их вывод. Дайте мне знать, если я должен опубликовать код, возможно, всего 200 строк. Реальной графической реализации и т. Д. Просто на данный момент фреймворк.

Спасибо, ребята, любая помощь очень ценится!

РЕДАКТИРОВАТЬ: Спасибо за быстрые ответы людей. Я прочитал комментарии ниже и хотел дать обновление и прояснить некоторые вещи.

Во-первых, я смотрю на автоинструменты, но это в основном учебный проект, и частью этого является создание make-файлов. Кроме того, я родом из Java, поэтому очень хочу понять, что именно я строю и как мой проект сочетается. Как и выше, я даже не знаю, должна ли что-то быть библиотекой или просто указывать во время компиляции.

Обзор моей цели : Я вижу двигатель почти как подпроект. Несмотря на то, что он простой (<10 файлов), он будет загружать то, что я считаю «состояниями», и циклически обрабатывать методы [<strong> обработки событий, обновления, отображения ], которые определяет состояние. У меня есть алгоритм, который стремится к постоянному количеству обновлений в секунду, при этом меняя частоту кадров при необходимости.

Например, метод display состояний будет использовать функции отображения, поддерживаемые модулем SDL (возможно, механизм листов, состояние может сказать «загрузить эти ресурсы, отобразить эти листы» или библиотека виджетов). , что угодно ...) для представления модели игрового мира. Метод обработки событий может использовать интерфейс абстрактной клавиатуры. Я хочу иметь возможность добавить такую ​​функциональность в движок. Обновление будет управлять моделью, которая представляет игровой мир. Он будет следить за объектами в мире (сцена, игрок и NP), применять движения, основанные на физике и обнаружении столкновений, и т.д ...

Я думаю, что я хочу иметь возможность построить это и просто включить объект (и заголовки?) В игру, над которой я работаю. Является ли это вопросом 'скопируйте dir движка в корневой каталог игрового проекта и добавьте его в основной Makefile, соберите все вместе', или 'запускать make на движке всякий раз, когда он меняется, создавать игровой проект с копией самого последнего объекта движка (совместно используемого объекта, чего-то еще?) и заголовков',что мне будет легче работать с несколькими небольшими игровыми проектами, используя один движок?Я вроде хочу настроить себя так, чтобы я мог приступить к работе со случайными игровыми идеями, такими как у меня есть, такими как 2-недельное кодирование и т.д. ...

Состояния представляют любой другой взгляд и набор взаимодействий,Движок имеет стек состояний LIFO, поэтому простая игра может иметь в стеке следующие состояния: DrivingMode - PauseMenu - Настройки. В реальной игре есть экземпляр GameEngine, и для запуска игры будет добавлен DrivingMode.Пользователь делает паузу, которая приостанавливает состояние DrivingMode и толкает состояние PauseMenu (запускает init, run и т. Д. При нажатии).Здесь пользователь выбирает настройки, которые ставят паузу в состояние PauseMenu, и загружает настройки ... Когда они выходят обратно, состояния выталкиваются (очистка и т. Д. Запускаются первыми), а верхнее состояние возобновляется.

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

Ответы [ 2 ]

6 голосов
/ 24 июня 2011

Прежде всего, вам действительно нужно, чтобы состояния были модульными?Если вы планируете написать движок для конкретной цели, ваши состояния, вероятно, не сильно изменятся и, следовательно, вероятно, должны быть скомпилированы как часть самого движка.

Разделение состояний от движка добавитдополнительный уровень сложности и усложнение реализации.

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

Вы можете выбрать:

  • Скомпилировать движок и состояния как одну библиотеку (возможно, статическую, с которой вы связываете свою игру)
  • Скомпилируйте движок как статическую библиотеку, а затем скомпилируйте состояния как разделяемые объекты, которые могут быть динамически связаны (это будет соответствовать опции модульного состояния, но это добавит много сложности)
  • Скомпилируйте весь движок+ Игра в один большой исполняемый файл, который избавляет от необходимости каких-либо ссылок на библиотеки (но также сделатьдвигатель и игра более связаны друг с другом)

На мой взгляд, вариант 1 выглядит наилучшим образом.

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

Если вы по-прежнему хотите, чтобы игра определяла свои собственные состояния, тогда вы захотите перейти ко второму варианту и реализовать несколько основных состояний.в вашем движке (возможно, что-то вроде INIT, MAIN_MENU, SHUT_DOWN), а также что-то вроде «менеджера плагинов», который в этом случае будет отвечать за регистрацию состояний игры с помощью игрового движка.

Каждое состояние можетзатем скомпилировать по отдельности как общий объект (.so) и динамически загрузить при загрузке игры.

Что касается Makefiles, то это действительно зависит от того, что вы планируете использовать (CMake, GNU autotools и т. д.)

Make-файлы GNU имеют довольно простой синтаксис, но научиться правильно их использовать может быть немного сложно.

Они состоят из целей, которые определены следующим образом:

default:
    gcc [...]

all:
    gcc [...]
    gcc [...]
    <...>

Первая цель - цель по умолчанию, когда make вызывается без аргументов. Я не буду подробно описывать, как использовать make-файлы (для GNU Make: эта ссылка )

Вы должны знать, что make-файлы быстро становятся невероятно утомительными в обслуживании, и обычно предпочитается решение, подобное autotools .

Обратите внимание, что autotools оченьбольшая система, состоящая из множества программ и может быть довольно трудоемкой в ​​освоении.Если вы хотите сосредоточиться на разработке игрового движка, я настоятельно рекомендую использовать IDE проекта, например Code :: blocks , для компиляции и компоновки кода.

РЕДАКТИРОВАТЬ

В ответ на ваши изменения я бы добавил следующее:

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

Тогда ваш движок предоставит интерфейс для регистрации состояний, которые игры будут использовать, чтобы сообщать«Вот мое состояние, которое называется title », и позже оно сообщит двигателю «переключаться в состояние, называемое title », когда это необходимо.

Одна вещь, которую вы можете захотетьРассмотрим наличие нескольких основных состояний, которые должны регистрировать все игры (налагаемые самим движком).

Тогда движок будет собственным проектом, а игровые проекты будут просто иметь копию библиотеки движка в / lib например.Затем вы статически связываете движок с вашей игрой во время компиляции.

Если вы хотите получить более подробную информацию о том, как можно структурировать объекты состояния, дайте мне знать.


2 голосов
/ 24 июня 2011

Многие вещи, которые вы спрашиваете, не имеют однозначного ответа, часто это личные предпочтения.

По вашему вопросу у меня сложилось впечатление, что вы также компилируете свои заголовки, вы не должны компилировать заголовки, они должны быть включены только в файлы .cpp и другие заголовки.Затем они компилируются как часть cpp.Файлы должны содержать только те заголовки, которые им действительно нужны.

Пока ваш проект небольшой, хранить все в одном каталоге часто лучше, но если вы знаете, что он будет расти, тогда настройка хорошей структуры каталогов является хорошейидея.Хорошо отделить потенциально многократно используемый GameEngine от реальной игры, как и вы.

Создание библиотеки полезно, когда эта часть будет повторно использована в других проектах или когда ваш проект станет настолько большим, что их число.o файлы становятся очень высокими.Так что, если это относится к GameEngine, сделайте его свободным.Для проектов многократного использования, таких как игровой движок, часто также полезно хранить заголовки в отдельном каталоге.Поскольку проекты, зависящие от него, будут нуждаться только в заголовках и lib, им не нужны остальные источники.

Когда проекты становятся больше, используя отдельные каталоги для исходного кода, промежуточные (.o) и конечные исполняемые файлы помогают поддерживать управляемость ваших файлов, так как хранение .o с вашими источниками обычно увеличивает количество файлов в вашем каталоге src на 50%.

Если вы хотите настроить его действительно хорошо, вы можете взглянуть на autoconf и automake.У них есть крутая кривая обучения, но они заберут много Makefile из ваших рук.Это инструменты, которые создают скрипт конфигурирования, найденный в исходных дистрибутивах многих пакетов с открытым исходным кодом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...