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
Jeśli potrzebujesz niestandardowej integracji z zewnętrznym oprogramowaniem lub sprzętem na niskim poziomie, gdzie Lua nie wystarcza, Defold SDK pozwala pisać rozszerzenia do silnika w C, C++, C#, Objective-C, Java lub JavaScript, zależnie od platformy docelowej. Typowe zastosowania natywnych rozszerzeń to:
Obsługa C# jest eksperymentalna i przeznaczona dla natywnych rozszerzeń, a nie dla komponentów skryptowych Defold. Używa .NET 9 NativeAOT do utworzenia biblioteki statycznej; dodaj pliki źródłowe .cs do folderu src rozszerzenia, a usługa budowania wygeneruje plik projektu. Obsługiwane platformy zależą od bieżących możliwości NativeAOT i usługi budowania. Aktualny przepływ pracy i przetestowaną konfigurację przedstawia oficjalny przykład języków dla natywnych rozszerzeń.
Defold udostępnia gotowy punkt startowy do pracy z natywnymi rozszerzeniami dzięki chmurowemu rozwiązaniu do budowania. Każde natywne rozszerzenie, które zostanie dodane do projektu gry, bezpośrednio lub przez Library Project, staje się częścią zwykłej zawartości projektu. Nie ma potrzeby budowania specjalnych wersji silnika i rozsyłania ich do członków zespołu. Robi się to automatycznie - każdy członek zespołu, który zbuduje i uruchomi projekt, otrzyma plik wykonywalny silnika specyficzny dla projektu, z wszystkimi natywnymi rozszerzeniami wbudowanymi na stałe.

Defold udostępnia serwer budowania w chmurze bezpłatnie i bez żadnych ograniczeń użycia. Serwer jest hostowany w Europie, a URL, pod który wysyłany jest kod natywny, konfiguruje się w oknie Editor Preferences albo przez opcję wiersza poleceń --build-server narzędzia bob. Jeśli chcesz uruchomić własny serwer, postępuj zgodnie z tymi instrukcjami.
Aby utworzyć nowe rozszerzenie, utwórz folder w katalogu głównym projektu. Ten folder będzie zawierał wszystkie ustawienia, kod źródłowy, biblioteki i zasoby związane z rozszerzeniem. Serwer budowania rozpoznaje strukturę folderów i zbiera wszystkie pliki źródłowe oraz biblioteki.
myextension/
│
├── ext.manifest
│
├── src/
│
├── include/
│
├── lib/
│ └──[platforms]
│
├── manifests/
│ └──[platforms]
│
└── res/
└──[platforms]
platform albo architecture-platform, zależnie od tego, jakie architektury są obsługiwane przez twoje biblioteki.
Obsługiwane platformy to ios, android, osx, win32, linux, web.
Obsługiwane pary arc-platform to arm64-ios, arm64_sim-ios, armv7-android, arm64-android, x86_64-android, arm64-osx, x86_64-osx, x86_64-win32, arm64-linux, x86_64-linux, wasm-web oraz wasm_pthread-web.
platform albo architecture-platform, tak samo jak podfoldery w lib. Dozwolony jest też podfolder common, zawierający pliki zasobów wspólne dla wszystkich platform.Opcjonalny folder manifests rozszerzenia zawiera dodatkowe pliki używane podczas procesu budowania i pakowania. Pliki należy umieszczać w podfolderach nazwanych według platform:
android - Ten folder przyjmuje plik-szablon manifestu, który zostanie scalony z główną aplikacją (jak opisano tutaj).
build.gradle z zależnościami rozwiązywanymi przez Gradle..keep) dla klas potrzebnych w czasie działania.ios - Ten folder przyjmuje plik-szablon manifestu, który zostanie scalony z główną aplikacją (jak opisano tutaj).
Podfile z zależnościami rozwiązywanymi przez CocoaPods.SwiftPackages.json z zależnościami rozwiązywanymi przez Swift Package Manager.osx - Ten folder przyjmuje plik-szablon manifestu, który zostanie scalony z główną aplikacją (jak opisano tutaj).
Podfile z zależnościami rozwiązywanymi przez CocoaPods.SwiftPackages.json z zależnościami rozwiązywanymi przez Swift Package Manager.web - Ten folder przyjmuje plik-szablon manifestu, który zostanie scalony z główną aplikacją (jak opisano tutaj).Dodaj plik .keep do katalogu manifests/android rozszerzenia, obok build.gradle. Na przykład plik /myextension/manifests/android/myextension.keep może zachowywać klasy Java rozszerzenia za pomocą reguły:
-keep,allowoptimization class com.example.myextension.** { *; }
Zastąp com.example.myextension pakietem zawierającym klasy Java rozszerzenia. Ta reguła zachowuje klasy i ich składowe, pozwalając R8 optymalizować ich kod. Dodaj reguły dla innych klas używanych przez Java Native Interface (JNI) lub mechanizm refleksji, ponieważ R8 może nie wykryć takich odwołań automatycznie.
Jeśli rozszerzenie korzysta z adnotacji w czasie działania, dodaj również:
-keepattributes *Annotation*
Te reguły są łączone z wybranym plikiem reguł projektu po włączeniu R8.
Przy użyciu zgodnego serwera Extender R8 usuwa również nieużywane zasoby Androida. Jeśli rozszerzenie wyszukuje zasoby dynamicznie według nazwy, dodaj reguły zachowywania zasobów w formacie XML w katalogu res/android/res/raw w folderze rozszerzenia.
Rozszerzenie może dołączać dane do archiwum gry, deklarując zasoby niestandardowe w pliku ext.properties obok ext.manifest:
[project]
custom_resources.default = /myextension/data
Na przykład umieść plik JSON w /myextension/data/settings.json. Ścieżka jest względna wobec katalogu głównego projektu i zawiera folder rozszerzenia. Udostępniając rozszerzenie jako bibliotekę, dodaj myextension do ustawienia Include Dirs biblioteki, aby korzystające z niej projekty otrzymały rozszerzenie wraz z danymi.
Te ścieżki są łączone z project.custom_resources z pliku game.project oraz ze ścieżkami dostarczanymi przez inne rozszerzenia. Ustawienie zasobów niestandardowych w projekcie nie zastępuje zasobów pochodzących z rozszerzeń. Pliki są dołączane zarówno podczas budowania w edytorze, jak i do archiwów tworzonych przez Bob, a w czasie działania można je wczytać:
local data, err = sys.load_resource("/myextension/data/settings.json")
if data then
local settings = json.decode(data)
pprint(settings)
else
print(err)
end
Różnice między zasobami niestandardowymi a zasobami pakietu opisano w instrukcji dostępu do plików.
Rozszerzenia są traktowane tak samo jak inne zasoby w projekcie i można je udostępniać w ten sam sposób. Jeśli folder natywnego rozszerzenia zostanie dodany jako folder biblioteki, można go udostępniać i używać jako zależności projektu. Więcej informacji znajdziesz w instrukcji o bibliotekach.
Zbudujmy bardzo proste rozszerzenie. Najpierw tworzymy nowy folder główny myextension i dodajemy plik ext.manifest zawierający nazwę rozszerzenia MyExtension. Zwróć uwagę, że ta nazwa jest symbolem C++ i musi odpowiadać pierwszemu argumentowi DM_DECLARE_EXTENSION (patrz niżej).

# C++ symbol in your extension
name: "MyExtension"
Rozszerzenie składa się z jednego pliku C++, myextension.cpp, który tworzymy w folderze src.

Plik źródłowy rozszerzenia zawiera następujący kod:
// myextension.cpp
// Extension lib defines
#define LIB_NAME "MyExtension"
#define MODULE_NAME "myextension"
// include the Defold SDK
#include <dmsdk/sdk.h>
static int Reverse(lua_State* L)
{
// The number of expected items to be on the Lua stack
// once this struct goes out of scope
DM_LUA_STACK_CHECK(L, 1);
// Check and get parameter string from stack
char* str = (char*)luaL_checkstring(L, 1);
// Reverse the string
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;
}
// Put the reverse string on the stack
lua_pushstring(L, str);
// Return 1 item
return 1;
}
// Functions exposed to Lua
static const luaL_reg Module_methods[] =
{
{"reverse", Reverse},
{0, 0}
};
static void LuaInit(lua_State* L)
{
int top = lua_gettop(L);
// Register lua names
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)
{
// Init 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 uses a macro for setting up extension entry points:
//
// DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)
// MyExtension is the C++ symbol that holds all relevant extension data.
// It must match the name field in the `ext.manifest`
DM_DECLARE_EXTENSION(MyExtension, LIB_NAME, AppInitializeMyExtension, AppFinalizeMyExtension, InitializeMyExtension, 0, 0, FinalizeMyExtension)
Zwróć uwagę na makro DM_DECLARE_EXTENSION, które służy do deklarowania różnych punktów wejścia do kodu rozszerzenia. Pierwszy argument symbol musi odpowiadać nazwie podanej w ext.manifest. W tym prostym przykładzie nie ma potrzeby definiować żadnych punktów wejścia update ani on_event, więc w tych miejscach do makra przekazano 0.
Teraz wystarczy zbudować projekt (Project ▸ Build). Spowoduje to wysłanie rozszerzenia do serwera budowania, który wygeneruje własny silnik z nowym rozszerzeniem wbudowanym na stałe. Jeśli serwer budowania napotka jakiekolwiek błędy, pojawi się okno dialogowe z błędami budowania.
Aby przetestować rozszerzenie, utwórz obiekt gry i dodaj do niego komponent skryptu z krótkim kodem testowym:
local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
local reverse_s = myextension.reverse(s)
print(reverse_s) --> ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba
I to wszystko! Utworzyliśmy w pełni działające natywne rozszerzenie.
Jak widzieliśmy wyżej, makro DM_DECLARE_EXTENSION służy do deklarowania różnych punktów wejścia do kodu rozszerzenia:
DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)
Punkty wejścia pozwalają uruchamiać kod w różnych momentach cyklu życia rozszerzenia:
app_initinit - wszystkie API Defold są już zainicjalizowane. To zalecany moment w cyklu życia rozszerzenia na utworzenie wiązań Lua do kodu rozszerzenia.init() plików skryptów.updateupdate() plików skryptów.on_eventfinal() plików skryptów.finalapp_finalNastępujące identyfikatory są definiowane przez serwer budowania dla każdej odpowiedniej platformy:
DM_PLATFORM_WINDOWSDM_PLATFORM_OSXDM_PLATFORM_IOSDM_PLATFORM_ANDROIDDM_PLATFORM_LINUXDM_PLATFORM_HTML5Dzienniki serwera budowania są dostępne, gdy projekt korzysta z natywnych rozszerzeń. Dziennik serwera budowania (log.txt) jest pobierany razem z własnym silnikiem podczas budowania projektu, przechowywany w pliku .internal/%platform%/build.zip i rozpakowywany także do folderu budowania projektu.
Portal zasobów Defold także zawiera kilka natywnych rozszerzeń.