WebGL を対象とした場合に必要なメモリへの配慮
WebGL テンプレートの使用

WebGL: ブラウザースクリプトとの相互作用

Web 用のコンテンツを構築するときは、Web ページ上の他の要素と通信する必要があります。また、Web API を使用して Unity が現在デフォルトで公開していない機能を実装したいこともあるかもしれません。 いずれの場合も、ブラウザーの JavaScript エンジンと直接接続する必要があります。Unity WebGL はこれを行うためのさまざまな方法を提供します。

Unity スクリプトを JavaScript 関数から 呼び出す

プロジェクトでブラウザの JavaScript を使用する場合に推奨される方法は、JavaScript ソースをプロジェクトに加えてから、スクリプトコードからこれらの関数を直接呼び出すことです。 これを行うには、Assets フォルダーの Plugins サブフォルダーの下に .jslib 拡張子をつけて (通常の .js は UnityScript コンパイラーによって選択されます) JavaScript コードのファイルを配置します。プラグインファイルには以下のような構文が必要です。

mergeInto(LibraryManager.library, {

  Hello: function () {
    window.alert("Hello, world!");
  },

  HelloString: function (str) {
    window.alert(Pointer_stringify(str));
  },

  PrintFloatArray: function (array, size) {
    for(var i = 0; i < size; i++)
    console.log(HEAPF32[(array >> 2) + i]);
  },

  AddNumbers: function (x, y) {
    return x + y;
  },

  StringReturnValueFunction: function () {
    var returnStr = "bla";
    var bufferSize = lengthBytesUTF8(returnStr) + 1;
    var buffer = _malloc(bufferSize);
    stringToUTF8(returnStr, buffer, bufferSize);
    return buffer;
  },

  BindWebGLTexture: function (texture) {
    GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
  },

});

次に、上記の関数を以下のように C# スクリプトから呼び出します。

using UnityEngine;
using System.Runtime.InteropServices;

public class NewBehaviourScript : MonoBehaviour {

    [DllImport("__Internal")]
    private static extern void Hello();

    [DllImport("__Internal")]
    private static extern void HelloString(string str);

    [DllImport("__Internal")]
    private static extern void PrintFloatArray(float[] array, int size);

    [DllImport("__Internal")]
    private static extern int AddNumbers(int x, int y);

    [DllImport("__Internal")]
    private static extern string StringReturnValueFunction();

    [DllImport("__Internal")]
    private static extern void BindWebGLTexture(int texture);

    void Start() {
        Hello();
        
        HelloString("This is a string.");
        
        float[] myArray = new float[10];
        PrintFloatArray(myArray, myArray.Length);
        
        int result = AddNumbers(5, 7);
        Debug.Log(result);
        
        Debug.Log(StringReturnValueFunction());
        
        var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
        BindWebGLTexture(texture.GetNativeTextureID());
    }
}

単純な数値型は、変換を必要とせずに、関数パラメーターで JavaScript に渡すことができます。他のデータ型は、emscripten ヒープ内のポインターとして渡されます (実際には JavaScript の大きな配列です)。文字列の場合は、Pointer_stringify ヘルパー関数を使用して JavaScript 文字列に変換できます。文字列値を返すには、メモリを割り当てるために _malloc を呼び出し、JavaScript 文字列を書き込むために stringToUTF8 ヘルパー関数を呼び出す必要があります。文字列が戻り値の場合は、il2cpp ランタイムがメモリ解放の処理をします。プリミティブ型の配列の場合、emscripten はメモリを表すさまざまなサイズの整数、符号なし整数、浮動小数点のヒープに対して、異なる ArrayBufferViews を提供します。 HEAP8、HEAPU8、HEAP16、HEAPU16、HEAP32、HEAPU32、HEAPF32、HEAPF64 などです。 WebGL のテクスチャにアクセスするために、emscripten は GL.textures 配列を提供し Unity から WebGL テクスチャオブジェクトへネイティブのテクスチャ ID をマッピングします。WebGL 関数は、emscripten の WebGL コンテキストGLctx で呼び出すことができます。

JavaScript コードを Unity から呼び出す古い方法

注意: Unity 5.6 以降では、Unity から JavaScript コードを呼び出すには .jslib プラグインの使用が推奨されます。以下に説明する方法は、互換性の理由でサポートされており、新しいバージョンの Unity ではサポートが廃止される場合があります。

Application.ExternalCall()Application.ExternalEval() 関数を使って、JavaScript コードが埋め込まれた Web ページでコードを呼び出すことができます。式はビルドのローカルスコープで処理されるということに注意してください。グローバルスコープで JavaScript コードを実行したい場合は、後述の コードの可視性 セクションを参照してください。

Unity スクリプト関数を JavaScript から 呼び出す

ブラウザーの JavaScript から Unity スクリプトにデータや通知の送信が必要な場合があります。推奨される方法は、コンテンツ内でゲームオブジェクトのメソッドを呼び出すことです。プロジェクトに埋め込まれた JavaScript プラグインから呼び出しを行う場合は、以下のコードを使用します。

SendMessage(objectName, methodName, value);

objectName __ はシーンのオブジェクトの名。 methodName __ は、現在オブジェクトにアタッチされているスクリプトのメソッド名です。__value __ には文字列、数字などで、以下の例のように空にしておくことも可能です。

SendMessage('MyGameObject', 'MyFunction');
SendMessage('MyGameObject', 'MyFunction', 5);

SendMessage('MyGameObject', 'MyFunction', 'MyString');

埋め込みページのグローバルスコープから呼び出しをしたい場合は、後述の コードの可視性 セクションを参照してください。

C++ 関数を Unity スクリプトから 呼び出す

Unity は emscripten を使用してソースコードを C++ から JavaScript へとコンパイルしているので、同じように C または C++ でプラグインを書きその関数を C# から呼び出すこともできます。ですから、上の例のような jslib の代わりに、プロジェクトで下のような C ファイルを使用することが可能です。このプラグインは自動でコンパイルされ、上記の JavaScript の例のようにスクリプト側から呼び出すことが可能です。

プラグインを実装するのに C++ (.cpp) を使用する場合は、名前マングリング を避けるために、関数を C リンケージで宣言してください。

# include <stdio.h>
void Hello ()
{
    printf("Hello, world!\n");
}
int AddNumbers (int x, int y)
{
    return x + y;
}

コードの可視性

Unity 5.6 から、すべてのビルドコードはそれ自体のスコープで実行されます。このアプローチを使うと、ページに埋め込まれているコードと矛盾することなく、ページにゲームを埋め込むことが可能になります。また、1 つのページに複数のビルドを埋め込むことが可能になります。

プロジェクト内の JavaScript コードがすべて .jslib プラグインの形式である場合、この JavaScript コードはコンパイルされたビルドと同じスコープ内で実行され、コードは以前のバージョンの Unity とほぼ同じように動作します (例えば、Module、SendMessage、HEAP8、ccall など のオブジェクトと関数は、JavaScript プラグインコードから直接見ることができます)。

ただし、埋め込みページのグローバルスコープから内部の JavaScript 関数を呼び出す場合は、常にページに複数のビルドが埋め込まれていると仮定する必要があります。そのため、どのビルドを参照しているかを明示的に特定する必要があります。以下は、ゲームがインスタンス化されている場合の例です。

var gameInstance = UnityLoader.instantiate("gameContainer", "Build/build.json", {onProgress: UnityProgress});

gameInstance.SendMessage() を使ってビルドにメッセージを送るか、 gameInstance.Module のようなビルドのモジュールオブジェクトにアクセスします。


WebGL を対象とした場合に必要なメモリへの配慮
WebGL テンプレートの使用