姓本无名 发表于 2023-8-15 15:45

UE4学习之路3:Puerts用ts调用C++

简介:

       ts怎么调用ue4中的类呢?
       首先,puerts已经辅佐我们生成了大部门的类:是指UCLASS,USTRUCT标识表记标帜UPPROPERTY,UFUNCTION的属性、方式,可以直接在ts中包含库ue,就能使用对应类提供的方式。其他类想使用怎么去措置呢。
       比如我们可能使用某些第三方库只有C++版本,那么关于第三方库怎么在ts脚本中调用呢?比如网络库,我们在ts脚本经常会调用发送网络动静函数,必需颠末c++调用第三方库来发出去。
       或者我们本身写了一个担任ue4的某个子类,但愿可以被ts访谒到。
1. 普通C++类:

       首先感激大佬的无私付出,才能使用Puerts,贴出大佬的文章:
https://github.com/Tencent/puerts/blob/master/doc/unreal/template_binding.md
       说下工程的具体法式:
       首先还是之前的项目,我们在Source/InstallPuerts的目录下,创建两个文件:Calc.h 和Calc.cpp文件。创建成功后,添加如下代码:

// .h 文件
#pragma once

class CalA
{
public:

        static int32_t Add(int32_t a, int32_t b)
        {
                return a + b;
        }

        int32_t Get()
        {
                return m_c;
        }
        int m_c;

private:
        int m_d;
};


class CalB
{
public:
        static int32_t Add(int32_t a, int32_t b)
        {
                return a + b;
        }
private:
};
      
// .cpp文件
#include ”Calc.h”
#include ”Binding.hpp”

UsingCppType(CalA);
UsingCppType(CalB);

struct AutoRegisterForCalAB
{
    AutoRegisterForCalAB()
    {
      puerts::DefineClass<CalA>().Function(”AddA”, MakeFunction(&CalA::Add)).Register();
      puerts::DefineClass<CalB>().Function(”AddF”, MakeFunction(&CalB::Add)).Register();
    }
};

AutoRegisterForCalAB _AutoRegisterForCalAB__;
          这两个类的声明相信大师都看得懂,主要在cpp文件,首先要包含生成ts的代码的头文件,然后固定格式,使用UsingCppType是在声明要生成ts。然后主要代码是
      puerts::DefineClass<类名>().Functiong(”生成的ts的函数名”,使用的函数).Register();
      AutoRegisterForCalAB这个布局体可有可无,其实就是通过布局体的自动创建过程来达到调用函数的目的。这两个函数也可以放到其他启动的函数处所。
      加完之后,打开UE4项目工程,还是之前我们创建的工程。点击编译,完成后再点击ue.d.ts按钮,在目录Plugins/Puerts/Typing/cpp中,就生成了文件index.d.ts:
declare module ”cpp” {
    import * as UE from ”ue”
    import {$Ref, $Nullable} from ”puerts”

    class CalA {
      static AddA(p0: number, p1: number) :number;
    }

    class CalB {
      static AddF(p0: number, p1: number) :number;
    }

}                 但愿大师都按照流程生成了这个文件。
          如何使用呢,就正常引用cpp文件,调用就好了。
import * as UE from &#39;ue&#39;

import {$ref, $unref, $set, argv, on, toManualReleaseDelegate, releaseManualReleaseDelegate} from &#39;puerts&#39;;
import * as cpp from &#39;cpp&#39;

console.log(”Quick start ---------------aaaaaaaaaaaaa----------------”);

let Cala = cpp.CalA;
console.log(Cala.AddA(12, 34));       UE4中运行:查看控制台:


       成功输出成果46。
       有个处所需要注意:就是在执行ue.d.ts生成ts代码的时候,如果是新增类,或者改削类的名字等,可以生成正确的ts文件,如果是删掉某个方式,则会漏掉删除操作,且封锁ue4的时候会报出ue4崩溃的问题,解决方式是封锁ue4改削可以达到效果。这个我咨询了puerts的创建者车大佬,感激大佬的回答,应该是ue4的live reload的功能不完善,不是puerts的问题
重头戏:说下方式或者属性如何转化:以后使用法式员基础技能:复制粘贴模板。
// Binging.hpp 文件内定义
//
// 撑持注册的方式
ClassDefineBuilder<T>& Constructor(InitializeFuncType constructor, int length, const CFunctionInfo** infos);
ClassDefineBuilder<T>& Function(const char* name, FunctionCallbackType func, const CFunctionInfo* info);
ClassDefineBuilder<T>& Function(const char* name, FunctionCallbackType func, int length, const CFunctionInfo** infos)
ClassDefineBuilder<T>& Method(const char* name, FunctionCallbackType func, const CFunctionInfo* info);
ClassDefineBuilder<T>& Method(const char* name, FunctionCallbackType func, int length, const CFunctionInfo** infos)
ClassDefineBuilder<T>& Property(const char* name, FunctionCallbackType getter, FunctionCallbackType setter = nullptr, const char* type = nullptr)

// 生成特定参数的方式
#define MakeConstructor(T, ...) ::puerts::template ConstructorWrapper<T, ##__VA_ARGS__>
#define MakeGetter(M) &(::puerts::PropertyWrapper<decltype(M), M>::getter)
#define MakeSetter(M) &(::puerts::PropertyWrapper<decltype(M), M>::setter)
#define MakeProperty(M) &(::puerts::PropertyWrapper<decltype(M), M>::getter), &(::puerts::PropertyWrapper<decltype(M), M>::setter), ::puerts::PropertyWrapper<decltype(M), M>::info()
#define MakeFunction(M) &(::puerts::FuncCallWrapper<decltype(M), M>::call), ::puerts::FuncCallWrapper<decltype(M), M>::info()
#define SelectFunction(SIGNATURE, M) &(::puerts::FuncCallWrapper<SIGNATURE, M>::call), ::puerts::FuncCallWrapper<SIGNATURE, M>::info()
#define MakeCheckFunction(M) &(::puerts::FuncCallWrapper<decltype(M), M>::checkedCall), ::puerts::FuncCallWrapper<decltype(M), M>::info()
#define MakeOverload(SIGNATURE, M) puerts::FuncCallWrapper<SIGNATURE, M>
#define CombineOverloads(...) &::puerts::OverloadsCombiner<__VA_ARGS__>::call, ::puerts::OverloadsCombiner<__VA_ARGS__>::length, ::puerts::OverloadsCombiner<__VA_ARGS__>::infos()
#define CombineConstructors(...) &::puerts::ConstructorsCombiner<__VA_ARGS__>::call, ::puerts::ConstructorsCombiner<__VA_ARGS__>::length, ::puerts::ConstructorsCombiner<__VA_ARGS__>::infos()

// 怎么使用:
// 构造函数:仅有一个int参数的构造函数
puerts::DefineClass<CalA>()
    .Constructor<int>()
    .Register();
// 构造函数:多个构造函数
puerts::DefineClass<CalA>()
    .Constructor(CombineConstructors(
      MakeConstructor(CalA, int32_t, int32_t),
      MakeConstructor(CalA)
      ))
    .Register();

// 静态函数:单一函数
puerts::DefineClass<CalA>()
    .Function(”Add”, MakeFunction(&CalA::Add))
    .Register();

// 静态函数:多个重载函数,假设CalA有4个构造函数,参数分袂是下面4种
puerts::DefineClass<CalA>()
    .Function(”Overload”, CombineOverloads(
      MakeOverload(void(*)(), &CalA::Overload),
      MakeOverload(void(*)(int32_t), &CalA::Overload),
      MakeOverload(void(*)(int32_t, int32_t), &CalA::Overload),
      MakeOverload(void(*)(std::string, int32_t), &CalA::Overload)
    ))
    .Register();

// 成员函数:   无重载
puerts::DefineClass<CalA>()
    .Method(”Add”, MakeFunction(&CalA::Add))
    .Register();

// 成员函数:   多个重载,以及连着写法
puerts::DefineClass<CalA>()
    .Method(”OverloadMethod”, CombineOverloads(
      MakeOverload(int32_t(CalA::*)(), &CalA::OverloadMethod),
      MakeOverload(int32_t(CalA::*)(int32_t), &CalA::OverloadMethod),
      MakeOverload(uint32_t(CalA::*)(uint32_t), &CalA::OverloadMethod),
      MakeOverload(int64_t(CalA::*)(int64_t), &CalA::OverloadMethod)
      ))
    .Method(”GetSelf”, MakeFunction(&CalA::GetSelf))
    .Register();

// 成员变量:
puerts::DefineClass<TestClass>()
    .Property(”X”, MakeProperty(&TestClass::X))
    .Property(”Y”, MakeProperty(&TestClass::Y))
    .Register();

2. UE4的类:


         本身编写的担任UE4的类,也必需在文件Source/XXX项目路径下,否则是没法子生成ts的,不外有些东西没必要生成ts的类,也别放在这个目录下,否则会生成ts代码。
       担任的UE的类,声明为UFUNCTION和UPROPERTY的,不需要额外写注册的代码,只需ue4编译并点击ue.d.ts,就能生成ts代码,生成路径是:Plugins\Puerts\Typing\ue目录。
      比如我写的:
就能引用到了:
// .h文件
#pragma once

#include ”ArrayBuffer.h”
#include ”CoreMinimal.h”
#include ”UObject/NoExportTypes.h”
#include ”TestObject.generated.h”
/**
*
*/
UCLASS()
class INSTALLPUERTS_API UMyTestObject : public UObject
{
    GENERATED_BODY()

public:
    UMyTestObject();

    UFUNCTION(BlueprintCallable, meta = (DisplayName = ”Add”, ScriptName = ”Add”, Keywords = ”test”), Category = ”Test”)
      int32 Add(int32 a, int32 b) const;

    ~UMyTestObject();
};

// .cpp文件
#include ”TestObject.h”

UMyTestObject::UMyTestObject()
{

}

UMyTestObject::~UMyTestObject()
{

}

int32 UMyTestObject::Add(int32 a, int32 b) const
{
        return a+b;
} ts文件包含库ue就能访谒了。
下面说说非UFUNTION,和UPROPERTY怎么生成:
比如UObject的GetName,GetWorld不是UFUNCTION
#include ”CoreMinimal.h”
#include ”Binding.hpp”
#include ”UEDataBinding.hpp”

UsingUClass(UObject)
UsingUClass(UWorld) // for return type

puerts::DefineClass<UObject>()
    .Method(”GetName”, SelectFunction(FString (UObjectBaseUtility::*)() const, &UObjectBaseUtility::GetName))
    .Method(”GetWorld”, MakeFunction(&UObject::GetWorld))
    .Register(); 这里因为是UE的类,所以不能使用UsingCppType,要使用UsingUClass,后面的函数基本一样。
页: [1]
查看完整版本: UE4学习之路3:Puerts用ts调用C++