facebook twitter hatena line email

Unity/WebGL/js連携

提供: 初心者エンジニアの簡易メモ
2025年8月9日 (土) 23:22時点におけるAdmin (トーク | 投稿記録)による版 (unity6000の時のwebglの表示ロード)

(差分) ←前の版 | 最新版 (差分) | 次の版→ (差分)
移動: 案内検索

サンプル

unity-2020.1.2f1のWebGLで動作確認

  • Assets/Plugins/jsconnect.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;
  },
  BindWebGLTexture: function (texture) {
    GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
  },
});
  • Assets/Scripts/JsConnect.cs
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;

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

        var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
        BindWebGLTexture(texture.GetNativeTextureID());
    }
    public Text label;
    public void SetText(string text)
    {
        label.text = text;
    }
}
  1. GameObjectを作成し、名前をJsConnectObjに変更
  2. JsConnectのクラスをJsConnectObjにAddComponentで追加
  3. WebGLでビルド時にHello()のエラーが出るが問題ない。
  • WebGLで出力したindex.htmlにSendMessage()を追加
<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | unsi</title>
    <link rel="shortcut icon" href="TemplateData/favicon.ico">
    <link rel="stylesheet" href="TemplateData/style.css">
  </head>
  <body>
    <div id="unity-container" class="unity-desktop">
      <canvas id="unity-canvas"></canvas>
      <div id="unity-loading-bar">
        <div id="unity-logo"></div>
        <div id="unity-progress-bar-empty">
          <div id="unity-progress-bar-full"></div>
        </div>
      </div>
      <div id="unity-footer">
        <div id="unity-webgl-logo"></div>
        <div id="unity-fullscreen-button"></div>
        <div id="unity-build-title">unsi</div>
      </div>
    </div>
    <script>
      var buildUrl = "Build";
      var loaderUrl = buildUrl + "/write.loader.js";
      var config = {
        dataUrl: buildUrl + "/write.data.br",
        frameworkUrl: buildUrl + "/write.framework.js.br",
        codeUrl: buildUrl + "/write.wasm.br",
        streamingAssetsUrl: "StreamingAssets",
        companyName: "DefaultCompany",
        productName: "unsi",
        productVersion: "1.0",
      };
      var container = document.querySelector("#unity-container");
      var canvas = document.querySelector("#unity-canvas");
      var loadingBar = document.querySelector("#unity-loading-bar");
      var progressBarFull = document.querySelector("#unity-progress-bar-full");
      var fullscreenButton = document.querySelector("#unity-fullscreen-button");

      if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
        container.className = "unity-mobile";
        config.devicePixelRatio = 1;
      } else {
        canvas.style.width = "626px";
        canvas.style.height = "500px";
      }
      loadingBar.style.display = "block";

      var script = document.createElement("script");
      script.src = loaderUrl;
      script.onload = () => {
        createUnityInstance(canvas, config, (progress) => {
          progressBarFull.style.width = 100 * progress + "%";
        }).then((unityInstance) => {
          loadingBar.style.display = "none";
          fullscreenButton.onclick = () => {
            unityInstance.SetFullscreen(1);
          };
          unityInstance.SendMessage('JsConnectObj', 'SetText', 'HelloJavascript!!!'); // add
        }).catch((message) => {
          alert(message);
        });
      };
      document.body.appendChild(script);
    </script>
  </body>
</html>

参考:https://note.com/npaka/n/nca1e35a649e3

unity2020以外のとき

上記ではunity2019-2017まで動作しなかった。(unity5未満は未確認) unityInstanceの直下では、unityが起動してないときに、実行されてしまうようで、ボタンなどからクリックすることで呼び出せた。

<script>
      var unityInstance = UnityLoader.instantiate("unityContainer", "Build/jstest.json", {onProgress: UnityProgress});
</script>
<input type="button" value="クリック" onclick="func1()">
<script>
    var func1 = function () {
unityInstance.SendMessage('JsTest', 'SetText', 'This is a text.');
     }
</script>

unity2020の時のwebglの表示ロード

以下の通りエラーが出る・・

Uncaught ReferenceError: unityFramework is not defined
   at HTMLScriptElement.r.onload (webgl_unsiread.loader.js:1)

unity6000の時のwebglの表示ロード

<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <style>
    <link rel="stylesheet" href="TemplateData/style.css">
  </style>
  </head>
  <body>
    <div id="unity-container" class="unity-desktop">
      <canvas id="unity-canvas" width=626 height=250 tabindex="-1"></canvas>
      <div id="unity-loading-bar">
        <div id="unity-progress-bar-empty">
          <div id="unity-progress-bar-full"></div>
        </div>
      </div>
      <div id="unity-warning"> </div>
    </div>
    <script>
      var canvas = document.querySelector("#unity-canvas");
      function unityShowBanner(msg, type) {
        var warningBanner = document.querySelector("#unity-warning");
        function updateBannerVisibility() {
          warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
        }
        var div = document.createElement('div');
        div.innerHTML = msg;
        warningBanner.appendChild(div);
        if (type == 'error') div.style = 'background: red; padding: 10px;';
        else {
          if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
          setTimeout(function() {
            warningBanner.removeChild(div);
            updateBannerVisibility();
          }, 5000);
        }
        updateBannerVisibility();
      }
      var buildUrl = "Build";
      var loaderUrl = buildUrl + "/webgl_test1.loader.js";
      var config = {
        arguments: [],
        dataUrl: buildUrl + "/webgl_test1.data",
        frameworkUrl: buildUrl + "/webgl_test1.framework.js",
        codeUrl: buildUrl + "/webgl_test1.wasm",
        streamingAssetsUrl: "StreamingAssets",
        companyName: "DefaultCompany",
        productName: "unsiwrite",
        productVersion: "1.1.0",
        showBanner: unityShowBanner,
      };
      if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
        var meta = document.createElement('meta');
        meta.name = 'viewport';
        meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
        document.getElementsByTagName('head')[0].appendChild(meta);
        document.querySelector("#unity-container").className = "unity-mobile";
        canvas.className = "unity-mobile";
      } else {
        canvas.style.width = "626px";
        canvas.style.height = "250px";
      }
      document.querySelector("#unity-loading-bar").style.display = "block";
      var script = document.createElement("script");
      script.src = loaderUrl;
      script.onload = () => {
        createUnityInstance(canvas, config, (progress) => {
          document.querySelector("#unity-progress-bar-full").style.width = 100 * progress + "%";
              }).then((unityInstance) => {
                document.querySelector("#unity-loading-bar").style.display = "none";

                unityInstance.SendMessage('JsConnectObj', 'SetText', 'HelloJavascript!!!'); // add
              }).catch((message) => {
                alert(message);
              });
            };
      document.body.appendChild(script);
    </script>
  </body>
</html>

これで、データをunityが読み込んでくれる。

TemplateData/style.css

#unity-container { position: relative }
#unity-canvas { background: #231F20 }
.unity-mobile #unity-canvas { width: 100%; height: 100% }
#unity-loading-bar { position: absolute; left: 30%; top: 50%; transform: translate(-50%, -50%); display: none }
#unity-logo { width: 154px; height: 130px; background: url('unity-logo-dark.png') no-repeat center }
#unity-progress-bar-empty { width: 141px; height: 18px; margin-top: 10px; margin-left: 6.5px; background: url('progress-bar-empty-dark.png') no-repeat center }
#unity-progress-bar-full { width: 10%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png')  }
#unity-footer { position: relative }
.unity-mobile #unity-footer { display: none }
#unity-logo-title-footer { float:left; width: 102px; height: 38px; background: url('unity-logo-title-footer.png') no-repeat center }
#unity-build-title { float: right; margin-right: 10px; line-height: 38px; font-family: arial; font-size: 18px }
#unity-fullscreen-button { cursor:pointer; float: right; width: 38px; height: 38px; background: url('fullscreen-button.png') no-repeat center }
#unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }

コンテンツかぶりを防ぐためにcssの

#unity-container { position: absolute }

をrelativeにして、ローディングの位置調整で、#unity-loading-barのleftを50%から30%に

ブラウザのconsole.logで"Uncaught TypeError: Cannot read property 'apply' of undefined"エラーが出るとき

Invoking error handler due to
Uncaught TypeError: Cannot read property 'apply' of undefined
20149427-27f7-4cca-ba13-66d3b3d96c55:8 Uncaught TypeError: Cannot read property 'apply' of undefined
    at 20149427-27f7-4cca-ba13-66d3b3d96c55:8
    at Object.ccall (20149427-27f7-4cca-ba13-66d3b3d96c55:8)
    at Object.SendMessage (20149427-27f7-4cca-ba13-66d3b3d96c55:8)
    at Object.SendMessage (UnityLoader.js:4)
    at func1 (645:127)
    at <anonymous>:1:1

起動前にjsが読み込まれてると思われる。

あとは、

ロード画面を用意して、jsをロードが完了したときに、sceneを移動するなどを、やったほうが良い。