在Unity官方文档中就已经介绍了Unity和JS相互调用的问题,但是我们实际的应用中往往是使用iframe来展示WebGL。这样不但是webgl和js相互调用的问题,还包含了iframe跨域的问题。
我们的项目中前端使用的是angular框架,就以angular为基础来说一下这个问题,当然vue的前端框架应该都一样的原理。
首先说一下unity和js相互调用的问题
Unity和JS的相互调用
unity调用js:
1.首先在Unity/Assets/Plugins目录下存放你需要调用的js。
2.在Plugins目录下新建文本文档__Internal,后缀改为jslib。
3.编写脚本内容。
mergeInto(LibraryManager.library, {
//开启新窗口
OpenUrlWindow:function(str,counts)
{
OpenUrl_Window(Pointer_stringify(str),Pointer_stringify(counts)); //调用js方法
},
//关闭新窗口
CloseUrlWindow:function()
{
CloseUrl_Window();//调用js方法
},
FullScreen:function(){
},
JumpUrl:function(str)
{
Jump_Url(Pointer_stringify(str)); //调用js方法
}
});
我们以JumpUel为例,我们要在C#中引入动态链接库, [DllImport("__Internal")],然后C#中调用JumpUrl函数即可。
4.C#调用。这里我们点击场景中的一个物体就触发这个函数。以上是在unity中的处理。
string str ="unity调用JS";
[DllImport("__Internal")]
private static extern void JumpUrl(string str);
void Start()
{
}
private void OnMouseDown()
{
JumpUrl(str);
}
5.打包成webgl。
6.打包成功后使用VSCode打开index文件,是一个html文件代码。我们在script语句块中编写相应的方法,注意:我们在unity中JumpUrl对应的js方法是Jump_Url不要吧函数名字写错。
function Jump_Url(str){
console.log(str);
}
编写完成后我们打开运行,点击场景中的物体,就会调用js中的方法。
JS调用Unity
js调用unity就相对简单多了。
1.在unity场景中创建一个物体,挂载上要掉用的脚本。
2.在脚本中随便写个方法。 public void Close(){Debug.log("我是Unity");}
3.打包,因为unity的版本不同打出来的包的index内容也不同,只要找到unityInstance,在他下边调用即可。
unityInstance.SendMessage('场景中挂载脚本的物体名','方法名')
unityInstance.SendMessage('场景中挂载脚本的物体名','方法名','方法对应参数')
以上完成了js调用unity的的方法。知道以上的方法以后,并不能真正的解决我们开发中遇到的问题,因为我们往往要使用iframe将webgl嵌入到我们的前端页面,我们需要跨域来相互调用。
iframe跨域调用
iframe跨域调用涉及到父子之间的调用,webgl是子,嵌入到的页面就是父。
父调子(JS调用Unity)
1.父的代码
<!-- html:iframe嵌入 -->
<iframe allowfullscreen="true" id="unity3d" style="width: 100%;height: 100%;padding:2px 2px 0 2px" frameborder="0" scrolling="no"
[src]="Workshop3dAddress | safe">
</iframe>
//js代码
change3D(){
let ifim:any;
ifim =window.document.getElementById('unity3d');
ifim.contentWindow.postMessage("ref",'*')
}
ref会传入到子中,我们可以使用不同的值来区分调用的方法。
2.子的代码
script.onload = () => {
var unitysf;
createUnityInstance(canvas, config, (progress) => {
progressBarFull.style.width = 100 * progress + "%";
}).then((unityInstance) => {
loadingBar.style.display = "none";
unitysf=unityInstance
}).catch((message) => {
alert(message);
});
addEventListener("message",e=>{
console.log("父调用子")
unitysf.SendMessage("JSToUnity","CameraMove");
})
};
addEventListener就是我们监听前端调用的方法。 unitysf=unityInstance不用过多解释。在监听的方法中,我们写入js调用unity的方法,就完成了前端跨域调用unity的方法。e就是父中传过来的参数,根据e的不同我们可以判断调用那个函数。
子调父(Unity调用JS)
1.子的代码
var data ="unity"
data=JSON.parse(JSON.stringify(data));
function Jump_Url(str){
console.log(str);
window.parent.postMessage({
data: JSON.stringify(data)
},'*')
}
这里我们要有两个注意的地方,1是要将data转化一边data=JSON.parse(JSON.stringify(data));
2是 window.parent.postMessage({ data: JSON.stringify(data)},'*')记得在后边加一个*解决跨域的问题。
2.父的代码
var self = this;
window.addEventListener('message', function(event) {
console.log('Received message from iframe:', event.data);
self.navi(self.groups[0]);//js代码
self.updateView();//js代码
}, false);
这里注意:因为addEventListener后是一个函数说以要加一个 var self = this;才能调用JS中的方法,(前端的基础知识)。
以上我们完成了Unity跨域调用JS的方法。