Unity——Js和Unity互相呼叫

小紫蘇發表於2021-12-03

Unity專案可以打包成WebGl,打包後的專案檔案:

image-20211203184830096

Build中是打包後的Js程式碼;

Index.html是web專案的入口,裡面可以調整web的自適應,也可以拿去巢狀;

TemplateData是打包時候選的webGl模板;

web端遊戲可能Unity只負責做遊戲部分,而官網由另外的團隊製作,之間就需要Unity和Js程式碼之間的相互呼叫;

Unity呼叫JavaScript

宣告一下,這裡說的都是Unity和外部JS程式碼的互相呼叫,專案內呼叫有其他方法;

老版本提供一個過時的方法

1.在WebGL專案中的Index.html中新增要呼叫的JS方法

function Unity2JavaScript() { alert("UnityToWeb") }

2.Unity中呼叫

Application.ExternalCall("Unity2JavaScript");
//可以有引數,沒有返回值
//Application.ExternalCall("Unity2JavaScript",a,10,"aaaa");

Unity建議使用的方法

1.在Plugins資料夾中,建立字尾為.jslib的檔案,在其中寫需要呼叫的js程式碼

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) + size]);
  },

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

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

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

});

2.Unity中呼叫——__Internal.jslib

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呼叫Unity

這裡面有巨坑,天坑,人都坑傻了!!!

官方文件中有這幾行字

image-20211203222807404

恰好我用的2020版本的Unity;

主要使用這個API——

SendMessage("遊戲物件名","方法名","引數"); 這個和引數和lua呼叫c#差不多了,但是怎麼呼叫這個api就很玄學了;

首先如果你呼叫這個方法需要在Unity的資源已經載入完成才可以,這個好解決,js加個button;

<button Type="button" onclick="TestSend()">WebToUnity</button>

其次在呼叫這個方法前需要先例項化UnityInstance變數;

var gameInstance = null;
script.onload = () => {
		gameInstance = createUnityInstance(document.querySelector("#unity-canvas"), {
        	dataUrl: "Build/Test.data",
        	frameworkUrl: "Build/Test.framework.js",
        	codeUrl: "Build/Test.wasm",
        	streamingAssetsUrl: "StreamingAssets",
        	companyName: "DefaultCompany",
       		productName: "UnityToWeb",
        	productVersion: "0.1",
      });
};
//以上的引數都可以在unity的playersetting介面找到;

最後呼叫時要在then中用lamda表示式

function TestSend() {
	gameInstance.then((unityInstance) => {
		unityInstance.SendMessage("Canvas","OnLogin","dqwreqweraf");        
	});
}

完整的index.html

<!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 | UnityToWeb</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">
	<button Type="button" onclick="TestSend()">WebToUnity</button>
      <canvas id="unity-canvas" width=960 height=600></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-mobile-warning">
        WebGL builds are not supported on mobile devices.
      </div>
      <div id="unity-footer">
        <div id="unity-webgl-logo"></div>
        <div id="unity-fullscreen-button"></div>
        <div id="unity-build-title">UnityToWeb</div>
      </div>
    </div>
    <script>
      var buildUrl = "Build";
      var loaderUrl = buildUrl + "/Test.loader.js";
      var config = {
        dataUrl: buildUrl + "/Test.data",
        frameworkUrl: buildUrl + "/Test.framework.js",
        codeUrl: buildUrl + "/Test.wasm",
        streamingAssetsUrl: "StreamingAssets",
        companyName: "DefaultCompany",
        productName: "UnityToWeb",
        productVersion: "0.1",
      };

      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");
      var mobileWarning = document.querySelector("#unity-mobile-warning");

      // By default Unity keeps WebGL canvas render target size matched with
      // the DOM size of the canvas element (scaled by window.devicePixelRatio)
      // Set this to false if you want to decouple this synchronization from
      // happening inside the engine, and you would instead like to size up
      // the canvas DOM size and WebGL render target sizes yourself.
      // config.matchWebGLToCanvasSize = false;

      if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
        container.className = "unity-mobile";
        // Avoid draining fillrate performance on mobile devices,
        // and default/override low DPI mode on mobile browsers.
        config.devicePixelRatio = 1;
        mobileWarning.style.display = "block";
        setTimeout(() => {
          mobileWarning.style.display = "none";
        }, 5000);
      } else {
        canvas.style.width = "960px";
        canvas.style.height = "600px";
      }
      loadingBar.style.display = "block";

      var script = document.createElement("script");
      script.src = loaderUrl;
	  var gameInstance = null;
      script.onload = () => {
		gameInstance = createUnityInstance(document.querySelector("#unity-canvas"), {
         dataUrl: "Build/Test.data",
        frameworkUrl: "Build/Test.framework.js",
        codeUrl: "Build/Test.wasm",
        streamingAssetsUrl: "StreamingAssets",
        companyName: "DefaultCompany",
        productName: "UnityToWeb",
        productVersion: "0.1",
      });
      };
	  
	  function TestSend() {
            gameInstance.then((unityInstance) => {
            unityInstance.SendMessage("Canvas","OnLogin","dqwreqweraf");        
            });
          }
	  
      document.body.appendChild(script);
    </script>
	
  </body>
</html>

相關文章