经过之前 duktape-unity 的开发, 在自己的小项目中使用, 总结下来主要有几个问题:
- Duktape 对 JS 新标准的支持有限, 不支持 await/async, Promise 也不是 Duktape 直接支持的, 诸如此类特性的缺失写起脚本来始终是有点遗憾的
- 标准 JS 本身不支持运算符重载, 这让 Vector3 + Vector3 等在 C# 中写起来非常自然的运算在 JS 中用起来略显不便
- 运行效率相对略低
后来发现 QuickJS 基本可以弥补上述缺陷, 不但支持到最新ES2020的标准, 还支持运算符重载, 效率更是可以接近 Lua (非JIT), 唯一可惜的是 QuickJS 目前还没有 Debugger API 支持, 但毕竟是暂时还没有, 不能阻止我们先用先爽 😃
于是我就继续在 duktap-unity 的基础上, 将 Duktape 替换成 QuickJS, 做了这里要介绍的 unity-jsb. 还没有全部完成所有预期功能, 仍处于玩具级, 欢迎大家交流指导 (QQ群 859823032).
特性支持
- 支持在JS异步函数中等待 Unity YieldInstruction 对象
- 支持在JS异步函数中等待 System.Threading.Tasks.Task 对象 (limited support)
- 向 JS 导入 C# 运算符重载 +, -, *, /, ==, -(负)
- 支持 Websocket (limited support)
- [初步] 支持 XMLHttpRequest (limited support)
- [初步] 未导出的类型通过反射方式进行 C#/JS 交互
- [初步] 支持 C# 代码热更 (hotfix, limited support)
- [未完成] 支持 JS 字节码 (QuickJS)
- [未完成] Webpack HMR 运行时模块热替换 (可能会放弃, limited support, for development only)
特性示例
推荐使用 typescript 编写脚本, unity-jsb 对导出的 C# 类型自动生成了对应的 d.ts 声明, 以提供强类型辅助. 示例代码均使用 typescript.
也可以根据喜好选择 coffeescript/clojurescript 等任何可以编译成 javascript 的语言. 最终运行的都是 javascript.
MonoBehaviour in Javascript
支持 JS class 直接继承 MonoBehaviour, 所有响应函数支持 JS 异步函数.
不建议大规模使用这种方式, 毕竟交互开销还是不能忽视的, 进入 JS 运行时后尽量减少 JS/C# 交互还是性能优化的重点之一.
class MyClass extends UnityEngine.MonoBehaviour {
protected _tick = 0;
Awake() {
console.log("MyClass.Awake", this._tick++);
}
async OnEnable() {
console.log("MyClass.OnEnable", this._tick++);
await jsb.Yield(new UnityEngine.WaitForSeconds(1));
console.log("MyClass.OnEnable (delayed)", this._tick++);
}
OnDisable() {
console.log("MyClass.OnDisable", this._tick++);
}
OnDestroy() {
console.log("MyClass.OnDestroy", this._tick++);
}
async test() {
console.log("MyClass.test (will be destroied after 5 secs.",