This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
Если вам необходимо пользовательское взаимодействие с внешним программным или аппаратным обеспечением на низком уровне, где Lua недостаточно, Defold SDK позволяет писать расширения для движка на C, C++, Objective C, Java или Javascript, в зависимости от целевой платформы. Типичными случаями использования нативных расширений являются:
Defold предоставляет точку входа для нативных расширений с нулевой настройкой и облачным решением для сборки. Любое нативное расширение, разработанное и добавленное в игровой проект, либо напрямую, либо через Library Project, становится частью содержимого проекта. Нет необходимости создавать специальные версии движка и распространять их среди членов команды, это происходит автоматически - любой член команды, который собирает и запускает проект, получит исполняемый файл движка для конкретного проекта со всеми встроенными расширениями.
Чтобы создать новое расширение, создайте папку в корне проекта. Эта папка будет содержать все настройки, исходный код, библиотеки и ресурсы, связанные с расширением. Конструктор расширений распознает структуру папок и соберет все исходные файлы и библиотеки.
myextension/
│
├── ext.manifest
│
├── src/
│
├── include/
│
├── lib/
│ └──[platforms]
│
├── manifests/
│ └──[platforms]
│
└── res/
└──[platforms]
platform
, или architecure-platform
, в зависимости от того, какие архитектуры поддерживаются вашими библиотеками.
Supported platforms are ios
, android
, osx
, win32
, linux
, web
.
Supported arc-platform
pairs are arm64-ios
, x86_64-ios
, armv7-android
, arm64-android
, arm64-osx
, x86_64-osx
, x86-win32
, x86_64-win32
, arm64-linux
, x86_64-linux
, js-web
and wasm-web
.
platform
, или architecure-platform
, как и подпапки “lib”. Также допускается подпапка common
, содержащая файлы ресурсов, общие для всех платформ.Опциональная папка manifests расширения содержит дополнительные файлы, используемые в процессе сборки и комплектации. Файлы должны быть помещены во вложенные папки, названные по платформе
:
android
- В эту папку помещается файл-заглушка манифеста, который будет объединен с основным приложением (как описано здесь). Папка также может содержать файл build.gradle
с зависимостями, которые должны быть разрешены Gradle (пример). Наконец, папка может также содержать ноль или более файлов ProGuard (экспериментально).ios
- Эта папка принимает файл-заглушку манифеста, который должен быть объединен с основным приложением (как описано здесь).osx
- Эта папка принимает файл-заглушку манифеста, который должен быть объединен с основным приложением (как описано здесь).web
- Эта папка принимает файл-заглушку манифеста, который должен быть объединен с основным приложением (как описано здесь).Расширения рассматриваются так же, как и любые другие ассеты в вашем проекте, и ими можно делиться таким же образом. Если папка нативного расширения добавлена в качестве папки библиотеки, она может быть совместно использована другими пользователями как зависимость. Для получения дополнительной информации обратитесь к руководству Library project manual.
Давайте создадим очень простое расширение. Сначала создадим новую корневую папку myextension и добавим в нее файл ext.manifest, содержащий имя расширения “MyExtension”. Обратите внимание, что имя является символом C++ и должно совпадать с первым аргументом DM_DECLARE_EXTENSION
(см. ниже).
# C++ symbol in your extension
name: "MyExtension"
Расширение состоит из одного файла C++, myextension.cpp, который создается в папке “src”.
Исходный файл расширения содержит следующий код:
// myextension.cpp
// Определения расширения lib
#define LIB_NAME "MyExtension"
#define MODULE_NAME "myextension"
// включаем Defold SDK
#include <dmsdk/sdk.h>
static int Reverse(lua_State* L)
{
// Количество ожидаемых элементов в стеке Lua после того,
// как эта структура выйдет из области видимости
DM_LUA_STACK_CHECK(L, 1);
// Проверка и получение строки параметра из стека
char* str = (char*)luaL_checkstring(L, 1);
// Развернем строку
int len = strlen(str);
for(int i = 0; i < len / 2; i++) {
const char a = str[i];
const char b = str[len - i - 1];
str[i] = b;
str[len - i - 1] = a;
}
// Поместим развернутую строку в стек
lua_pushstring(L, str);
// Вернем значение 1
return 1;
}
// Функции, открытые для Lua
static const luaL_reg Module_methods[] =
{
{"reverse", Reverse},
{0, 0}
};
static void LuaInit(lua_State* L)
{
int top = lua_gettop(L);
// Регистрация имен Lua
luaL_register(L, MODULE_NAME, Module_methods);
lua_pop(L, 1);
assert(top == lua_gettop(L));
}
dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params)
{
return dmExtension::RESULT_OK;
}
dmExtension::Result InitializeMyExtension(dmExtension::Params* params)
{
// Инициализация Lua
LuaInit(params->m_L);
printf("Registered %s Extension\n", MODULE_NAME);
return dmExtension::RESULT_OK;
}
dmExtension::Result AppFinalizeMyExtension(dmExtension::AppParams* params)
{
return dmExtension::RESULT_OK;
}
dmExtension::Result FinalizeMyExtension(dmExtension::Params* params)
{
return dmExtension::RESULT_OK;
}
// Defold SDK использует макрос для установки точек входа расширения:
//
// DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)
// MyExtension это символ C++, который содержит все соответствующие данные расширения.
// Он должно совпадать с полем имени в `ext.manifest`
DM_DECLARE_EXTENSION(MyExtension, LIB_NAME, AppInitializeMyExtension, AppFinalizeMyExtension, InitializeMyExtension, 0, 0, FinalizeMyExtension)
Обратите внимание на макрос DM_DECLARE_EXTENSION
, который используется для объявления различных точек входа в код расширения. Первый аргумент символ
должен соответствовать имени, указанному в ext.manifest. Для этого простого примера нет необходимости в точках входа “update” или “on_event”, поэтому в этих местах макросу присваивается 0
.
Теперь осталось только создать проект (Project ▸ Build). Это загрузит расширение в конструктор расширений, который запустит движок с включенным в него новым расширением. Если сборщик столкнется с какими-либо ошибками, появится диалог с ошибками сборки.
Чтобы протестировать расширение, создайте игровой объект и добавьте компонент скрипта с некоторым тестовым кодом:
local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
local reverse_s = myextension.reverse(s)
print(reverse_s) --> ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba
Вот и все! Мы создали полностью работающее нативное расширение.
Как мы видели выше, макрос DM_DECLARE_EXTENSION
используется для объявления различных точек входа в код расширения:
DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)
Точки входа позволят вам запускать код в различных точках жизненного цикла расширения:
app_init
init
- Все API Defold были инициализированы. Это рекомендуемый момент жизненного цикла расширения, когда создаются привязки Lua к коду расширения.init()
файлов скриптов.update
update()
файлов скриптов.on_event
final()
файлов скриптов.final
app_final
Следующие идентификаторы определяются разработчиком на каждой соответствующей платформе:
Журналы сервера сборки доступны, если проект использует нативные расширения. Журнал сервера сборки (log.txt
) загружается вместе с движком при сборке проекта и хранится в файле .internal/%platform%/build.zip
, а также распаковывается в папку сборки вашего проекта.
Помимо названия расширения, файл манифеста может содержать флаги компиляции для конкретной платформы, флаги компоновки, библиотеки и фреймворки. Если файл ext.manifest не содержит сегмента “platforms”, или платформа отсутствует в списке, платформа, для которой вы собираете пакет, будет собрана, но без дополнительных флагов.
Вот пример:
name: "AdExtension"
platforms:
arm64-ios:
context:
frameworks: ["CoreGraphics", "CFNetwork", "GLKit", "CoreMotion", "MessageUI", "MediaPlayer", "StoreKit", "MobileCoreServices", "AdSupport", "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreMotion", "CoreTelephony", "CoreVideo", "Foundation", "GLKit", "JavaScriptCore", "MediaPlayer", "MessageUI", "MobileCoreServices", "OpenGLES", "SafariServices", "StoreKit", "SystemConfiguration", "UIKit", "WebKit"]
flags: ["-stdlib=libc++"]
linkFlags: ["-ObjC"]
libs: ["z", "c++", "sqlite3"]
defines: ["MY_DEFINE"]
armv7-ios:
context:
frameworks: ["CoreGraphics", "CFNetwork", "GLKit", "CoreMotion", "MessageUI", "MediaPlayer", "StoreKit", "MobileCoreServices", "AdSupport", "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreMotion", "CoreTelephony", "CoreVideo", "Foundation", "GLKit", "JavaScriptCore", "MediaPlayer", "MessageUI", "MobileCoreServices", "OpenGLES", "SafariServices", "StoreKit", "SystemConfiguration", "UIKit", "WebKit"]
flags: ["-stdlib=libc++"]
linkFlags: ["-ObjC"]
libs: ["z", "c++", "sqlite3"]
defines: ["MY_DEFINE"]
Допустимыми ключами для компиляционных флагов, специфичных для конкретной платформы, являются:
frameworks
- Фреймворки Apple, которые необходимые для сборки (iOS и OSX)flags
- Флаги, которые должны быть переданы компиляторуlinkFlags
- Флаги, которые должны быть переданы компоновщикуlibs
- Библиотеки, необходимые включения при компоновкеdefines
- Определения установки при сборкеaaptExtraPackages
- Отдельное имя пакета, которое должно быть сгенерировано (Android)aaptExcludePackages
- Регулярные выражения (или точные названия) пакетов для исключения (AndroidaaptExcludeResourceDirs
- Регулярные выражения (или точные названия) каталоги ресурсов для исключения (Android)Портал ассетов в Defold, также содержит много нативных расширений.
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB