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

ネイティブ拡張

Lua では対応できない低レベルで、外部のソフトウェアやハードウェアと独自に連携する必要がある場合は、Defold SDK を使ってエンジンの拡張を作成できます。対象プラットフォームに応じて、C、C++、C#、Objective-C、Java、JavaScript を使用できます。ネイティブ拡張(native extension)の代表的な用途は次のとおりです。

  • 携帯電話のカメラなど、特定のハードウェアとの連携。
  • 外部の低レベル API との連携。たとえば、Luasocket を利用できるネットワーク API を通じた連携に対応していない広告ネットワーク API などです。
  • 高速な計算とデータ処理。

C# のサポートは実験的なもので、Defold のスクリプトコンポーネント(script component)ではなく、ネイティブ拡張を対象としています。.NET 9 NativeAOT を使って静的ライブラリを生成します。拡張の src フォルダーに .cs ソースファイルを追加すると、ビルドサービスがプロジェクトファイルを生成します。対象プラットフォームのサポート範囲は、現在の NativeAOT とビルドサービスの対応状況に従います。現在のワークフローとテスト済みの構成については、公式のネイティブ拡張の言語サンプルを参照してください。

ビルドサーバー

Defold はクラウドベースのビルド機能により、セットアップ不要でネイティブ拡張を使い始められる仕組みを提供しています。作成したネイティブ拡張は、直接、またはライブラリプロジェクト(Library Project)を通じてゲームプロジェクトに追加すると、通常のプロジェクトコンテンツの一部になります。特別なバージョンのエンジンをビルドしてチームメンバーに配布する必要はありません。これは自動的に処理され、プロジェクトをビルドして実行するチームメンバーは、すべてのネイティブ拡張が組み込まれた、そのプロジェクト専用のエンジン実行ファイルを取得できます。

クラウドビルド

Defold は、使用制限のないクラウドビルドサーバーを無料で提供しています。サーバーはヨーロッパに設置されています。ネイティブコードの送信先 URL は、エディターの環境設定ウィンドウ、または bob--build-server コマンドラインオプションで設定します。独自のサーバーをセットアップする場合は、こちらの手順に従ってください。

プロジェクトの構成

新しい拡張を作成するには、プロジェクトのルートにフォルダーを作成します。このフォルダーには、拡張に関連するすべての設定、ソースコード、ライブラリ、リソース(resource)を格納します。拡張ビルダーはフォルダー構造を認識し、ソースファイルとライブラリを収集します。

 myextension/
 │
 ├── ext.manifest
 │
 ├── src/
 │
 ├── include/
 │
 ├── lib/
 │   └──[platforms]
 │
 ├── manifests/
 │   └──[platforms]
 │
 └── res/
     └──[platforms]

ext.manifest
拡張フォルダーには ext.manifest ファイルを 必ず 格納する必要があります。この設定ファイルには、個々の拡張をビルドする際に使うフラグと定義を記述します。ファイル形式の定義は、拡張マニフェストのマニュアルを参照してください。
src
このフォルダーには、すべてのソースコードファイルを格納します。
include
この任意のフォルダーには、インクルードファイルを格納します。
lib
この任意のフォルダーには、拡張が依存するコンパイル済みライブラリを格納します。ライブラリファイルは、ライブラリが対応するアーキテクチャに応じて、platform または architecture-platform という名前のサブフォルダーに配置します。

サポートされるプラットフォームは iosandroidosxwin32linuxweb です。

サポートされる arc-platform の組み合わせは arm64-iosarm64_sim-iosarmv7-androidarm64-androidx86_64-androidarm64-osxx86_64-osxx86-win32x86_64-win32arm64-linuxx86_64-linuxwasm-web、および wasm_pthread-web です。

manifests
この任意のフォルダーには、ビルドまたはバンドル作成の処理で使う追加ファイルを格納します。詳しくは後述します。
res
この任意のフォルダーには、拡張が依存する追加リソースを格納します。リソースファイルは、lib のサブフォルダーと同様に、platform または architecture-platform という名前のサブフォルダーに配置します。すべてのプラットフォームに共通するリソースファイルを格納する common サブフォルダーも使用できます。

マニフェストファイル

拡張の任意の manifests フォルダーには、ビルドとバンドル作成の処理で使う追加ファイルを格納します。ファイルは、platform という名前のサブフォルダーに配置します。

  • android - このフォルダーには、メインアプリケーションにマージするマニフェストのスタブファイルを配置できます(こちらで説明しています)。
    • このフォルダーには、Gradle で解決する依存関係を記述した build.gradle ファイルも配置できます。
    • さらに、このフォルダーには0個以上の ProGuard ファイルを配置できます(実験的な機能です)。
  • ios - このフォルダーには、メインアプリケーションにマージするマニフェストのスタブファイルを配置できます(こちらで説明しています)。
    • このフォルダーには、Cocoapods で解決する依存関係を記述した Podfile ファイルも配置できます。
  • osx - このフォルダーには、メインアプリケーションにマージするマニフェストのスタブファイルを配置できます(こちらで説明しています)。
  • web - このフォルダーには、メインアプリケーションにマージするマニフェストのスタブファイルを配置できます(こちらで説明しています)。

拡張の共有

拡張はプロジェクト内のほかのアセット(asset)と同じように扱われ、同じ方法で共有できます。ネイティブ拡張のフォルダーを Library フォルダーとして追加すると、プロジェクトの依存関係としてほかのユーザーと共有し、利用してもらえます。詳しくは、ライブラリプロジェクトのマニュアルを参照してください。

単純な拡張の例

とても単純な拡張をビルドしてみましょう。まず、ルートに新しいフォルダー myextension を作成し、拡張の名前「MyExtension」を記述したファイル ext.manifest を追加します。この名前は C++ のシンボルであり、DM_DECLARE_EXTENSION の最初の引数と一致する必要がある点に注意してください(後述します)。

マニフェスト

# C++ symbol in your extension
name: "MyExtension"

この拡張は、「src」フォルダーに作成する1つの C++ ファイル myextension.cpp で構成されます。

C++ ファイル

拡張のソースファイルには、次のコードを記述します。

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

拡張コードへの各エントリーポイントを宣言するマクロ DM_DECLARE_EXTENSION に注目してください。最初の引数 symbol は、ext.manifest で指定した名前と一致する必要があります。この単純な例では、updateon_event のエントリーポイントは不要なので、マクロのそれらの位置には 0 を指定しています。

あとはプロジェクトをビルドするだけです(Project ▸ Build)。拡張が拡張ビルダーにアップロードされ、新しい拡張を組み込んだカスタムエンジンが生成されます。ビルダーでエラーが発生すると、ビルドエラーを表示するダイアログが開きます。

拡張をテストするには、ゲームオブジェクト(game object)を作成し、テストコードを記述したスクリプトコンポーネントを追加します。

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 - すべての Defold API の初期化が完了しています。拡張コードへの Lua バインディングは、拡張のライフサイクルのこの時点で作成することをお勧めします。
    • スクリプトの初期化 - スクリプトファイルの init() 関数が呼び出されます。
  • エンジンのループ
    • エンジンの更新
      • 拡張の update
      • スクリプトの更新 - スクリプトファイルの update() 関数が呼び出されます。
    • エンジンのイベント(ウィンドウの最小化、最大化など)
      • 拡張の on_event
  • エンジンの終了(または再起動)
    • スクリプトの終了処理 - スクリプトファイルの final() 関数が呼び出されます。
    • 拡張の final
    • 拡張の app_final

定義されるプラットフォーム識別子

各プラットフォームでは、ビルダーによって対応する次の識別子が定義されます。

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

ビルドサーバーのログ

プロジェクトでネイティブ拡張を使用している場合は、ビルドサーバーのログを利用できます。ビルドサーバーのログ(log.txt)は、プロジェクトのビルド時にカスタムエンジンとともにダウンロードされます。ファイル .internal/%platform%/build.zip 内に格納されるほか、プロジェクトのビルドフォルダーにも展開されます。

拡張のサンプル

Defold Asset Portal にも、いくつかのネイティブ拡張があります。