256 lines
9.1 KiB
Markdown
256 lines
9.1 KiB
Markdown
---
|
||
title: Puerts(一)——学习资料归纳
|
||
date: 2023-07-24 15:12:29
|
||
excerpt:
|
||
tags: Puerts TypeScript
|
||
rating: ⭐
|
||
---
|
||
|
||
# 前言
|
||
https://github.com/Tencent/puerts
|
||
- [安装方法](https://github.com/Tencent/puerts/blob/master/doc/unreal/zhcn/install.md)
|
||
- [FAQ](https://github.com/Tencent/puerts/blob/master/doc/unreal/zhcn/faq.md)
|
||
- [更新日志](https://github.com/Tencent/puerts/blob/master/doc/unreal/zhcn/changelog.md)
|
||
|
||
## Puerts
|
||
- 相关文章&视频:
|
||
- [UE引擎里头跑个nodejs服务器是怎样一种体验?](https://zhuanlan.zhihu.com/p/428250631)
|
||
- [在你的ios、android应用中嵌入官方版nodejs是什么感觉?](https://zhuanlan.zhihu.com/p/568969543)
|
||
- [[UnrealCircle深圳] puerts-UE下TypeScript编程插件 | 腾讯 车雄生](https://www.bilibili.com/video/BV1oB4y1A7dY/?spm_id_from=333.337.search-card.all.click&vd_source=d47c0bb42f9c72fd7d74562185cee290)
|
||
- 案例工程:
|
||
- https://github.com/chexiongsheng/puerts_unreal_demo
|
||
- 知乎文章:
|
||
- UE5 PuerTS学习与实践:https://zhuanlan.zhihu.com/p/632862773
|
||
- UE4下基于V8实现的代码热刷新:https://zhuanlan.zhihu.com/p/364505146
|
||
- PuerTS:js调用ue的过程:https://zhuanlan.zhihu.com/p/396751427
|
||
- UE4:PuerTS的js调试相关:https://zhuanlan.zhihu.com/p/406387721
|
||
- 基于Puerts的编辑器UI开发-Mixin的非最佳实践:https://zhuanlan.zhihu.com/p/551338775
|
||
## TypeScript
|
||
- http://www.patrickzhong.com/TypeScript/zh/tutorials/typescript-in-5-minutes.html
|
||
- https://ts.xcatliu.com/
|
||
- https://jkchao.github.io/typescript-book-chinese/#why
|
||
|
||
# TypeScript Setup
|
||
安装:
|
||
```bash
|
||
npm install -g typescript
|
||
```
|
||
|
||
编译:
|
||
```bash
|
||
tsc xxx.ts
|
||
```
|
||
|
||
# Puerts
|
||
## Setup
|
||
1. 编译插件。
|
||
2. 进入插件目录`Plugins\Puerts`执行`node enable_puerts_module.js`。
|
||
3. 在项目根目录下执行`npm init`,并且添加。之后重新生成一次VS解决方案并且执行`npm install`。
|
||
```json
|
||
"dependencies": {
|
||
"@types/react": "^15.6.6",
|
||
"@types/react-reconciler": "^0.18.0",
|
||
"@types/mocha": "^7.0.1"
|
||
}
|
||
```
|
||
5. 代码写在项目目录下的`Content/TypeScript`中。
|
||
6. 之后就会在编辑器`Blueprints/TypeScript`目录下出现资产图标。
|
||
7. 加入ReactUMG。
|
||
1. 进入 Content/javascript 目录 npm init 创建 package.json。
|
||
2. 创建成功后,向文件中粘贴如下内容
|
||
```json
|
||
"dependencies": {
|
||
"react": "^16.11.0",
|
||
"react-reconciler": "^0.23.0"
|
||
}
|
||
```
|
||
3. 然后 npm install 一次。
|
||
4. 打开工程根目录的 tsconfig.json, 在 typeRoots 中 加入 "Plugins/ReactUMG/Typing"。
|
||
8. 打开 工程,在引擎中点击 ue.d.ts 。
|
||
### Node环境设置
|
||
|
||
### 调试方法
|
||
具体可以参考:
|
||
- Puerts Inspector指南(一)在UE4和Unity里调试Javascript:https://zhuanlan.zhihu.com/p/359598262
|
||
|
||
调试器的选择有:
|
||
1. 在Chrome输入`devtools://devtools/bundled/inspector.html?v8only=true&ws=127.0.0.1:8080`。
|
||
2. 在Chrome输入`chrome://inspect`,点击Configure...,输入IP&Port后,点击Inspect。
|
||
3. 使用VSCode进行调试。
|
||
1. 在`Launch Program`处点击`add Configuration`。
|
||
2. 选择`Node.js: Attach`。
|
||
3. 设置端口。
|
||
4. 点击绿色箭头即可调试。
|
||
|
||
#### 方式1:自创建虚拟机模式下调试配置
|
||
创建FJsEnv传入调试端口
|
||
```c++
|
||
//8080是调试端口 GameScript = MakeShared<puerts::FJsEnv>(std::make_unique<puerts::DefaultJSModuleLoader>(TEXT("JavaScript")), std::make_shared<puerts::FDefaultLogger>(), 8080);
|
||
```
|
||
|
||
阻塞等待调试器链接
|
||
```c++
|
||
GameScript = MakeShared<puerts::FJsEnv>(std::make_unique<puerts::DefaultJSModuleLoader>(TEXT("JavaScript")), std::make_shared<puerts::FDefaultLogger>(), 8080);
|
||
GameScript->WaitDebugger();
|
||
GameScript->Start("QuickStart", Arguments);
|
||
```
|
||
|
||
#### 方式2:自动绑定模式下调试配置
|
||
1. 菜单上选择`Edit->ProjectSettings`,打开设置页面后在`Plugins -> Puerts Setting`页面中开启调试以及设置端口。
|
||
|
||
# TypeScript
|
||
- Express TypeScript化改造:https://www.jianshu.com/p/978628a15027
|
||
|
||
## Express
|
||
#### 使用ts-node将ts文件编译在内存中
|
||
在使用`ts-node`之前需要进行全局安装
|
||
```shell
|
||
$ npm install ts-node -g
|
||
|
||
# 用ts-node直接运行项目,这个库会将我们的ts文件编译成js文件保存在内存中进行引用
|
||
$ ts-node ./bin/www
|
||
# 热更新模式
|
||
$ ts-node-dev ./bin/www
|
||
```
|
||
虽然`ts-node`可以帮我们直接运行ts文件,但在开发完成后部署在生产环境时,还是推荐使用`tsc`打包出来的`js`文件会更加稳定。
|
||
|
||
#### 配置npm脚本
|
||
```json
|
||
"scripts": {
|
||
"start": "ts-node app.ts",
|
||
"dev": "ts-node-dev app.ts",
|
||
"build": "tsc",
|
||
"server": "node ./dist/app.js"
|
||
},
|
||
```
|
||
|
||
# Puerts
|
||
Puerts的使用方法主要为
|
||
- 继承
|
||
- 继承原生UE C++类:继承并且实现之后就会在
|
||
- Mixin:
|
||
- 在C++类中调用TypeScript文件
|
||
## puerts_unreal_demo 食用方法
|
||
项目默认使用UTsGameInstance,可以在cpp中修改OnStart()中调用的TS脚本文件名,来查看结果。优先查看TS文件:
|
||
- QuickStart
|
||
- UsingMixin
|
||
- UsingMakeUClass
|
||
- UI
|
||
- UsingWidget
|
||
- UsingReactUMG
|
||
|
||
### 蓝图相关
|
||
```javascript
|
||
//蓝图加载
|
||
//UE.Class.Load方式
|
||
//let bpClass = UE.Class.Load('/Game/StarterContent/TestBlueprint.TestBlueprint_C')
|
||
//let bpActor = UE.GameplayStatics.BeginDeferredActorSpawnFromClass(gameInstance, bpClass, undefined) as UE.Game.StarterContent.TestBlueprint.TestBlueprint_C;
|
||
blueprint.load(UE.Game.StarterContent.TestBlueprint.TestBlueprint_C);
|
||
const TestBlueprint_C = UE.Game.StarterContent.TestBlueprint.TestBlueprint_C; //别名
|
||
let bpActor = UE.GameplayStatics.BeginDeferredActorSpawnFromClass(gameInstance, TestBlueprint_C.StaticClass(), undefined) as UE.Game.StarterContent.TestBlueprint.TestBlueprint_C;
|
||
UE.GameplayStatics.FinishSpawningActor(bpActor, undefined);
|
||
bpActor.Foo(false, 8000, 9000);
|
||
//如果确定后续不需要使用TestBlueprint_C了,应该unload节省内存
|
||
blueprint.unload(TestBlueprint_C);
|
||
|
||
//蓝图结构体加载
|
||
//UE.UserDefinedStruct.Load方式
|
||
//let TestStruct = UE.UserDefinedStruct.Load("UserDefinedStruct'/Game/StarterContent/TestStruct.TestStruct'");
|
||
//let testStruct = UE.NewStruct(TestStruct) as UE.Game.StarterContent.TestStruct.TestStruct;
|
||
blueprint.load(UE.Game.StarterContent.TestStruct.TestStruct);
|
||
const TestStruct = UE.Game.StarterContent.TestStruct.TestStruct;
|
||
let testStruct = new TestStruct();
|
||
testStruct.age = 10;
|
||
testStruct.speed = 5;
|
||
bpActor.Bar(testStruct);
|
||
blueprint.unload(TestStruct);
|
||
|
||
//蓝图枚举
|
||
console.log("-------------------------15---------------------------");
|
||
console.log(UE.Game.StarterContent.TestEnum.TestEnum.Blue);
|
||
console.log(UE.Game.StarterContent.TestEnum.TestEnum.Red);
|
||
console.log(UE.Game.StarterContent.TestEnum.TestEnum.Green);
|
||
```
|
||
|
||
### Delegate
|
||
```javascript
|
||
//Delegate
|
||
function MutiCast1(i) {
|
||
console.warn("MutiCast1<<<", i);
|
||
}
|
||
|
||
function MutiCast2(i) {
|
||
console.warn("MutiCast2>>>", i);
|
||
actor.NotifyWithInt.Remove(MutiCast2);//调用一次后就停掉
|
||
}
|
||
|
||
actor.NotifyWithInt.Add(MutiCast1)
|
||
actor.NotifyWithInt.Add(MutiCast2)
|
||
|
||
console.log("NotifyWithString.IsBound", actor.NotifyWithString.IsBound());
|
||
console.log("NotifyWithRefString.IsBound", actor.NotifyWithRefString.IsBound());
|
||
actor.NotifyWithRefString.Bind((strRef) => {
|
||
//console.error("NotifyWithRefString");
|
||
console.log("NotifyWithRefString", $unref(strRef));
|
||
$set(strRef, "out to NotifyWithRefString");//引用参数输出
|
||
});
|
||
console.log("NotifyWithString.IsBound", actor.NotifyWithString.IsBound());
|
||
console.log("NotifyWithRefString.IsBound", actor.NotifyWithRefString.IsBound());
|
||
|
||
actor.NotifyWithStringRet.Bind((inStr) => {
|
||
return "////" + inStr;
|
||
});
|
||
|
||
actor.NotifyWithInt.Broadcast(888999);
|
||
let strRef = $ref("666");
|
||
actor.NotifyWithRefString.Execute(strRef);
|
||
console.log("out str:" + $unref(strRef));
|
||
let retStr = actor.NotifyWithStringRet.Execute("console.log('hello world')");
|
||
console.log("ret str:" + retStr);
|
||
console.log("waiting native call script...........");
|
||
|
||
//Pass JsFunction as Delegate
|
||
function IsJohn(str:string) : boolean {
|
||
return str == "John";
|
||
}
|
||
obj.PassJsFunctionAsDelegate(toManualReleaseDelegate(IsJohn));
|
||
//release after using
|
||
releaseManualReleaseDelegate(IsJohn);
|
||
|
||
//unhandledRejection
|
||
on('unhandledRejection', function(reason: any) {
|
||
console.log('unhandledRejection~~~');
|
||
});
|
||
|
||
new Promise(()=>{
|
||
throw new Error('unhandled rejection');
|
||
});
|
||
```
|
||
## 热更新方法
|
||
https://zhuanlan.zhihu.com/p/364505146
|
||
|
||
|
||
## UE C++调用Puerts脚本方法
|
||
```c++
|
||
//h
|
||
TSharedPtr<puerts::FJsEnv> GameScript;
|
||
|
||
//cpp
|
||
GameScript = MakeShared<puerts::FJsEnv>();
|
||
TArray<TPair<FString, UObject*>> Arguments;
|
||
Arguments.Add(TPair<FString, UObject*>(TEXT("GameInstance"), this));
|
||
GameScript->Start("QuickStart", Arguments);
|
||
```
|
||
|
||
```javascript
|
||
//在FJsEnv启动,调用Start时传入的参数可以通过argv获取。如果是继承ue类方式,这里的argv是空的
|
||
let gameInstance = (argv.getByName("GameInstance") as UE.GameInstance);
|
||
let actor = UE.GameplayStatics.BeginDeferredActorSpawnFromClass(gameInstance, UE.MainActor.StaticClass(), undefined) as UE.MainActor;
|
||
UE.GameplayStatics.FinishSpawningActor(actor, undefined);
|
||
|
||
console.log(actor.GetName());
|
||
console.log(actor.K2_GetActorLocation().ToString());
|
||
```
|
||
|
||
## UE C++访问Puerts
|
||
通过UDynamicDelegateProxy,其成员记录了绑定的虚拟机与JS函数。 |