【unity3d】c#与js通信

1,551 阅读4分钟

c#与js通信

在项目中使用浏览器 JavaScript 的建议方法是将 JavaScript 源代码添加到项目中,然后直接从脚本代码中调用这些函数。为此,请使用 .jslib 扩展名将包含 JavaScript 代码的文件放置在 Assets 文件夹中的“Plugins”子文件夹下。

举个例子:项目运行时,c#脚本调用js中的函数,alert('hello')

步骤:

  1. 在unity的Assets中新建一个Plugins文件夹,这个文件夹里面的文件扩展名是jslib,用于c#向js传递信息的

image.png

  1. 在Plugins中新建一个CallJs.jslib文件(名称不重要,只要是以.jslib结尾的就行),自行定义,例如内容如下:
mergeInto(LibraryManager.library, {
  // 下面这些都是在c#中调用的方法
  Hello: function () {
   // 这里写你要执行的方法
   window.alert('Hello');
   // 也可以写一个函数,例如handlerClick,这个函数就要在index.html定义了
   // handlerClick()
  }
});

可以参考docs.unity.cn/cn/current/…

  1. 在Assets文件下的Script文件夹中新建一个c#脚本,调用上述函数,内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
public class rayGetObj : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void Hello();
    void Start()
    {
      Hello();
    }
}
  1. 将c#脚本挂载到模型上,例如挂载到相机上

image.png

  1. 最后要打包之后,放在服务器中才能运行,在unity中时运行不了的,会报错。

js与c#通信

有时需要从浏览器的 JavaScript 向 Unity 脚本发送一些数据或通知。建议的做法是调用内容中的游戏对象上的方法。如果要从嵌入在项目中的 JavaScript 插件执行调用,可使用以下代码:

MyGameInstance.SendMessage(objectName, methodName, value);

我们做好项目之后打包出来的东西长这个样子: image.png

这个index.html中的代码长这个样子:  image.png

  1. 在index.html中声明一个myInstance变量,用于保存unityInstance对象
var myInstance;  
createUnityInstance(document.querySelector("#unity-canvas"), {
  dataUrl: "Build/kesheng.data.unityweb",
  frameworkUrl: "Build/kesheng.framework.js.unityweb",
  codeUrl: "Build/kesheng.wasm.unityweb",
  streamingAssetsUrl: "StreamingAssets",
  companyName: "DefaultCompany",
  productName: "kesheng",
  productVersion: "0.1",
}).then((unityInstance) => {
  //保存 unityInstance对象
  myInstance = unityInstance;
}).catch((message) => {
  alert(message);
});
  1. 要调用c#脚本的方法,只要执行一条语句就可以了
// 其中,__objectName__ 是场景中的对象名称;__methodName__ 是当前附加到该对象的脚本中的方法名称;__value__ 可以是字符串、数字,也可为空。
myInstance.SendMessage(__objectName__, __methodName__, __value__);

// 使用方法
function callUnity(msg){
  //js调用C#方法
  myInstance.SendMessage("Canvas","JsCallUnity", msg);
}
  1. unity中的c#脚本代码如下,并将脚本挂载到对应的模型上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d7b867c9175846a9b39f3c8ae4c13ba8~tplv-k3u1fbpfcp-watermark.image?)
public class jsCallUnity : MonoBehaviour
{
    public GameObject floor12;
    private bool flag = false;
    // Start is called before the first frame update
    // Update is called once per frame
    public void JsCallUnity(string msg) {
        Debug.Log(msg);
        flag = !flag;
        floor12.gameObject.SetActive(flag);  
    }
}

image.png

射线检测获取点击模型对象

射线投射从原点沿着射线方向发送假想的“激光束”,直至命中场景中的碰撞体。随后会返回有关该对象和 RaycastHit 对象内的投射命中点的信息。

docs.unity.cn/cn/current/…

射线能检测到模型对象并返回该对象的前提是:模型上要添加一个碰撞器的组件,其他的就是写c#脚本获取了:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
// 要引入的命名空间
using UnityEngine.AI;

public class rayGetObj : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void SayClickName(string str);
    [DllImport("__Internal")]
    private static extern void PrintPos(string str);
    RaycastHit hit;
    // Update is called once per frame
    void Update()
    {
        ClickCollider();
    }
    void ClickCollider() {
        // 检测到物体并且鼠标按下的时候
        if (Input.GetMouseButtonDown(0)) {
            // 射线发射的起始位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            // ui坐标的宽
            // Debug.Log(Camera.main.pixelWidth);
            // ui坐标的高
            // Debug.Log(Camera.main.pixelHeight);
            // Physics.Raycast通过射线检测的方式检测到碰撞的物体
            bool iscollider = Physics.Raycast(ray, out hit);
            if (iscollider) {
                SayClickName(hit.collider.gameObject.name);
                // 点击到的设备物体
                Transform objectHit = hit.transform;
                // 设备物体的transform的position
                Debug.Log(objectHit.position);
                // 世界坐标转视口坐标
                // var point = Camera.main.WorldToViewportPoint(objectHit.position);
                // Debug.Log(point);
                // 世界坐标转ui坐标
                var point1 = Camera.main.WorldToScreenPoint(objectHit.position);
                PrintPos(Camera.main.pixelWidth + "," + Camera.main.pixelHeight + "," + point1.x + "," + point1.y);
            }
        }
    }
}

坐标转换

四种坐标

image.png

世界坐标:是3d坐标,在模型中transform的position的值 image.png 屏幕坐标:屏幕坐标是以像素来定义的,与分辨率有关,例如分辨率为1920*1080的屏幕,则Screen.width为1920,Screen.height为1080;Screen.width = Camera.main.pixelWidth和Screen.height = Camera.main.pixelHeight只有在相机视口坐标是整个屏幕时才满足。  image.png 视角坐标:视口坐标系其实就是将屏幕坐标系单位化,视口坐标的左下角为(0 , 0),右上角为(1 , 1)  image.png ui坐标:它的原点在左上角为(0,0),右下角坐标为(Screen.width, Screen.height), 因为这是一个二维的坐标系,所以坐标z的值永远都为0。 image.png