美文网首页unity3D技术分享
在 Unity 中使用 Typescript 脚本

在 Unity 中使用 Typescript 脚本

作者: b8ab | 来源:发表于2019-12-10 21:04 被阅读0次

本文介绍的插件 duktape-unity 可以使你在 Unity3D 中使用 javascript/typescript 来写脚本. 这里说的脚本是指可以在包括iOS上动态执行的脚本. 目前主流的选择是 lua 和 ILRuntime(C#), 都是很成熟的方案. typescript 或许可以是介于两者之间的一种选择, 即有动态脚本语言的特性, 又有强类型的辅助.

概况

duktape-unity 的使用方法与 slua/ulua 等是类似的, 通过生成绑定代码并对部分值类型进行特定优化来提高交互效率. 并针对 js 的使用习惯, 做了一些 js 风格的封装, 例如事件/委托的封装, 有两种方式在 js 中将 js 函数注册到 C# 事件/委托上 (这里均以 ts 为例):

// 方法一, 直接注册 js 函数
UnityEngine.Application.lowMemory.on(() => {
    console.log("low memory");
});
// 方法二, 构造一个 Delegate 对象进行注册, 这种方式 Delegate 对象本身就是一个 Dispatcher, 可以自己再 on/off 多个响应者
let delegate = new DuktapeJS.Delegate0();
delegate.on(this, () => {
    console.log("low memory")
});
delegate.on(this, () => {
    // ...
});
UnityEngine.Application.lowMemory.on(delegate);

而且, 得益于自动生成的 d.ts 声明的帮助, 写脚本时是有类型验证的.

集成

Assets/Duktape 是插件主要代码, 直接放到工程目录(可以是子目录)中即可. Assets/DuktapeExtra 是插件辅助代码, 可选, 目前主要作用是将 js stacktrack 转换到 typescript stacktrack, 在调试过程中有较大帮助.

接着, 在项目根目录编辑生成绑定代码的配置文件 ./duktape.json:

{
    "outDir": "Assets/Generated",  // 生成csharp绑定代码的目录
    "typescriptDir": "Assets/Generated",  // 生成 d.ts 声明的目录
    // rootpath of ts/js project
    "workspace": "",
    "logPath": "Temp/duktape.log", // 生成csharp绑定代码过程中产生的日志文件
    // auto, cr, lf, crlf
    "newLineStyle": "auto", // 生成代码的换行符
    // 隐式生成 (在下列模块中定义的类型中未明确禁止生成的类都将生成绑定)
    "implicitAssemblies": [
        "UnityEngine",
        "UnityEngine.CoreModule", 
        "UnityEngine.UI", 
        "UnityEngine.UIModule", 
        "UnityEngine.TextRenderingModule",
        "UnityEngine.AnimationModule"
    ], 
    // 显式生成 (在下列模块中定义的类型必须明确指定需要生成绑定的类型)
    "explicitAssemblies": [
        "Assembly-CSharp"
    ],
    // 禁止生成绑定的类型全名前缀
    "typePrefixBlacklist": [
        "JetBrains.",
        "Unity.Collections.",
        "Unity.Jobs.",
        "Unity.Profiling.",
        "UnityEditor.",
        "UnityEditorInternal.",
        "UnityEngineInternal.",
        "UnityEditor.Experimental.",
        "UnityEngine.Experimental.",
        "Unity.IO.LowLevel.",
        "Unity.Burst.",
        // more types ...
        "UnityEngine.Assertions."
    ], 
    // 生成绑定代码所在的命名空间
    "ns": "DuktapeJS",
    // 生成的绑定代码中使用的缩进符
    "tab": "    "
}

然后执行菜单 Duktape/Generate Bindings 生成绑定代码.


generate_bindings.png

编写 C# 调用 js 的启动代码:

// Launcher.cs
public class Launcher : MonoBehaviour, IDuktapeListener
{
    public bool debuggerSupport;
    public string entryScript = "main";

    private DuktapeVM _vm;

    public void OnBinded(DuktapeVM vm, int numRegs) { }
    public void OnBindingError(DuktapeVM vm, Type type) { }
    public void OnProgress(DuktapeVM vm, int step, int total) { }
    public void OnTypesBinding(DuktapeVM vm) { }

    public void OnLoaded(DuktapeVM vm)
    {
        _vm.AddSearchPath("Assets/Scripts/out");
        if (debuggerSupport)
        {
            DuktapeDebugger.CreateDebugger(_vm);
        }
        _vm.EvalMain(entryScript);
    }

    void Awake()
    {
        _vm = new DuktapeVM();
        _vm.Initialize(this);
    }
}

接着, 就可以开始愉快的用 typescript 写脚本了. 上一步生成绑定代码时, 会自动生成 C# 类对应的 d.ts 申明文件, 因此写脚本的体验接近 C#, 定义跳转/引用查询/重命名等功能一应俱全.

// main.ts
import { MyBridge } from "./app";

console.log("hello, world!");

(function () {
    let go = new UnityEngine.GameObject("_jsgo");
    let bridge = go.AddComponent(DuktapeJS.Bridge);
    bridge.SetBridge(new MyBridge());
})();

完成 ts 脚本的编写, 用 tsc 编译出 js 结果就可以运行了. 这步可以利用 tsc watch 实时监听脚本的修改并自动完成编译, 增量编译的速度极快, 几乎无感.


tsc_watch.png

运行项目, 就可以看到脚本中调用 console.log 产生的日志输出:


console_log.png

调试

到这, 经常用日志调试法调试的伙伴们要崩溃了, 这日志根本看不出来是从哪一行代码产生的啊, 这可怎么调试. 有办法, 只需要在脚本中调用

enableStacktrace(true); 

那么所有脚本产生的日志输出就会自动带上脚本调用栈. 如图所示:


console_log_with_stacktrace.png

当然日志调试法不是万能的, 更多时候还是需要进行断点调试. 首先在代码中调用
DuktapeDebugger.CreateDebugger(vm) 即可启动调试服务.

在 vscode 端需要安装插件 Duktape Debugger (HaroldBrenes), vscode 插件管理器中目前版本为 0.5.6, 可以用于 js 脚本的调试, 对 ts 存在一些bug, 可以使用笔者修改过的版本 duk-debug-0.5.6.vsix 在插件管理器中手工安装即可.
在 vscode 中正确配置 launch.json 后, 即可进行远程调试. 首先要启动游戏, 然后启动 Attach 调试, 调试是可以反复多次的, 游戏运行过程中仍然可以再次 Attach.

addbreakpoint_and_launch.png

命中断点后, 就可以安逸查看各个变量值的情况了.

breakpoint.png

有一点需要注意的, 因为脚本是在主线程执行的, 所以调试过程在没有打开 Run in background 选项的情况下可能无法流畅进行, 建议开启该选项再进行断点调试.


run_in_background.png

基于 duktape-unity 在 Unity 项目中使用 typescript 作为脚本的基本流程就是这样. 代码在这里:
https://github.com/ialex32x/duktape-framework

上述代码 Unity 2018.3.5+可以运行, 更低版本没有测试过.

后续有时间会继续更新代码, 演示 websocket, protobuf, 热更新, 界面框架等的使用方法.

目前项目还不成熟, 如果您对使用 typescript/javascript 写脚本感兴趣, 不妨尝试一下, 给个星星. 有问题建议, 欢迎拍砖, issue. 期待您的关注 :)

相关文章

网友评论

    本文标题:在 Unity 中使用 Typescript 脚本

    本文链接:https://www.haomeiwen.com/subject/chtwgctx.html