Как использовать классы, реализованные в exe из dll

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

Затем движок загрузит dll, получит экземпляр игры, предоставит игре указатели на любые функции и структуры данных, которые нужны игре, и вызовет такие методы, как game->update(); для экземпляра игры. Все идет нормально.

Я хотел бы, чтобы в движке были реализованы такие вещи, как базовые классы, такие как Entity, Transform, Vector3 и т. д. Затем в игре я хочу, например, вывести своего персонажа из Entity.

class Character : public engine::Entity {...};

Подобные вещи компилируются нормально, так как я включаю заголовки из движка, но они не связываются, так как я не использую файлы obj и файлы cpp, формирующие движок. Я знаю, почему это не работает. Насколько я знаю, мои (разумные) варианты:

  1. Сделайте эти классы только заголовком - таким образом он всегда будет компилироваться везде.

Я не хочу этого, так как это увеличит время компиляции, размер двоичного файла и т.д.

  1. Поместите общую функциональность в библиотеку или dll.

Это будет работать, но файл lib будет означать, что у меня есть одни и те же классы, скомпилированные (связанные) как в exe (движок), так и в dll (игра) - это кажется небрежным. Dll будет работать, но похоже, что мне придется проделать много работы со всеми экспортами и импортами как для движка, так и для игры. Также, вероятно, самое главное, подход lib и dll имеет общую проблему, которая заключается в том, что во время разработки я могу в конечном итоге перемещать различные классы из них и в них, поскольку иерархия классов может сильно измениться и т. д.

Мой вопрос в том, есть ли другой способ обойти это? Для меня это кажется довольно полезной функцией иметь иерархию классов в exe, которую можно использовать из dll. Я пробовал даже очень глупые вещи, такие как заставить компоновщик использовать файлы .obj, сгенерированные во время компиляции движка, но это не сработало, если я не указывал все файлы .obj один за другим. (Я использую Visual Studio 2017).

Я не хочу отказываться от модульности этой конструкции.

Редактировать: поскольку dll зависят от платформы, давайте рассмотрим Windows (хотя я думаю, что другие платформы будут похожими).


person Aldarrion    schedule 27.04.2017    source источник
comment
Я немного смущен тем, что движок - это exe, а игра - dll. Не будет ли логичнее наоборот?   -  person 463035818_is_not_a_number    schedule 27.04.2017


Ответы (2)


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

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

Если я придумаю что-нибудь новаторское, я опубликую это здесь, а пока вот некоторая информация о динамической загрузке, которая поможет вам начать работу. https://en.wikipedia.org/wiki/Dynamic_loading

person MrJman006    schedule 27.04.2017
comment
На мой взгляд, было бы разумно иметь движок, который управляет основным игровым циклом, где он просто вызывает game->update(). Если игра является исполняемым файлом, каждый, кто хочет сделать игру, должен позаботиться об основном цикле. Наличие движка в виде dll больше похоже на наличие фреймворка. Мне, наверное, следует погрузиться в код IdTech4 и посмотреть, как именно это там делается. Спасибо в любом случае :) - person Aldarrion; 28.04.2017
comment
Да, всегда приятно видеть, как успешные проекты делают вещи, чтобы получить вдохновение. К вашему сведению, есть веб-сайт обмена стеками разработки игр, где этот материал может быть более подходящим. Вот вопрос об отделении движка от игры от редактора уровней, который может вас заинтересовать. gamedev.stackexchange.com/questions/26520/ - person MrJman006; 28.04.2017
comment
Вы правы в концепции движка, который должен быть достаточно универсальным, чтобы вызывать обновление игрового материала, но вы хотите, чтобы программисты могли использовать код вашего движка, по крайней мере, для регистрации объектов. Для этого у них должен быть способ загрузить этот код для использования. Вот почему он обычно идет в .dll. Вы не можете загрузить из .exe, если вы не настраиваете общую память. - person MrJman006; 28.04.2017
comment
В конце дня мы обсудим, как код вашего движка компилируется и загружается каким-то другим кодом, который имеет реальную игровую логику. Как бы вы этого ни достигли, это не имеет значения, пока независимый программист может регистрировать игровые объекты с помощью движка (в обычной настройке, движок в .dll) или может регистрировать сигналы игрового движка с кодом игровой логики (мое лучшее предположение о дизайне для того, что вы пытаются добиться). - person MrJman006; 28.04.2017

Put the common functionality into a lib or a dll.

Это сработает, но файл lib будет означать, что у меня скомпилированы (связаны) одни и те же классы как в exe, так и в dll.

нет, не будет. Классы будут скомпилированы и доступны в общей библиотеке (.so в Linux, .dll в Windows, .dylib в Mac), а ваш исполняемый файл будет вызывать этот конкретный метод из общей библиотеки. он не будет снова скомпилирован в ваш исполняемый файл.

Взгляните на все фреймворки или библиотеки на C++, которые реализованы:

  • The public part is exposed on the headers
    • __dllexport(true) on the classes / functions.
  • The private part is hidden
    • Private shouldn't even exist on the public headers unless it's a d-ptr
    • https://en.wikipedia.org/wiki/Opaque_pointer
    • Это добавляет больше безопасности к двоичной совместимости.
  • Не беспокойтесь об увеличении времени загрузки, если вы используете подход с общей библиотекой, это незначительно.
person Tomaz Canabrava    schedule 27.04.2017
comment
В той части, которую вы цитируете, говорится о подходе lib (static). У динамического подхода есть и другие недостатки, о которых я говорю. В любом случае спасибо, я могу поменять местами, хотя подход IdTech кажется действительно хорошим. - person Aldarrion; 28.04.2017