WebGL & XLua 开发经验总结
前言:因项目需求,需要基于原有的游戏项目,开发出一个web版本,于是有了这份经验总结。旨在整理自己开发时遇到的一些坑的和一些经验。
第0关.WebGL开发中的一些重要的注意事项
1.禁止使用System.Net下的任何.Net网络类
WebGL原生并不支持使用Sokect和服务器进行通信,所以如果项目中使用了Socket和服务器进行通信,请替换成UnityWebRequest或者在PackManager中下载第三方的js插件UnityWebSocket。
2. System.File下的文件读写操作不再生效
WebGL并不支持对设备文件的读写操作,WebGL的资源都存储在远端的服务器上,如果资源不在Resources文件夹下(Resources文件下的资源会随着build被打包到Build/xxx.data中),则需要通过UnityWebRequest下载,比如AB包文件、StreamingAssets下的资源。
3. 拒绝使用多线程
WebGL是单线程执行的,所以请不要使用多线程,否则可能导致代码阻塞,工程直接卡死!如果要实现多线程效果,请使用协程实现。
4. 检查第三方库和插件的兼容性
在打包WebGL项目时,确认好项目使用的第三方库和插件兼容WebGL平台,否则可能打包失败。
第1关.WebGL项目打包后的结构
- Build下的.data中包含项目运行时所需的数据和资源,例如Resources文件夹下的内容将会包含在该文件中。
- Build下的.framework.js文件主要实现webAssembly环境下的unity框架,定义了与unity引擎的交互方式。
- Build下的.loader.js文件用于加载.wasm文件、.data文件以及在web侧加载unity实例,实现生成unity实例的方法,是unity程序运行在web上的核心入口
- Build下的.wasm文件,wasm文件主要包括编译后的项目运行所需的代码,即编译后的字节码,另外还有元数据、函数表、数据表等。
- index.html是web项目运行的html页面,可自定义。详情可参考unity官方文档
- StreamingAssets即项目StreamingAssets中的内容
- TemplateData下为webgl模板所需的资源文件,包括css代码以及一些展示用的图片文件
第2关.WebGL+XLua导出
关于WebGL+XLua导出流程,网上有详细的文档可供参考,这里不过多赘述。详情可参考:webgl-building、https://zhuanlan.zhihu.com/p/475307249、https://www.cnblogs.com/fzuljz/p/18263464
第3关.WebGL中c#与js交互
在WebGL开发中,由于C#并不好直接与浏览器进行交互,想要更好的和浏览器交互以及调用一些浏览器提供的api,还是需要通过js来进行。这里提供一种简单且可行的方法,利用unity提供的.jslib文件实现c#侧调用js代码实现浏览器交互。
- 创建.jslib文件
创建一个扩展名为.jslib的文件,文件名可以自定义。
var JsPlugin = {
//具体的实现函数
//获取时间戳
GetCurTimeStampJs: function(){
return Date.now();
},
};
//并入Unity中,官方写法。
mergeInto(LibraryManager.library, JsPlugin);
- 在c#脚本中声明外部函数
使用[DllImport("__Internal")]
属性来声明外部函数,使得其能在c#中被调用
public static class WebGLHelper
{
[DllImport("__Internal")]
private static extern int GetCurTimeStampJs();
/// <summary>
/// 获取当前时间戳(毫秒级)
/// </summary>
/// <returns></returns>
public static int GetCurTimeStamp()
{
return GetCurTimeStampJs();
}
}
- 在lua或c#中调用
print(WebGLHelper.GetCurTimeStamp())
print(CS.WebGLHelper.GetCurTimeStamep())
一些坑点
jslib拓展的方法并不能直接返回字符串,
这是因为js 和 wasm(C#)使用不同的内存模型。js 的字符串是动态的,而在 wasm 中,内存是通过线性内存块管理的。
直接返回 js 字符串给 C# 是不可行的,因为 C# 需要在 wasm 的内存中访问这个字符串。
为了让 C# 能够读取字符串,需要在 wasm 的内存中分配一块区域来存储这个字符串,并返回一个指向这块内存的指针。
_malloc 用于在 wasm 的内存中分配空间。
另外需要注意的是js中的字符串编码为Utf-16,而C#中为Utf-8,所以在计算长度时需要转换一下。
function ReturnString(returnStr)
{
var bufferSize = lengthBytesUTF8(returnStr) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
return buffer;
}
直接调用浏览器原生接口写入文本信息到黏贴板可能在某些环境下不被支持,比如Safari浏览器中。
一个简单可行的方法是动态创建一个html元素,然后写入文本并执行复制操作。只要元素离的足够远,就看不到。
//复制文本
CopyText: function (text) {
function onExecCommand(val)
{
let input = document.createElement('input');
input.setAttribute('readonly', 'readonly');
input.setAttribute('value', val);
input.style.position = "absolute";
input.style.opacity = 0;
input.style.left = "-999999px";
input.style.top = "-999999px";
document.body.appendChild(input);
input.focus();
input.select();
input.setSelectionRange(0, 9999);
if (document.execCommand('copy')) {
document.execCommand('copy');
Toast.success("复制成功")