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
Se devi interagire in modo personalizzato con software o hardware esterni a basso livello e Lua non è sufficiente, l’SDK di Defold permette di scrivere estensioni del motore in C, C++, C#, Objective-C, Java o JavaScript, a seconda della piattaforma di destinazione. Alcuni casi d’uso tipici delle estensioni native sono:
Il supporto a C# è sperimentale ed è destinato alle estensioni native, non ai componenti script di Defold. Usa .NET 9 NativeAOT per produrre una libreria statica; aggiungi i file sorgente .cs alla cartella src di un’estensione e il servizio di build genererà il file di progetto. Le piattaforme di destinazione supportate dipendono dalle capacità attuali di NativeAOT e del servizio di build. Consulta l’esempio ufficiale dei linguaggi per le estensioni native per il flusso di lavoro attuale e la configurazione verificata.
Defold permette di iniziare a usare le estensioni native senza alcuna configurazione, grazie a una soluzione di build nel cloud. Ogni estensione nativa sviluppata e aggiunta a un progetto di gioco, direttamente o tramite un progetto libreria, diventa parte del normale contenuto del progetto. Non occorre creare versioni speciali del motore e distribuirle ai membri del team: tutto questo viene gestito automaticamente. Ogni membro del team che crea una build ed esegue il progetto ottiene un eseguibile del motore specifico per quel progetto, con tutte le estensioni native integrate.

Defold mette a disposizione gratuitamente il server di build nel cloud, senza limitazioni d’uso. Il server è ospitato in Europa e l’URL a cui viene inviato il codice nativo si configura nella finestra delle preferenze dell’editor oppure tramite l’opzione a riga di comando --build-server di bob. Se desideri configurare un tuo server, segui queste istruzioni.
Per creare una nuova estensione, crea una cartella nella radice del progetto. Questa cartella conterrà tutte le impostazioni, il codice sorgente, le librerie e le risorse associate all’estensione. Il servizio di build delle estensioni riconosce la struttura delle cartelle e raccoglie tutti i file sorgente e le librerie.
myextension/
│
├── ext.manifest
│
├── src/
│
├── include/
│
├── lib/
│ └──[platforms]
│
├── manifests/
│ └──[platforms]
│
└── res/
└──[platforms]
platform o architecture-platform, a seconda delle architetture supportate dalle librerie.
Le piattaforme supportate sono ios, android, osx, win32, linux, web.
Le coppie arc-platform supportate sono 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 e wasm_pthread-web.
platform o architecture-platform, come per le sottocartelle di lib. È consentita anche una sottocartella common, contenente i file delle risorse comuni a tutte le piattaforme.La cartella facoltativa manifests di un’estensione contiene file aggiuntivi usati nel processo di build e di creazione del bundle. I file vanno collocati in sottocartelle denominate secondo lo schema platform:
android - Questa cartella accetta un frammento di file manifest da unire a quello dell’applicazione principale (come descritto qui).
build.gradle con dipendenze da risolvere tramite Gradle..keep) per le classi necessarie a runtime.ios - Questa cartella accetta un frammento di file manifest da unire a quello dell’applicazione principale (come descritto qui).
Podfile con dipendenze da risolvere tramite Cocoapods.osx - Questa cartella accetta un frammento di file manifest da unire a quello dell’applicazione principale (come descritto qui).web - Questa cartella accetta un frammento di file manifest da unire a quello dell’applicazione principale (come descritto qui).Aggiungi un file .keep alla directory manifests/android dell’estensione, accanto a build.gradle. Per esempio, /myextension/manifests/android/myextension.keep può conservare le classi Java dell’estensione con:
-keep,allowoptimization class com.example.myextension.** { *; }
Sostituisci com.example.myextension con il package che contiene le classi Java della tua estensione. Questa regola conserva le classi e i loro membri, consentendo a R8 di ottimizzarne il codice. Aggiungi regole per le altre classi a cui accedi tramite Java Native Interface (JNI) o reflection, poiché R8 potrebbe non rilevare automaticamente questi utilizzi.
Se l’estensione dipende da annotazioni a runtime, includi anche:
-keepattributes *Annotation*
Queste regole vengono combinate con il file di conservazione selezionato nel progetto quando R8 è abilitato.
Un’estensione può includere dati nell’archivio del gioco dichiarando risorse personalizzate in un file ext.properties accanto al suo ext.manifest:
[project]
custom_resources.default = /myextension/data
Per esempio, inserisci un file JSON in /myextension/data/settings.json. Il percorso è relativo alla radice del progetto e include la cartella dell’estensione. Quando condividi l’estensione come libreria, includi myextension in Include Dirs della libreria, affinché i progetti che la usano ricevano l’estensione e i suoi dati.
Questi percorsi vengono combinati con project.custom_resources di game.project e con quelli forniti dalle altre estensioni. Impostare le risorse personalizzate nel progetto non sostituisce quelle fornite dalle estensioni. Sia le build dell’editor sia gli archivi di Bob includono i file, che possono essere caricati a runtime:
local data, err = sys.load_resource("/myextension/data/settings.json")
if data then
local settings = json.decode(data)
pprint(settings)
else
print(err)
end
Consulta Accesso ai file per le differenze tra risorse personalizzate e risorse del bundle.
Le estensioni vengono trattate come qualsiasi altro asset del progetto e possono essere condivise allo stesso modo. Se una cartella di estensione nativa viene aggiunta come cartella di libreria, può essere condivisa e usata da altri come dipendenza del progetto. Consulta il manuale dei progetti libreria per ulteriori informazioni.
Realizza un’estensione molto semplice. Per prima cosa, crea una nuova cartella myextension nella radice e aggiungi un file ext.manifest contenente il nome dell’estensione, “MyExtension”. Il nome è un simbolo C++ e deve corrispondere al primo argomento di DM_DECLARE_EXTENSION (vedi sotto).

# C++ symbol in your extension
name: "MyExtension"
L’estensione è composta da un singolo file C++, myextension.cpp, creato nella cartella “src”.

Il file sorgente dell’estensione contiene il seguente codice:
// 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)
Osserva la macro DM_DECLARE_EXTENSION, usata per dichiarare i vari punti di ingresso nel codice dell’estensione. Il primo argomento, symbol, deve corrispondere al nome specificato in ext.manifest. In questo semplice esempio non servono punti di ingresso update o on_event, quindi in quelle posizioni viene passato 0 alla macro.
Ora basta creare una build del progetto (Project ▸ Build). L’estensione verrà caricata sul servizio di build delle estensioni, che produrrà un motore personalizzato con la nuova estensione inclusa. Se il servizio rileva errori, verrà mostrata una finestra di dialogo con gli errori di build.
Per provare l’estensione, crea un oggetto di gioco (game object) e aggiungi un componente script con del codice di test:
local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
local reverse_s = myextension.reverse(s)
print(reverse_s) --> ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba
Ecco fatto! Hai creato un’estensione nativa completamente funzionante.
Come visto sopra, la macro DM_DECLARE_EXTENSION serve a dichiarare i vari punti di ingresso nel codice dell’estensione:
DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)
I punti di ingresso permettono di eseguire codice in vari momenti del ciclo di vita di un’estensione:
app_init dell’estensioneinit dell’estensione - Tutte le API di Defold sono state inizializzate. Questo è il momento consigliato nel ciclo di vita dell’estensione per creare i binding Lua al codice dell’estensione.init() dei file script.update dell’estensioneupdate() dei file script.on_event dell’estensionefinal() dei file script.final dell’estensioneapp_final dell’estensioneIl servizio di build definisce i seguenti identificatori sulle rispettive piattaforme:
DM_PLATFORM_WINDOWSDM_PLATFORM_OSXDM_PLATFORM_IOSDM_PLATFORM_ANDROIDDM_PLATFORM_LINUXDM_PLATFORM_HTML5I log del server di build sono disponibili quando il progetto usa estensioni native. Il log del server di build (log.txt) viene scaricato insieme al motore personalizzato quando viene creata una build del progetto. Viene conservato nel file .internal/%platform%/build.zip ed estratto anche nella cartella di build del progetto.
Anche l’Asset Portal di Defold contiene diverse estensioni native.