大家好,我是阿赵。
Unity可以发布WebGL,发布后是一个HTML页面。这时候,Unity内部的内容,怎样和外部的HTML页面的内容进行交互呢?
先说一下基础知识,Unity发布的WebGL,不能直接双击打开html文件的,必须通过服务器访问。所以如果没有服务器的话,可以自己在本机搭建一个wamp之类的服务器,就可以方便调试。
一、通过C#调用页面的JavaScript方法
1、基本调用
如果想通过C#在Unity工程内部调用页面的JavaScript方法,比如DOM或者BOM的,需要做以下几个事情。
1. 建立jslib文件
在Unity官方文档里面可以看到,官方支持在插件文件夹里面放置jslib文件来编写JavaScript:

所以我们先在Unity工程的Assets文件夹里面建一个Plugins文件,然后在里面建一个后缀名为jslib的文件,文件名都可以,主要是后缀名一定要是jslib:

然后在里面编写内容:
mergeInto(LibraryManager.library, {
Hello: function () {
window.alert("Hello, world!");
},
HelloString: function (str) {
window.alert(UTF8ToString(str));
},
});
这里主要是写了2个方法,第一个Hello方法,是不带参数的,直接调用的是JavaScript的alert弹窗。第二个叫做HelloString的方法,需要传入一个字符串参数,然后调用alert弹窗时把字符串传进去。
这里可以看到了第一个需要注意的地方,在把字符串传到JavaScript的时候,需要使用UTF8ToString方法进行转换,不然JavaScript那边会收到一串数字。
2. 在C#注册方法并且调用。
在写好了JavaScript方法之后,就需要调用这些方法。写一个继承了MonoBehaviour的脚本挂到一个物体上,比如:

如果只是发送消息,其实并不是必须这样做,但为了之后能接收到从页面发送的消息,是需要使用SendMessage的,所以需要一个GameObject作为一个接收的对象。
在这个c#脚本里面,需要先把刚才写的2个JavaScript方法给注册声明一下:
[DllImport("__Internal")]
private static extern void Hello();
[DllImport("__Internal")]
private static extern void HelloString(string str);
这样,在调用Hello方法和HelloString方法时,就会去查找jslib里面的方法并执行。
接下来简单写个测试:
private void OnGUI()
{
if(GUILayout.Button("test1",GUILayout.Width(200),GUILayout.Height(100)))
{
Hello();
}
if (GUILayout.Button("test2", GUILayout.Width(200), GUILayout.Height(100)))
{
HelloString("Hello azhao");
}
}
发布WebGL,拷贝到服务器,然后运行,会看到:

点击test1按钮,会看到:

点击test2按钮,会看到:

到这里,从C#调用JavaScript方法的基础操作就完成了。
2、 调用页面本身的JavaScript方法
刚才的例子调用的是页面JavaScript的alert弹窗方法,如果是想在页面里面写JavaScript,然后从Unity里面调用,又需要怎样操作呢?
打开Unity发布WebGL时自动生成的index.html文件,可以看到里面有这么一个可以调用的函数:

这个函数的作用是显示一个提示信息框。我们就拿这个作为例子,看看是否能从Unity里面调用到页面的JavaScript函数。
1. 在jslib文件写方法
mergeInto(LibraryManager.library, {
Hello: function () {
window.alert("Hello, world!");
},
HelloString: function (str) {
window.alert(UTF8ToString(str));
},
ShowBanner:function(str,t){
unityShowBanner(UTF8ToString(str),UTF8ToString(t));
}
});
新增的是ShowBanner方法,里面的内容是直接调用了页面上的JavaScript的函数unityShowBanner。注意方法之间需要用逗号分隔。这个函数需要2个参数,第一个是显示内容,第二个是显示的类型。这两个参数就在后面C#传入了,记得注意要用UTF8ToString来转换一下字符串。
2. 在C#注册方法并调用
在刚才的C#文件里面,增加一个方法的声明:
[DllImport("__Internal")]
private static extern void ShowBanner(string str,string t);
然后增加一个测试调用:
private void OnGUI()
{
if(GUILayout.Button("test1",GUILayout.Width(200),GUILayout.Height(100)))
{
Hello();
}
if (GUILayout.Button("test2", GUILayout.Width(200), GUILayout.Height(100)))
{
HelloString("Hello azhao");
}
if (GUILayout.Button("test3", GUILayout.Width(200), GUILayout.Height(100)))
{
ShowBanner("这是一个来自Unity的提示信息", "warning");
}
}
主要是test3的按钮,会调用ShowBanner函数,并传入值。
发布WebGL,拷贝文件到服务器,然后运行,会看到:

然后点击test3按钮,会看到:

这里调用页面JavaScript里面的函数已经成功了。
3、 修改页面元素的内容和样式。
通过Unity内部的C#控制页面的HTML元素内容和样式,可以在jslib里面写选择器来获取元素,然后赋值。
1. 修改jslib
mergeInto(LibraryManager.library, {
Hello: function () {
window.alert("Hello, world!");
},
HelloString: function (str) {
window.alert(UTF8ToString(str));
},
ShowBanner:function(str,t){
unityShowBanner(UTF8ToString(str),UTF8ToString(t));
},
ChangeBtn:function(str){
let btn = document.getElementById("sendUnityBtn");
btn.innerHTML = UTF8ToString(str);
}
});
主要是增加了最后的ChangeBtn方法。
2. 修改C#
同样的先声明方法:
[DllImport("__Internal")]
private static extern void ChangeBtn(string str);
然后增加调用
if (GUILayout.Button("test4", GUILayout.Width(200), GUILayout.Height(100)))
{
ChangeBtn("发送信息给Unity");
}
发布WebGL,拷贝文件到服务器,由于增加了一个HTML上面的按钮标签,所以需要修改一下index.html文件:
在body里面加多一个按钮:
<button id="sendUnityBtn">传值给Unity</button>


这样就可以通过id选择器来选中这个按钮了。
拷贝到服务器,运行:

会看到多了一个按钮,点击上面的test4按钮,会看到

这个按钮上的字发生了变化了,所以我们从c#控制HTML标签内容已经成功了。
二、 通过JavaScript调用C#方法
接下来要反过来,从JavaScript发送消息给Unity。和其他各种平台的原生交互一样,是通过SendMessage来实现这个功能的,SendMessage有3个参数,第一个是接收信息的GameObject对象的名字,第二个是方法名,第三个是需要传递的参数。
一般来说需要调用SendMessage之前需要先获得Unity的单例,比如在WebGL的index.html里面就有:

它这里是创建了一个Unity的单例。其实我们可以把它存起来备用。
在上面的例子里面我们已经在HTML页面上面加了个按钮了,所以可以通过这个按钮来测试一下。

这里传入的参数,第一个是JSCtrl,就之前挂c#脚本的GameObject名字了,然后第二个参数是方法名ChangeContent,所以我们需要在c#脚本里面加这个方法来让JavaScript调用:
private string content = "Hello world!";
private void OnGUI()
{
if(GUILayout.Button("test1",GUILayout.Width(200),GUILayout.Height(100)))
{
Hello();
}
if (GUILayout.Button("test2", GUILayout.Width(200), GUILayout.Height(100)))
{
HelloString("Hello azhao");
}
if (GUILayout.Button("test3", GUILayout.Width(200), GUILayout.Height(100)))
{
ShowBanner("这是一个来自Unity的提示信息", "warning");
}
if (GUILayout.Button("test4", GUILayout.Width(200), GUILayout.Height(100)))
{
ChangeBtn("发送信息给Unity");
}
GUILayout.Label(content);
}
public void ChangeContent(string str)
{
content = str;
}
为了能让传入的值显示,所以用一个content变量来存储一个字符串,通过ChangeContent来改变这个content,然后用GUILayout.Label来显示这个字符串:

可以看到,一开始这个字符串显示的是Hello world!,然后按“传值给Unity”的按钮,会看到:

显示的字符已经变成了从HTML传进去的“Hello azhao”字符串了。
三、WebGL模板
刚才在制作这些例子的过程中,发现一个问题,就是每次重新编译之后,生成的index.html文件都会变回默认的,而我们在index.html里面做了的修改就会丢失了,又要一次次的重新修改。
其实Unity是可以修改发布WebGL的模版的。

在设置——Player——WebGL页签里面,会找到WebGL Template选项,这里就是选择发布WebGL的模版的地方。默认有3个模板可以选择。
这个模板也是可以自定义的,在Assets文件夹下新建一个WebGLTemplates文件夹,然后在里面建立你需要的模板的文件,比如我建立了一个叫做azhao的模板。里面再放2个文件,第一个文件是thumbnail.png图片,是用于显示在WebGL Template里面可选项的图标。第二个文件就是你需要的模版index.html文件了。

把文件放好后,可以再次回到设置里面:

会发现多了一个模板的选项。选中它,这样这个工程再发布WebGL的时候,就会使用刚才我们放进去的index.html文件了,我们可以修改这个文件,把自己需要的功能放进去。

1203

被折叠的 条评论
为什么被折叠?



