UE脚本插件Puerts
好处:
- 有类型检查,解决Lua无类型的痛
- 性能和蓝图差不多
- 可以热更
概述:一套虚拟机运行时,创建并管理JS/TS的运行时环境(通过例如V8引擎),负责脚本加载编译、GC,完成反射绑定和静态模板绑定功能,有调试支持,也支持热重载。
typescript
- string
- number
- boolean
- null(适用于联合类型)
- undefined(适用于联合类型)
- 数组[]或Array
- 元组[]
Puerts架构
- 桥接层(V8的各种API,C++的相关类)
- 类型映射(通过反射系统实现)
- 内存管理(TS对象和引擎对象一对一)
- JS引擎(v8/Node.js/QuickJS)
Puerts核心原理大揭秘:TypeScript如何驱动游戏引擎逻辑-CSDN博客
TS调用C++
1、Puerts可以使用反射生成.d.ts文件,这个文件包含所有可以通过反射机制获取到的C++函数(包括蓝图),这个文件保证了TS的类型安全检查。如果是非反射的函数或者对象,需要在C++端手动进行静态绑定。
2、C++的类以及所有成员都可以在TS算随意获取并创建,如果是蓝图类或者其他相关资源,需要提前通过UE.Class.Load()进行加载(等同于C++的LoadObject< UClass>),然后再通过UE的其他API对这个蓝图进行操作,例如利用world.SpawnActor进行对象生成,或者通过blueprint.tojs直接将其转换成js代码供TS操控此资源。
3、V8的桥接层会处理函数转发,在此之前需要对参数进行转换,例如TS中的对象UE.Vector需要转换成FVector结构体,UObject对象则通过TS的代理对象包装来进行转换,当对象函数被调用时,自动转发到C++层。
4、如果函数有返回值,则需要再次通过桥接层进行参数转换返回给TS。
C++调用TS
思路有很多
主要通过C++委托绑定来进行调用。
1、C++内声明委托,然后TS端通过反射生成.d.ts文件,按照TS调用C++的思路,TS端可以拿到这个委托了。如果不是UClass下的委托,需要在TS端使用toDelegate。纯C++也可以直接使用std::function将函数当初参数传给TS,也可以访问到。
2、TS内部进委托绑定。
3、C++进行委托触发。
内存管理
V8的内存管理:(99+ 封私信 / 62 条消息) 翻译:V8 引擎的内存管理 - 知乎
Puerts中TS代理对象含义:
C++中UObject对象和类似TArray的对象创建后,TS在使用时,会一对一地创建一个TS的对象与之对应,例如上文中的UE.Class.Load(),返回的就是一个TS的代理对象,这种方式就是典型的TS代理对象持有UE对象的引用,这个时候此UE对象的引用计数就会+1,以至于这个对象不会被UEGC掉。当UE的对象被手动摧毁时,会有回调函数通知TS的代理对象也摧毁,这样的方式保证了内存安全,防止崩溃。