Manuals
Manuals




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

Natywne rozszerzenia

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++, Objective-C, Java lub JavaScript, zależnie od platformy docelowej. Typowe zastosowania natywnych rozszerzeń to:

  • Integracja z konkretnym sprzętem, na przykład z kamerą w telefonie.
  • Integracja z zewnętrznymi niskopoziomowymi API, na przykład z API sieci reklamowych, które nie pozwalają na komunikację sieciową w sposób, w jaki można by użyć Luasocket.
  • Obliczenia o wysokiej wydajności i przetwarzanie danych.

Serwer budowania

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.

Budowanie w chmurze

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.

Układ projektu

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]

ext.manifest
Folder rozszerzenia musi zawierać plik ext.manifest. Jest to plik konfiguracyjny z flagami i definicjami używanymi podczas budowania pojedynczego rozszerzenia. Definicję formatu pliku znajdziesz w instrukcji o manifestach rozszerzenia.
src
Ten folder powinien zawierać wszystkie pliki z kodem źródłowym.
include
Ten opcjonalny folder zawiera pliki include.
lib
Ten opcjonalny folder zawiera wszystkie skompilowane biblioteki, od których zależy rozszerzenie. Pliki biblioteki należy umieszczać w podfolderach nazwanych według 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, x86_64-ios, armv7-android, arm64-android, arm64-osx, x86_64-osx, x86-win32, x86_64-win32, arm64-linux, x86_64-linux, js-web, wasm-web oraz wasm_pthread-web.

manifests
Ten opcjonalny folder zawiera dodatkowe pliki używane podczas procesu budowania lub pakowania. Szczegóły znajdziesz poniżej.
res
Ten opcjonalny folder zawiera dodatkowe zasoby, od których zależy rozszerzenie. Pliki zasobów należy umieszczać w podfolderach nazwanych według 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.

Pliki manifestu

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).
    • Folder może też zawierać plik build.gradle z zależnościami, które mają być rozwiązywane przez Gradle.
    • Na koniec folder może też zawierać zero lub więcej plików ProGuard (eksperymentalnych).
  • ios - Ten folder przyjmuje plik-szablon manifestu, który zostanie scalony z główną aplikacją (jak opisano tutaj).
    • Folder może też zawierać plik Podfile z zależnościami, które mają być rozwiązywane przez CocoaPods.
  • osx - Ten folder przyjmuje plik-szablon manifestu, który zostanie scalony z główną aplikacją (jak opisano tutaj).
  • web - Ten folder przyjmuje plik-szablon manifestu, który zostanie scalony z główną aplikacją (jak opisano tutaj).

Udostępnianie rozszerzenia

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.

Prosty przykład rozszerzenia

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).

Manifest

# Symbol C++ w twoim rozszerzeniu
name: "MyExtension"

Rozszerzenie składa się z jednego pliku C++, myextension.cpp, który tworzymy w folderze src.

Plik C++

Plik źródłowy rozszerzenia zawiera następujący kod:

// myextension.cpp
// Definicje biblioteki rozszerzenia
#define LIB_NAME "MyExtension"
#define MODULE_NAME "myextension"

// dołącz Defold SDK
#include <dmsdk/sdk.h>

static int Reverse(lua_State* L)
{
    // Oczekiwana liczba elementów na stosie Lua
    // po wyjściu tej struktury z zakresu
    DM_LUA_STACK_CHECK(L, 1);

    // Sprawdź i pobierz parametr tekstowy ze stosu
    char* str = (char*)luaL_checkstring(L, 1);

    // Odwróć łańcuch znaków
    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;
    }

    // Umieść odwrócony łańcuch na stosie
    lua_pushstring(L, str);

    // Zwróć 1 element
    return 1;
}

// Funkcje udostępnione do Lua
static const luaL_reg Module_methods[] =
{
    {"reverse", Reverse},
    {0, 0}
};

static void LuaInit(lua_State* L)
{
    int top = lua_gettop(L);

    // Zarejestruj nazwy w 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)
{
    // Zainicjalizuj 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 używa makra do ustawiania punktów wejścia rozszerzenia:
//
// DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)

// MyExtension to symbol C++, który przechowuje wszystkie istotne dane rozszerzenia.
// Musi odpowiadać polu name w `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.

Cykl życia rozszerzenia

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:

  • Start silnika
    • Uruchamiają się systemy silnika
    • Rozszerzenie app_init
    • Rozszerzenie init - wszystkie API Defold są już zainicjalizowane. To zalecany moment w cyklu życia rozszerzenia na utworzenie wiązań Lua do kodu rozszerzenia.
    • Inicjalizacja skryptów - wywoływana jest funkcja init() plików skryptów.
  • Pętla silnika
    • Aktualizacja silnika
      • Rozszerzenie update
      • Aktualizacja skryptów - wywoływana jest funkcja update() plików skryptów.
    • Zdarzenia silnika (minimalizacja/maksymalizacja okna itp.)
      • Rozszerzenie on_event
  • Zamykanie silnika (lub ponowne uruchomienie)
    • Finalizacja skryptów - wywoływana jest funkcja final() plików skryptów.
    • Rozszerzenie final
    • Rozszerzenie app_final

Zdefiniowane identyfikatory platform

Następujące identyfikatory są definiowane przez serwer budowania dla każdej odpowiedniej platformy:

  • DM_PLATFORM_WINDOWS
  • DM_PLATFORM_OSX
  • DM_PLATFORM_IOS
  • DM_PLATFORM_ANDROID
  • DM_PLATFORM_LINUX
  • DM_PLATFORM_HTML5

Dzienniki serwera budowania

Dzienniki 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.

Przykłady rozszerzeń

Portal zasobów Defold także zawiera kilka natywnych rozszerzeń.