c#与js通信
在项目中使用浏览器 JavaScript 的建议方法是将 JavaScript 源代码添加到项目中,然后直接从脚本代码中调用这些函数。为此,请使用 .jslib 扩展名将包含 JavaScript 代码的文件放置在 Assets 文件夹中的“Plugins”子文件夹下。
举个例子:项目运行时,c#脚本调用js中的函数,alert('hello')
步骤:
- 在unity的Assets中新建一个Plugins文件夹,这个文件夹里面的文件扩展名是jslib,用于c#向js传递信息的
- 在Plugins中新建一个CallJs.jslib文件(名称不重要,只要是以.jslib结尾的就行),自行定义,例如内容如下:
mergeInto(LibraryManager.library, {
// 下面这些都是在c#中调用的方法
Hello: function () {
// 这里写你要执行的方法
window.alert('Hello');
// 也可以写一个函数,例如handlerClick,这个函数就要在index.html定义了
// handlerClick()
}
});
可以参考docs.unity.cn/cn/current/…
- 在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();
}
}
- 将c#脚本挂载到模型上,例如挂载到相机上
- 最后要打包之后,放在服务器中才能运行,在unity中时运行不了的,会报错。
js与c#通信
有时需要从浏览器的 JavaScript 向 Unity 脚本发送一些数据或通知。建议的做法是调用内容中的游戏对象上的方法。如果要从嵌入在项目中的 JavaScript 插件执行调用,可使用以下代码:
MyGameInstance.SendMessage(objectName, methodName, value);
我们做好项目之后打包出来的东西长这个样子:
这个index.html中的代码长这个样子:
- 在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);
});
- 要调用c#脚本的方法,只要执行一条语句就可以了
// 其中,__objectName__ 是场景中的对象名称;__methodName__ 是当前附加到该对象的脚本中的方法名称;__value__ 可以是字符串、数字,也可为空。
myInstance.SendMessage(__objectName__, __methodName__, __value__);
// 使用方法
function callUnity(msg){
//js调用C#方法
myInstance.SendMessage("Canvas","JsCallUnity", msg);
}
- unity中的c#脚本代码如下,并将脚本挂载到对应的模型上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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);
}
}
射线检测获取点击模型对象
射线投射从原点沿着射线方向发送假想的“激光束”,直至命中场景中的碰撞体。随后会返回有关该对象和 RaycastHit 对象内的投射命中点的信息。
射线能检测到模型对象并返回该对象的前提是:模型上要添加一个碰撞器的组件,其他的就是写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);
}
}
}
}
坐标转换
四种坐标
世界坐标:是3d坐标,在模型中transform的position的值
屏幕坐标:屏幕坐标是以像素来定义的,与分辨率有关,例如分辨率为1920*1080的屏幕,则Screen.width为1920,Screen.height为1080;Screen.width = Camera.main.pixelWidth和Screen.height = Camera.main.pixelHeight只有在相机视口坐标是整个屏幕时才满足。
视角坐标:视口坐标系其实就是将屏幕坐标系单位化,视口坐标的左下角为(0 , 0),右上角为(1 , 1)
ui坐标:它的原点在左上角为(0,0),右下角坐标为(Screen.width, Screen.height), 因为这是一个二维的坐标系,所以坐标
z
的值永远都为0。