見出し画像

Unity(WebGL)のC#とブラウザのJavaScriptの連携

Unity(WebGL)のC#とブラウザのJavaScriptの連携方法をまとめました。

1. Unity(WebGL)のC#とブラウザのJavaScriptの連携

Unity(WebGL)のC#とブラウザのJavaScript連携させることで、次のようなことを実現できます。

・Unity(WebGL)からHTMLテンプレート上の他の要素を操作。
・Unity(WebGL)からブラウザが提供するWeb APIを利用。
・Webアプリの部品としてUnity(WebGL)を利用。

2. Unity(WebGL)のC#からブラウザのJavaScriptを呼び出す

Unityプロジェクトに「JavaScriptプラグイン」を追加し、Unity(WebGL)のC#から「JavaScriptプラグイン」の関数を呼び出します。「JavaScriptプラグイン」から、Webブラウザの標準API(alert(), console.log())、およびHTMLテンプレートで定義されてるWeb APIを呼び出すことができます。

画像2

Unity(WebGL)のC#からJavaScriptを呼び出す手順は、次のとおり。

(1) Assetsフォルダ直下にPluginsフォルダを作成し、JavaScriptプラグイン(sample.jslib)を追加。

・Assets/Plugins/sample.jslib

mergeInto(LibraryManager.library, {

  // 関数呼び出し
  Hello: function () {
    window.alert("Hello, world!");
  },

  // 数値型の引数と戻り値
  AddNumbers: function (x, y) {
    return x + y;
  },

  // 数値型以外の型の引数
  PrintFloatArray: function (array, size) {
    for(var i = 0; i < size; i++)
      console.log(HEAPF32[(array >> 2) + i]);
  },

  // 文字列型の引数
  HelloString: function (str) {
    window.alert(Pointer_stringify(str));
  },

  // 文字列の戻り値
  StringReturnValueFunction: function () {
    var returnStr = "bla";
    var bufferSize = lengthBytesUTF8(returnStr) + 1;
    var buffer = _malloc(bufferSize);
    stringToUTF8(returnStr, buffer, bufferSize);
    return buffer;
  },

  // WebGLテクスチャのバインド
  BindWebGLTexture: function (texture) {
    GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
  },
});

(2) Hierarchyウィンドウに空のゲームオブジェクトを作成し、以下のスクリプトを追加。
Unity(WebGL)のC#からJavaScriptプラグインを呼び出すコードになります。

・Assets/Scripts/JsTest.cs

using UnityEngine;
using System.Runtime.InteropServices;

public class JsTest : 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();

        // 数値型の引数と戻り値
        int result = AddNumbers(5, 7);
        Debug.Log(result);

        // 数値型以外の型の引数
        float[] myArray = new float[10];
        PrintFloatArray(myArray, myArray.Length);

        // 文字列型の引数
        HelloString("This is a string.");

        // 文字列の戻り値
        Debug.Log(StringReturnValueFunction());

        // WebGLテクスチャのバインド
        var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
        BindWebGLTexture(texture.GetNativeTextureID());
    }
}

(3) ビルドして実行。
アラートやJavaScriptコンソールのログとして結果が出力されます。

3. JavaScriptプラグインの詳細

「JavaScriptプラグイン」の詳細は、次のとおり。

◎ JavaScriptプラグインの関数のインポート
UnityのC#からJavaScriptプラグインの関数を利用するには、「DllImport」と「extern」で関数のインポートを宣言する必要があります。

[DllImport("__Internal")]
private static extern void 関数名();

◎ 数値型の引数と戻り値
数値型の引数と戻り値は、変換なし利用できます。

int result = AddNumbers(5, 7);    ... Unity(WebGL)のC#

    ↓

AddNumbers: function (x, y) {    ... JavaScriptプラグイン
  return x + y;
},

◎ 数値型以外の型の引数
数値型以外の型(数値型配列など)の引数は、emscriptenヒープのポインタとして渡します。

float[] myArray = new float[10];    ... Unity(WebGL)のC#
PrintFloatArray(myArray, myArray.Length);

    ↓

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

emscriptenはオープンソースのトランスコンパイラで、これを利用することで、C言語やC++で書かれたプログラムをasm.jsに変換しています。emscriptenヒープにアクセスするには、以下の型付き配列バッファを利用します。

・HEAP8: 8ビットの符号付きメモリ
・HEAP16: 16ビットの符号付きメモリ
・HEAP32: 32ビットの符号付きメモリ
・HEAPU8: 8ビットの符号なしメモリ
・HEAPU16: 16ビットの符号なしメモリ
・HEAPU32: 32ビットの符号なしメモリ
・HEAPF32: 32ビットの浮動小数メモリ
・HEAPF64: 64ビットの浮動小数メモリ

◎ 文字列型の引数
文字列型の引数は、Pointer_stringify()を使用して、emscriptenヒープのポインタからJavaScript文字列に変換できます。

HelloString("This is a string.");    ... Unity(WebGL)のC#

    ↓

HelloString: function (str) {    ... JavaScriptプラグイン
  window.alert(Pointer_stringify(str));
},

◎ 文字列型の戻り値
文字列型の戻り値は、_malloc()でメモリを割り当てた後、stringToUTF8()でJavaScript文字列を書き込む必要があります。このメモリの解放はil2cppランタイムが行います。

Debug.Log(StringReturnValueFunction());    ... Unity(WebGL)のC#

    ↓

StringReturnValueFunction: function () {    ... JavaScriptプラグイン
  var returnStr = "bla";
  var bufferSize = lengthBytesUTF8(returnStr) + 1;
  var buffer = _malloc(bufferSize);
  stringToUTF8(returnStr, buffer, bufferSize);
  return buffer;
},

◎ WebGLテクスチャのバインド
WebGLテクスチャにアクセスするために、emscriptenはGL.textures配列を提供します。これによって、UnityからWebGLテクスチャをバインドして、テクスチャIDを取得することができます。

var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);    ... Unity(WebGL)のC#
BindWebGLTexture(texture.GetNativeTextureID());

    ↓

BindWebGLTexture: function (texture) {    ... JavaScriptプラグイン
  GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
},

JavaScript関数との相互作用について詳しくは、emscriptenのドキュメントを参照してください。

4. ブラウザスのJavaScriptからUnity(WebGL)のC#を呼び出す

ブラウザのJavaScript、またはJavaScriptプラグインから、gameInstance.SendMessage()を呼ぶことで、Unity(WebGL)内のゲームオブジェクトのメソッドを呼ぶことができます。

画像2

ブラウザのJavaScriptからUnity(WebGL)のC#を呼び出す手順は、次のとおり。

(1) HTMLテンプレート「index.html」に、gameInstance.SendMessage()を呼ぶコードを追加。
ボタン押下時に呼んでいます。

     <script>
     function onClick() {
         gameInstance.SendMessage('JsTest', 'SetText', 'This is a text.');
     }
     </script>
     <input type="button" value="OK" onClick="onClick()" />

gameInstance.SendMessage()の引数の意味は、次のとおり。

SendMessage(objectName, methodName, value...);
・objectName: シーン内のオブジェクト名。
・methodName: オブジェクトにアタッチされているメソッド名。
・value: 引数(文字列、数字など)。

(2) UnityのシーンにUIコンポーネント「Text」を追加。
ブラウザのJavaScriptから渡された文字列を表示します。

(3) ゲームオブジェクト「JsTest」のスクリプト「JsTest」に以下のコードを追加。

public Text label;

public void SetText(string text)
{
    label.text = text;
}

(4) UIコンポーネント「Text」をコンポーネント「JsTest」のlabelにドラッグ&ドロップ。

(5) ビルドして実行。
OKボタンを押すと、ラベルの文字列が変わります。


この記事が気に入ったらサポートをしてみませんか?