全面理解UE4委托编程

馋奶兔 提交于 2019-12-06 07:15:17

UE4中的delegate委托)常用于解耦不同对象之间的关联:委托的拥有者不与监听者有直接关联,监听者通过将响应函数绑定到拥有者的委托上,使得委托触发时能及时收到通知来做相关的逻辑处理

委托本质是一个特殊类的对象,它可以储存(一个或多个)函数指针、调用参数和返回值

UE4在DelegateCombinations.h提供了一些宏来方便开发者快速来自定义一个delegate类型,目前引擎(4.23)最多支持4个负载数据和9个参数

大致地使用流程如下:

① 使用DECLARE_*宏声明一个自定义delegate类型FDelegateXXX

② 声明一个FDelegateXXX类型的代理对象

③ 绑定需要执行的函数指针到代理对象上(注:绑定函数与代理对象的参数、返回值必须完全一致)

④ 触发代理对象中的函数指针按顺序立即执行

⑤ 不需要某个函数指针时,可将其从代理对象中解绑

 

UE4提供了五类Delegate:

名称 是否支持反射 能否有返回值 触发代理 绑定个数 支持的绑定实例类型
单播代理

DECLARE_DELEGATE_*

DECLARE_DELEGATE_RetVal_*

可以有

① 无返回值情况

bool ExecuteIfBound(...)

void Execute(...)

② 有返回值情况

RetValue Execute(...)

注:RetValue为绑定函数的返回值

1个

① Static函数  // BindStatic

② 普通C++对象的成员函数  // BindRaw

③ Lambda表达式  // BindLambda

④ 与某个UObject对象关联的Lambda表达式  // BindWeakLambda

⑤ 共享引用包裹的普通C++对象的成员函数  // BindSP

⑥ 线程安全的共享引用包裹的普通C++对象的成员函数  // BindThreadSafeSP

⑦ UObject对象的成员函数 // BindUObject

⑧ UObject对象的UFunction成员函数  // BindUFunction

多播代理 DECLARE_MULTICAST_DELEGATE_* void Broadcast(...) 多个

① Static函数  // AddStatic

② 普通C++对象的成员函数  // AddRaw

③ Lambda表达式  // AddLambda

④ 与某个UObject对象关联的Lambda表达式  // AddWeakLambda

⑤ 共享引用包裹的普通C++对象的成员函数  // AddSP

⑥ 线程安全的共享引用包裹的普通C++对象的成员函数 // AddThreadSafeSP

⑦ UObject对象的成员函数  // AddUObject

⑧ UObject对象的UFunction成员函数 // AddUFunction

事件 DECLARE_EVENT_* void Broadcast(...) 多个

同上

动态代理

DECLARE_DYNAMIC_DELEGATE_*

DECLARE_DYNAMIC_DELEGATE_RetVal_*

可以有

① 无返回值情况

bool ExecuteIfBound(...)

void Execute(...)

② 有返回值情况

RetValue Execute(...)

注:RetValue为绑定函数的返回值

1个

UObject对象的UFunction成员函数

动态多播代理 DECLARE_DYNAMIC_MULTICAST_DELEGATE_*

蓝图中可使用

void Broadcast(...) 多个 UObject对象的UFunction成员函数

下面为一些类型示例:

① 单播代理(无参、无返回值)

DECLARE_DELEGATE( FSimpleDelegate );

② 多播代理(无参)

DECLARE_MULTICAST_DELEGATE( FSimpleMulticastDelegate );

③ 事件(无参)

DECLARE_EVENT(UWorld, FOnTickFlushEvent);

④ 动态代理(无参、无返回值)

DECLARE_DYNAMIC_DELEGATE(FOnGameWindowCloseButtonClickedDelegate);

⑤ 动态多播代理(1个参数)

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLandedSignature, const FHitResult&, Hit);

 

单播代理

1. 定义代理类型

① 定义返回值为void含1个int类型参数的单播代理类型FCharacterDelegate

DECLARE_DELEGATE_OneParam(FCharacterDelegate, int); // TBaseDelegate<void, int>

② 定义返回值为bool含1个int类型参数的单播代理类型FCharacterDelegate_RetVal

DECLARE_DELEGATE_RetVal_OneParam(bool, FCharacterDelegate_RetVal, int);  // TBaseDelegate<bool, int>

2.  声明代理对象

FCharacterDelegate CharacterDelegate;

FCharacterDelegate_RetVal CharacterDelegateRetVal;

 

以FCharacterDelegate为例,讲述单播代理的绑定、触发执行及存在的风险

/*** TPSProjectCharacter.h ***/

UCLASS()
class UDelegatepTestClass : public UObject
{
    GENERATED_BODY()
protected:
    int m_nValue = 0;
public:
    void DelegateProc1(int nCode)
    {
        this->m_nValue = nCode;
        UE_LOG(LogTemp, Log, TEXT("DelegateProc1 : %d"), nCode);
    }

    UFUNCTION() void DelegateUFunctionProc1(int nCode)
    {
        this->m_nValue = nCode;
        UE_LOG(LogTemp, Log, TEXT("DelegateUFunctionProc1 : %d"), nCode);
    }
};

class DelegateCppTestClass
{
    int m_nValue = 0;
public:

    void CppDelegateProc(int nCode)
    {
        this->m_nValue = nCode;
        UE_LOG(LogTemp, Log, TEXT("CppDelegateProc : %d"), nCode);
    }

    void CppDelegateProc2(int nCode)
    {
        this->m_nValue = nCode;
        UE_LOG(LogTemp, Log, TEXT("CppDelegateProc2 : %d"), nCode);
    }

    void CppDelegateProc3(int nCode)
    {
        this->m_nValue = nCode;
        UE_LOG(LogTemp, Log, TEXT("CppDelegateProc3 : %d"), nCode);
    }

    void CppDelegateProc4(int nCode)
    {
        this->m_nValue = nCode;
        UE_LOG(LogTemp, Log, TEXT("CppDelegateProc4 : %d"), nCode);
    }

    void CppDelegateProc5(int nCode)
    {
        this->m_nValue = nCode;
        UE_LOG(LogTemp, Log, TEXT("CppDelegateProc5 : %d"), nCode);
    }
};

UCLASS(config=Game)
class ATPSProjectCharacter : public ACharacter
{
        GENERATED_BODY()

public:

    static void StaticCharacterDelegateProc(int nCode);  

    void OnBind();
    void OnExecute();
    void OnUnbind(); 

    FCharacterDelegate CharacterDelegate1;
    FCharacterDelegate CharacterDelegate2;
    FCharacterDelegate CharacterDelegate3;
    FCharacterDelegate CharacterDelegate4;
    FCharacterDelegate CharacterDelegate5;
    FCharacterDelegate CharacterDelegate6;
    FCharacterDelegate CharacterDelegate7;
    FCharacterDelegate CharacterDelegate8;
    FCharacterDelegate CharacterDelegate9;
    FCharacterDelegate CharacterDelegate10;
    FCharacterDelegate CharacterDelegate11;
    FCharacterDelegate CharacterDelegate12;
    FCharacterDelegate CharacterDelegate13; 
};


/*** TPSProjectCharacter.cpp ***/
static void StaticDelegateProc(int nCode)
{
    UE_LOG(LogTemp, Log, TEXT("StaticDelegateProc : %d"), nCode);
}

void ATPSProjectCharacter::StaticCharacterDelegateProc(int nCode)
{
    UE_LOG(LogTemp, Log, TEXT("StaticCharacterDelegateProc : %d"), nCode);
}

void ATPSProjectCharacter::OnBind()
{
    // Bind Static
    CharacterDelegate1.BindStatic(StaticDelegateProc);

    CharacterDelegate2.BindStatic(ATPSProjectCharacter::StaticCharacterDelegateProc);

    // Bind Raw
    DelegateCppTestClass Obj1;
    CharacterDelegate3.BindRaw(&Obj1, &DelegateCppTestClass::CppDelegateProc);

    // Bind Lambda
    auto LambdaDelegateProc = [](int nCode)->void
    {
        UE_LOG(LogTemp, Log, TEXT("LambdaDelegateProc : %d"), nCode);
    };
    CharacterDelegate4.BindLambda(LambdaDelegateProc);

    CharacterDelegate5.BindLambda(
        [](int nCode)->void
        {
            UE_LOG(LogTemp, Log, TEXT("LambdaDelegateProc2 : %d"), nCode);
        }
    );

    // Bind Weak Lambda
    auto WeakLambdaDelegateProc = [](int nCode)->void
    {
        UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateProc : %d"), nCode);
    };
    UDelegatepTestClass* UObj1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegate6.BindWeakLambda(UObj1, WeakLambdaDelegateProc);

    UDelegatepTestClass* UObj2 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegate7.BindWeakLambda(
        UObj2, [](int nCode)->void
        {
            UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateProc2 : %d"), nCode);
        }
    );

    // Bind SP(Shared Pointer)
    TSharedRef<DelegateCppTestClass> ObjSP1 = MakeShareable(new DelegateCppTestClass());
    CharacterDelegate8.BindSP(ObjSP1, &DelegateCppTestClass::CppDelegateProc2);

    TSharedRef<DelegateCppTestClass> ObjSP2 = MakeShared<DelegateCppTestClass>();
    CharacterDelegate9.BindSP(ObjSP2, &DelegateCppTestClass::CppDelegateProc3);

    // Bind Thread Safe SP(Shared Pointer)
    TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeSP1 = MakeShareable(new DelegateCppTestClass());
    CharacterDelegate10.BindThreadSafeSP(ObjSafeSP1, &DelegateCppTestClass::CppDelegateProc4);

    TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeSP2 = MakeShared<DelegateCppTestClass, ESPMode::ThreadSafe>();
    CharacterDelegate11.BindThreadSafeSP(ObjSafeSP2, &DelegateCppTestClass::CppDelegateProc5);

    // Bind UObject
    UDelegatepTestClass* UObj3 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegate12.BindUObject(UObj3, &UDelegatepTestClass::DelegateProc1);

    // Bind UFunction
    UDelegatepTestClass* UObj4 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegate13.BindUFunction(UObj4, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1")));

}

void ATPSProjectCharacter::OnExecute()
{
    CharacterDelegate1.ExecuteIfBound(1);
    CharacterDelegate2.ExecuteIfBound(2);
    CharacterDelegate3.ExecuteIfBound(3);
    CharacterDelegate4.ExecuteIfBound(4);
    CharacterDelegate5.ExecuteIfBound(5);
    CharacterDelegate6.ExecuteIfBound(6);
    CharacterDelegate7.ExecuteIfBound(7);
    CharacterDelegate8.ExecuteIfBound(8);
    CharacterDelegate9.ExecuteIfBound(9);
    CharacterDelegate10.ExecuteIfBound(10);
    CharacterDelegate11.ExecuteIfBound(11);
    CharacterDelegate12.ExecuteIfBound(12);
    if (CharacterDelegate13.IsBound())
    {
        CharacterDelegate13.Execute(13);
    }
}

void ATPSProjectCharacter::OnUnbind()
{
    CharacterDelegate1.Unbind();
    CharacterDelegate2.Unbind();
    CharacterDelegate3.Unbind();
    CharacterDelegate4.Unbind();
    CharacterDelegate5.Unbind();
    CharacterDelegate6.Unbind();
    CharacterDelegate7.Unbind();
    CharacterDelegate8.Unbind();
    CharacterDelegate9.Unbind();
    CharacterDelegate10.Unbind();
    CharacterDelegate11.Unbind();
    CharacterDelegate12.Unbind();
    CharacterDelegate13.Unbind();
}

 

注1:BindRaw函数用于绑定普通c++对象的成员函数,若该c++对象已被销毁,触发代理执行该对象的成员函数,将会导致内存违规操作

注2:BindLambda函数用于绑定lambda表达式,若lambda表达式捕获外部变量已被销毁,触发代理执行lambda表达式,将会导致内存违规操作

注3:BindWeakLambda、BindUObject、BindUFunction绑定时会与一个UObject对象进行弱引用关联(不影响该对象被gc回收)

         若UObject对象被gc回收,直接调用Execute触发代理,将会导致内存违规操作;可先调用IsBound或调用ExecuteIfBound触发代理来检查该UObject的有效性,再来执行代理

注4:BindSP、BindThreadSafeSP绑定时会与一个智能指针对象进行弱引用关联(不影响该对象的内存回收)

         若智能指针对象的内存被回收,直接调用Execute触发代理,将会导致内存违规操作;可先调用IsBound或调用ExecuteIfBound触发代理来检查该智能指针对象的有效性,再来执行代理

注5:单播代理对象在被销毁时,会在其析构函数中调用Unbind进行解绑操作

注6:不同的绑定实例类型定义在:DelegateInstancesImpl.h

 

BindStatic(绑定实例类型为:TBaseStaticDelegateInstance)

 

BindRaw(绑定实例类型为:TBaseRawMethodDelegateInstance)

 

BindLambda(绑定实例类型为:TBaseFunctorDelegateInstance)

 

 BindWeakLambda(绑定实例类型为:TWeakBaseFunctorDelegateInstance)

 

 BindSP(绑定实例类型为:TBaseSPMethodDelegateInstance)

 

BindThreadSafeSP(绑定实例类型为:TBaseSPMethodDelegateInstance)

 

 BindUObject(绑定实例类型为:TBaseUObjectMethodDelegateInstance)

 

 

 BindUFunction(绑定实例类型为:TBaseUFunctionDelegateInstance)

 

多播代理(组播代理)

1. 定义返回值为void含1个int类型参数的多播代理类型FCharacterDelegate_Multicase

DECLARE_MULTICAST_DELEGATE_OneParam(FCharacterDelegate_Multicast, int);  // TMulticastDelegate<void, int>

 

2.  声明代理对象

FCharacterDelegate_Multicast CharacterDelegateMulticast1;

 

以FCharacterDelegate_Multicast为例,讲述多播代理的绑定、触发执行及存在的风险

void ATPSProjectCharacter::OnDelegateMulticastTest()
{
    // Add Static
    bool b1 = CharacterDelegateMulticast1.IsBound(); // false
    
    FDelegateHandle HandleMC1 = CharacterDelegateMulticast1.AddStatic(StaticDelegateProc); // 绑定实例个数为:1
    CharacterDelegateMulticast1.AddStatic(ATPSProjectCharacter::StaticCharacterDelegateProc); // 绑定实例个数为:2

    bool b2 = CharacterDelegateMulticast1.IsBound(); // true
    bool b3 = CharacterDelegateMulticast1.IsBoundToObject(this); // false

    CharacterDelegateMulticast1.Remove(HandleMC1); // 绑定实例个数为:1

    FCharacterDelegate_Multicast::FDelegate MC1 = FCharacterDelegate_Multicast::FDelegate::CreateStatic(StaticDelegate2Proc);
    CharacterDelegateMulticast1.Add(MC1); // 绑定实例个数为:2
    CharacterDelegateMulticast1.Broadcast(100); // 顺序执行绑定实例列表(共2个)
    

    // Add Raw
    DelegateCppTestClass ObjMC1;
    CharacterDelegateMulticast2.AddRaw(&ObjMC1, &DelegateCppTestClass::CppDelegateProc); // 绑定实例个数为:1
    CharacterDelegateMulticast2.AddRaw(&ObjMC1, &DelegateCppTestClass::CppDelegateProc2); // 绑定实例个数为:2
    CharacterDelegateMulticast2.AddStatic(ATPSProjectCharacter::StaticCharacterDelegateProc); // 绑定实例个数为:3

    bool b4 = CharacterDelegateMulticast2.IsBoundToObject(&ObjMC1); // true

    CharacterDelegateMulticast2.RemoveAll(&ObjMC1); // CppDelegateProc、CppDelegateProc2被删除,绑定实例个数为:1

    bool b5 = CharacterDelegateMulticast2.IsBoundToObject(&ObjMC1); // false

    CharacterDelegateMulticast2.Broadcast(101); // 顺序执行绑定实例列表(共1个)
    
    CharacterDelegateMulticast2.Clear(); // 绑定实例个数为:0

    // Add Lambda
    auto LambdaDelegateMCProc = [](int nCode)->void
    {
        UE_LOG(LogTemp, Log, TEXT("LambdaDelegateMCProc : %d"), nCode);
    };
    CharacterDelegateMulticast3.AddLambda(LambdaDelegateMCProc);// 绑定实例个数为:1

    CharacterDelegateMulticast3.AddLambda(
        [](int nCode)->void
    {
        UE_LOG(LogTemp, Log, TEXT("LambdaDelegateMCProc2 : %d"), nCode);
    }
    );// 绑定实例个数为:2
    CharacterDelegateMulticast3.Broadcast(102);// 顺序执行绑定实例列表(共2个)

    // Add Weak Lambda
    auto WeakLambdaDelegateMCProc = [](int nCode)->void
    {
        UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateMCProc : %d"), nCode);
    };
    UDelegatepTestClass* UObjMC1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegateMulticast4.AddWeakLambda(UObjMC1, WeakLambdaDelegateMCProc);// 绑定实例个数为:1

    UDelegatepTestClass* UObjMC2 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegateMulticast4.AddWeakLambda(
        UObjMC2, [](int nCode)->void
    {
        UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateMCProc2 : %d"), nCode);
    }
    );// 绑定实例个数为:2
    CharacterDelegateMulticast4.Broadcast(103);// 顺序执行绑定实例列表(共2个)

    // Add SP(Shared Pointer)
    TSharedRef<DelegateCppTestClass> ObjMCSP1 = MakeShareable(new DelegateCppTestClass());
    CharacterDelegateMulticast5.AddSP(ObjMCSP1, &DelegateCppTestClass::CppDelegateProc2);// 绑定实例个数为:1

    TSharedRef<DelegateCppTestClass> ObjMCSP2 = MakeShared<DelegateCppTestClass>();
    CharacterDelegateMulticast5.AddSP(ObjMCSP2, &DelegateCppTestClass::CppDelegateProc3);// 绑定实例个数为:2
    CharacterDelegateMulticast5.Broadcast(104);

    // Add Thread Safe SP(Shared Pointer)
    TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeMCSP1 = MakeShareable(new DelegateCppTestClass());
    CharacterDelegateMulticast6.AddThreadSafeSP(ObjSafeMCSP1, &DelegateCppTestClass::CppDelegateProc4);// 绑定实例个数为:1

    TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeMCSP2 = MakeShared<DelegateCppTestClass, ESPMode::ThreadSafe>();
    CharacterDelegateMulticast6.AddThreadSafeSP(ObjSafeMCSP2, &DelegateCppTestClass::CppDelegateProc5);// 绑定实例个数为:2

    CharacterDelegateMulticast6.Broadcast(105);// 顺序执行绑定实例列表(共2个)

    // Add UObject
    UDelegatepTestClass* UObjMC3 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegateMulticast7.AddUObject(UObjMC3, &UDelegatepTestClass::DelegateProc1);// 绑定实例个数为:1
    CharacterDelegateMulticast7.AddUObject(UObjMC3, &UDelegatepTestClass::DelegateProc2);// 绑定实例个数为:2

    CharacterDelegateMulticast7.Broadcast(106);// 顺序执行绑定实例列表(共2个)

    // Add UFunction
    UDelegatepTestClass* UObjMC4 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegateMulticast8.AddUFunction(UObjMC4, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1")));// 绑定实例个数为:1
    CharacterDelegateMulticast8.Broadcast(107);// 顺序执行绑定实例列表(共1个)
}

 

注1:AddRaw函数用于绑定普通c++对象的成员函数,若该c++对象已被销毁,触发代理执行该对象的成员函数,将会导致内存违规操作

注2:AddLambda函数用于绑定lambda表达式,若lambda表达式捕获外部变量已被销毁,触发代理执行lambda表达式,将会导致内存违规操作

注3:AddWeakLambda、AddUObject、AddUFunction绑定时会与一个UObject对象进行弱引用关联(不影响该对象被gc回收),在触发代理时,会先检查该UObject的有效性,再来执行代理

注4:BindSP、BindThreadSafeSP绑定时会与一个智能指针对象进行弱引用关联(不影响该对象的内存回收),在触发代理时,会先检查该智能指针对象的有效性,再来执行代理

注5:可通过Remove删除指定Handle的代理对象;通过RemoveAll删除相关UObject对象所有的代理对象;通过Clear清除代理对象列表

 

事件

1. 定义返回值为void含1个int类型参数的事件类型FCharacterEvent

DECLARE_EVENT_OneParam(ATPSProjectCharacter, FCharacterEvent, int);  // TBaseMulticastDelegate<void, int>

 

注1:定义事件类型宏的第一个参数为拥有该事件类型A的类型B,即为类型B为事件类型A的友元类,可以访问A中的私有成员

注2:定义事件类型宏一般放在一个类的内部(即访问该类型时需要带上所在类的名称前缀,如ATPSProjectCharacter::FCharacterEvent),可有效减少事件类型名称冲突

2.  声明代理对象

FCharacterEvent CharacterEvent;

 

事件本质是一个多播代理,另外,在事件所在的类型ATPSProjectCharacter中,可访问事件的私有成员

 

动态代理

1. 定义返回值为void含1个int类型参数的动态代理类型FCharacterDelegate_Dynamic

DECLARE_DYNAMIC_DELEGATE_OneParam(FCharacterDelegate_Dynamic, int, nCode); // TBaseDynamicDelegate<FWeakObjectPtr, void, int> 

2. 定义返回值为bool含1个int类型参数的动态代理类型FCharacterDelegate_DynamicRetVal

DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(bool, FCharacterDelegate_DynamicRetVal, int, nCode);  // TBaseDynamicDelegate<FWeakObjectPtr, bool, int> 

 

 

以FCharacterDelegate_Dynamic为例,讲述动态代理的绑定、触发执行及存在的风险

void ATPSProjectCharacter::OnDelegateDynamicTest()
{
    bool bd1 = CharacterDelegateDynamic.IsBound(); // false

    UDelegatepTestClass* UObjDy1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    CharacterDelegateDynamic.BindUFunction(UObjDy1, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1")));// 绑定实例个数为:1

    bool bd2 = CharacterDelegateDynamic.IsBound(); // true

    CharacterDelegateDynamic.ExecuteIfBound(200);

    CharacterDelegateDynamic.Unbind();

    // 使用BindDynamic宏
    CharacterDelegateDynamic2.BindDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc);
    if (CharacterDelegateDynamic2.IsBound()) // true
    {
        CharacterDelegateDynamic2.Execute(201);
    }    

    CharacterDelegateDynamic2.Clear(); // 功能与Unbind一样,内部是直接调用Unbind方法
}

 

注:BindUObject绑定时会与一个UObject对象进行弱引用关联(不影响该对象被gc回收)

      若UObject对象被gc回收,直接调用Execute触发代理,将会导致内存违规操作;可先调用IsBound或调用ExecuteIfBound触发代理来检查该UObject的有效性,再来执行代理

 

动态多播代理

定义返回值为void含1个int类型参数的动态多播代理类型FCharacterDelegate_DynamicMulticast

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCharacterDelegate_DynamicMulticast, int, nCode); // TBaseDynamicMulticastDelegate<FWeakObjectPtr, void, int>

 

 

 

 FCharacterDelegate_DynamicMulticast为例,讲述动态多播代理的绑定、触发执行及存在的风险 

void ATPSProjectCharacter::OnDelegateDynamicMulticastTest()
{
    UDelegatepTestClass* UObjDMC1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass());
    // 使用AddDynamic宏
    //CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateProc1); // 运行时错误:Unable to bind delegate (function might not be marked as a UFUNCTION or object may be pending kill)
    CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateUFunctionProc1); // 绑定实例个数为:1
    //CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateUFunctionProc1); // 运行时错误 加入DelegateUFunctionProc1的绑定实例已存在
    CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateUFunctionProc2); // 绑定实例个数为:2

    // 使用AddUniqueDynamic宏
    CharacterDelegateDynamicMulticast.AddUniqueDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc); // 绑定实例个数为:3
    CharacterDelegateDynamicMulticast.AddUniqueDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc); // 加入DynamicMulticastProc的绑定实例已存在
    CharacterDelegateDynamicMulticast.AddUniqueDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc2); // 绑定实例个数为:4
 
    FScriptDelegate delegateVar1; // FScriptDelegate即为TScriptDelegate<>
    delegateVar1.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ATPSProjectCharacter::DynamicMulticastProc3")));
    CharacterDelegateDynamicMulticast.Add(delegateVar1); // 绑定实例个数为:5
    FScriptDelegate delegateVar2;
    delegateVar2.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ATPSProjectCharacter::DynamicMulticastProc3")));
    //CharacterDelegateDynamicMulticast.Add(delegateVar2); // 运行时错误 加入DynamicMulticastProc3的绑定实例已存在
    CharacterDelegateDynamicMulticast.AddUnique(delegateVar2); // 加入DynamicMulticastProc3的绑定实例已存在

    // 使用RemoveDynamic宏
    CharacterDelegateDynamicMulticast.RemoveDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc2); // 绑定实例个数为:4

    // 使用IsAlreadyBound宏
    bool bDMC1 = CharacterDelegateDynamicMulticast.IsAlreadyBound(this, &ATPSProjectCharacter::DynamicMulticastProc3);// true

    CharacterDelegateDynamicMulticast.Remove(delegateVar2); // 绑定实例个数为:3
    CharacterDelegateDynamicMulticast.Remove(UObjDMC1, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1")));// 绑定实例个数为:2

    bool bDMC2 = CharacterDelegateDynamicMulticast.IsAlreadyBound(this, &ATPSProjectCharacter::DynamicMulticastProc3); // false

    CharacterDelegateDynamicMulticast.RemoveAll(this); // 绑定实例个数为:1

    CharacterDelegateDynamicMulticast.Broadcast(300); // 顺序执行绑定实例列表(共1个)

    CharacterDelegateDynamicMulticast.Clear(); // 清除所有绑定实例
}

 

需要注意的是,只有动态多播代理才支持反射,才能在蓝图中使用(对其进行绑定、解绑、Broadcast、以及清除操作)

BP_MyTPSProjectCharacter是一个放置在关卡中的派生于ATPSProjectCharacter的蓝图对象

 

下图为在关卡蓝图中分配并绑定事件到BP_MyTPSProjectCharacter实例的CharacterDelegateDynamicMulticast动态多播代理变量上,按下8按键触发代理执行

 

引擎内建委托 

系统和引擎

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Engine\Source\Runtime\Core\Public\Misc\CoreDelegates.h **/
class CORE_API FCoreDelegates 
{
    // Callback for platform handling when flushing async loads.
    DECLARE_MULTICAST_DELEGATE(FOnAsyncLoadingFlush);
    static FOnAsyncLoadingFlush OnAsyncLoadingFlush;

    // Callback for a game thread interruption point when a async load flushing. Used to updating UI during long loads.
    DECLARE_MULTICAST_DELEGATE(FOnAsyncLoadingFlushUpdate);
    static FOnAsyncLoadingFlushUpdate OnAsyncLoadingFlushUpdate;

    // Callback on the game thread when an async load is started. This goes off before the packages has finished loading
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnAsyncLoadPackage, const FString&);
    static FOnAsyncLoadPackage OnAsyncLoadPackage;

    DECLARE_MULTICAST_DELEGATE_OneParam(FOnSyncLoadPackage, const FString&);
    static FOnSyncLoadPackage OnSyncLoadPackage;
    
    
    
    // Callback when an ensure has occurred
    static FOnHandleSystemEnsure OnHandleSystemEnsure;

    // Callback when an error (crash) has occurred
    static FOnHandleSystemError OnHandleSystemError;
    
    
    // Called when an error occurred.
    static FSimpleMulticastDelegate OnShutdownAfterError;

    // Called when appInit is called, very early in startup
    static FSimpleMulticastDelegate OnInit;

    // Called at the end of UEngine::Init, right before loading PostEngineInit modules for both normal execution and commandlets
    static FSimpleMulticastDelegate OnPostEngineInit;

    // Called at the very end of engine initialization, right before the engine starts ticking. This is not called for commandlets
    static FSimpleMulticastDelegate OnFEngineLoopInitComplete;

    // Called when the application is about to exit.
    static FSimpleMulticastDelegate OnExit;

    // Called when before the application is exiting.
    static FSimpleMulticastDelegate OnPreExit;
    
    
    // Called at the beginning of a frame
    static FSimpleMulticastDelegate OnBeginFrame;

    // Called at the end of a frame
    static FSimpleMulticastDelegate OnEndFrame;

    // Called at the beginning of a frame on the renderthread
    static FSimpleMulticastDelegate OnBeginFrameRT;

    // Called at the end of a frame on the renderthread
    static FSimpleMulticastDelegate OnEndFrameRT;
    
    
    // IOS-style temperature updates, allowing game to scale down to let temp drop (to avoid thermal throttling on mobile, for instance) */
    // There is a parellel enum in ApplicationLifecycleComponent
    enum class ETemperatureSeverity : uint8
    {
        Unknown,
        Good,
        Bad,
        Serious,
        Critical,

        NumSeverities,
    };
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnTemperatureChange, ETemperatureSeverity);
    static FOnTemperatureChange OnTemperatureChange;

    /** Called when the OS goes into low power mode */
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnLowPowerMode, bool);
    static FOnLowPowerMode OnLowPowerMode;
    
    
    DECLARE_MULTICAST_DELEGATE_TwoParams(FOnSystemResolutionChanged, uint32 /*ResX*/, uint32 /*ResY*/);
    static FOnSystemResolutionChanged OnSystemResolutionChanged;
    
    
    /** IOS-style application lifecycle delegates */
    DECLARE_MULTICAST_DELEGATE(FApplicationLifetimeDelegate);

    // This is called when the application is about to be deactivated (e.g., due to a phone call or SMS or the sleep button).
    // The game should be paused if possible, etc...
    static FApplicationLifetimeDelegate ApplicationWillDeactivateDelegate;
    
    // Called when the application has been reactivated (reverse any processing done in the Deactivate delegate)
    static FApplicationLifetimeDelegate ApplicationHasReactivatedDelegate;

    // This is called when the application is being backgrounded (e.g., due to switching
    // to another app or closing it via the home button)
    // The game should release shared resources, save state, etc..., since it can be
    // terminated from the background state without any further warning.
    static FApplicationLifetimeDelegate ApplicationWillEnterBackgroundDelegate; // for instance, hitting the home button
    
    // Called when the application is returning to the foreground (reverse any processing done in the EnterBackground delegate)
    static FApplicationLifetimeDelegate ApplicationHasEnteredForegroundDelegate;

    // This *may* be called when the application is getting terminated by the OS.
    // There is no guarantee that this will ever be called on a mobile device,
    // save state when ApplicationWillEnterBackgroundDelegate is called instead.
    static FApplicationLifetimeDelegate ApplicationWillTerminateDelegate;
    
    
    // Called when the OS needs control of the music (parameter is true) or when the OS returns
    // control of the music to the application (parameter is false). This can happen due to a
    // phone call or timer or other OS-level event. This is currently triggered only on iOS
    // devices.
    DECLARE_MULTICAST_DELEGATE_OneParam(FUserMusicInterruptDelegate, bool);
    static FUserMusicInterruptDelegate UserMusicInterruptDelegate;
    
    // [iOS only] Called when the mute switch is detected as changed or when the
    // volume changes. Parameter 1 is the mute switch state (true is muted, false is
    // unmuted). Parameter 2 is the volume as an integer from 0 to 100.
    DECLARE_MULTICAST_DELEGATE_TwoParams(FAudioMuteDelegate, bool, int);
    static FAudioMuteDelegate AudioMuteDelegate;
    
    // [iOS only] Called when the audio device changes
    // For instance, when the headphones are plugged in or removed
    DECLARE_MULTICAST_DELEGATE_OneParam(FAudioRouteChangedDelegate, bool);
    static FAudioRouteChangedDelegate AudioRouteChangedDelegate;
    
    
    // Called when the OS is running low on resources and asks the application to free up any cached resources, drop graphics quality etc.
    static FApplicationLifetimeDelegate ApplicationShouldUnloadResourcesDelegate;
    
    /** Sent when a device screen orientation changes */
    DECLARE_MULTICAST_DELEGATE_OneParam(FApplicationReceivedOnScreenOrientationChangedNotificationDelegate, int32);
    static FApplicationReceivedOnScreenOrientationChangedNotificationDelegate ApplicationReceivedScreenOrientationChangedNotificationDelegate;
    
    /** Callback for notifications regarding changes of the rendering thread. */
    DECLARE_MULTICAST_DELEGATE(FRenderingThreadChanged)

    /** Sent just after the rendering thread has been created. */
    static FRenderingThreadChanged PostRenderingThreadCreated;
    /* Sent just before the rendering thread is destroyed. */
    static FRenderingThreadChanged PreRenderingThreadDestroyed;
    
    
    // Called to request that systems free whatever memory they are able to. Called early in LoadMap.
    // Caller is responsible for flushing rendering etc. See UEngine::TrimMemory
    static FSimpleMulticastDelegate& GetMemoryTrimDelegate();

    // Called when OOM event occurs, after backup memory has been freed, so there's some hope of being effective
    static FSimpleMulticastDelegate& GetOutOfMemoryDelegate();
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Engine\Source\Runtime\CoreUObject\Public\UObject\UObjectGlobals.h **/
struct COREUOBJECT_API FCoreUObjectDelegates
{
    /** Sent at the very beginning of LoadMap */
    DECLARE_MULTICAST_DELEGATE_OneParam(FPreLoadMapDelegate, const FString& /* MapName */);
    static FPreLoadMapDelegate PreLoadMap;

    /** Sent at the _successful_ end of LoadMap */
    DECLARE_MULTICAST_DELEGATE_OneParam(FPostLoadMapDelegate, UWorld* /* LoadedWorld */);
    static FPostLoadMapDelegate PostLoadMapWithWorld;
    
    /** Sent when a network replay has started */
    static FSimpleMulticastDelegate PostDemoPlay;

    /** Called before garbage collection */
    static FSimpleMulticastDelegate& GetPreGarbageCollectDelegate();

    /** Delegate type for reachability analysis external roots callback. First parameter is FGarbageCollectionTracer to use for tracing, second is flags with which objects should be kept alive regardless, third is whether to force single threading */
    DECLARE_MULTICAST_DELEGATE_ThreeParams(FTraceExternalRootsForReachabilityAnalysisDelegate, FGarbageCollectionTracer&, EObjectFlags, bool);

    /** Called as last phase of reachability analysis. Allow external systems to add UObject roots *after* first reachability pass has been done */
    static FTraceExternalRootsForReachabilityAnalysisDelegate TraceExternalRootsForReachabilityAnalysis;

    /** Called after reachability analysis, before any purging */
    static FSimpleMulticastDelegate PostReachabilityAnalysis;

    /** Called after garbage collection */
    static FSimpleMulticastDelegate& GetPostGarbageCollect();

    /** Called before ConditionalBeginDestroy phase of garbage collection */
    static FSimpleMulticastDelegate PreGarbageCollectConditionalBeginDestroy;

    /** Called after ConditionalBeginDestroy phase of garbage collection */
    static FSimpleMulticastDelegate PostGarbageCollectConditionalBeginDestroy;

    /** Queries whether an object should be loaded on top ( replace ) an already existing one */
    DECLARE_DELEGATE_RetVal_OneParam(bool, FOnLoadObjectsOnTop, const FString&);
    static FOnLoadObjectsOnTop ShouldLoadOnTop;

    /** Called when path to world root is changed */
    DECLARE_MULTICAST_DELEGATE_OneParam(FPackageCreatedForLoad, class UPackage*);
    static FPackageCreatedForLoad PackageCreatedForLoad;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Engine\Source\Runtime\Engine\Classes\Engine\Engine.h **/
class ENGINE_API UEngine : public UObject , public FExec 
{
    /** Delegate called just prior to rendering. */
    FPreRenderDelegate PreRenderDelegate;
    FPreRenderDelegate& GetPreRenderDelegate() { return PreRenderDelegate; }

    /** 
     * Error message event relating to server travel failures 
     * 
     * @param Type type of travel failure
     * @param ErrorString additional error message
     */
    DECLARE_EVENT_ThreeParams(UEngine, FOnTravelFailure, UWorld*, ETravelFailure::Type, const FString&);
    FOnTravelFailure TravelFailureEvent;

    /** 
     * Error message event relating to network failures 
     * 
     * @param Type type of network failure
     * @param Name name of netdriver that generated the failure
     * @param ErrorString additional error message
     */
    DECLARE_EVENT_FourParams(UEngine, FOnNetworkFailure, UWorld*, UNetDriver*, ENetworkFailure::Type, const FString&);
    FOnNetworkFailure NetworkFailureEvent;

    /** 
     * Network lag detected. For the server this means all clients are timing out. On the client it means you are timing out.
     */
    DECLARE_EVENT_ThreeParams(UEngine, FOnNetworkLagStateChanged, UWorld*, UNetDriver*, ENetworkLagState::Type);
    FOnNetworkLagStateChanged NetworkLagStateChangedEvent;
    
    
    /** Triggered when a world is added. */    
    DECLARE_EVENT_OneParam( UEngine, FWorldAddedEvent , UWorld* );
    
    /** Return the world added event. */
    FWorldAddedEvent&        OnWorldAdded() { return WorldAddedEvent; }
    
    /** Triggered when a world is destroyed. */    
    DECLARE_EVENT_OneParam( UEngine, FWorldDestroyedEvent , UWorld* );
    
    /** Return the world destroyed event. */    
    FWorldDestroyedEvent&    OnWorldDestroyed() { return WorldDestroyedEvent; }
};

 

编辑器

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Engine\Source\Editor\UnrealEd\Public\Editor.h **/
#if WITH_EDITOR
struct UNREALED_API FEditorDelegates
{
    /** Sent when a PIE session is beginning (before we decide if PIE can run - allows clients to avoid blocking PIE) */
    static FOnPIEEvent PreBeginPIE;
    /** Sent when a PIE session is beginning (but hasn't actually started yet) */
    static FOnPIEEvent BeginPIE;
    /** Sent when a PIE session has fully started and after BeginPlay() has been called */
    static FOnPIEEvent PostPIEStarted;
    /** Sent when a PIE session is ending, before anything else happens */
    static FOnPIEEvent PrePIEEnded;
    /** Sent when a PIE session is ending */
    static FOnPIEEvent EndPIE;
    
    /** Called when a map is opened, giving map name, and whether it was a template */
    static FOnMapOpened OnMapOpened;
};
#endif

 

游戏世界

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Engine\Source\Runtime\Engine\Classes\Engine\World.h **/
class ENGINE_API FWorldDelegates
{
    DECLARE_MULTICAST_DELEGATE_TwoParams(FOnWorldTickStart, ELevelTick, float);
    static FOnWorldTickStart OnWorldTickStart;
    
    // Delegate called before actors are ticked for each world. Delta seconds is already dilated and clamped.
    DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnWorldPreActorTick, UWorld* /*World*/, ELevelTick/**Tick Type*/, float/**Delta Seconds*/);
    static FOnWorldPreActorTick OnWorldPreActorTick;

    DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnWorldPostActorTick, UWorld* /*World*/, ELevelTick/**Tick Type*/, float/**Delta Seconds*/);
    static FOnWorldPostActorTick OnWorldPostActorTick;

    // Callback for world creation
    static FWorldEvent OnPostWorldCreation;
    
    // Callback for world initialization (pre)
    static FWorldInitializationEvent OnPreWorldInitialization;
    
    // Callback for world initialization (post)
    static FWorldInitializationEvent OnPostWorldInitialization;
    
    // Callback for world cleanup start
    static FWorldCleanupEvent OnWorldCleanup;

    // Callback for world cleanup end
    static FWorldCleanupEvent OnPostWorldCleanup;

    // Callback for world destruction (only called for initialized worlds)
    static FWorldEvent OnPreWorldFinishDestroy;

    // Sent when a ULevel is added to the world via UWorld::AddToWorld
    static FOnLevelChanged            LevelAddedToWorld;

    // Sent when a ULevel is removed from the world via UWorld::RemoveFromWorld or 
    // LoadMap (a NULL object means the LoadMap case, because all levels will be 
    // removed from the world without a RemoveFromWorld call for each)
    static FOnLevelChanged            LevelRemovedFromWorld;
    
    // Global Callback after actors have been initialized (on any world)
    static UWorld::FOnWorldInitializedActors OnWorldInitializedActors;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Engine\Source\Runtime\Engine\Classes\Engine\World.h **/
DECLARE_MULTICAST_DELEGATE_OneParam(FOnActorSpawned, AActor*);

class ENGINE_API UWorld final : public UObject, public FNetworkNotify 
{
    /** a delegate that broadcasts a notification whenever an actor is spawned */
    FOnActorSpawned OnActorSpawned;
    
    /** Add a listener for OnActorSpawned events */
    FDelegateHandle AddOnActorSpawnedHandler( const FOnActorSpawned::FDelegate& InHandler );

    /** Remove a listener for OnActorSpawned events */
    void RemoveOnActorSpawnedHandler( FDelegateHandle InHandle );
    
    
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnWorldInitializedActors, const FActorsInitializedParams&);
    FOnWorldInitializedActors OnActorsInitialized;
    
    DECLARE_EVENT_OneParam(UWorld, FOnNetTickEvent, float);
    DECLARE_EVENT(UWorld, FOnTickFlushEvent);
    /** Event to gather up all net drivers and call TickDispatch at once */
    FOnNetTickEvent TickDispatchEvent;

    /** Event to gather up all net drivers and call PostTickDispatch at once */
    FOnTickFlushEvent PostTickDispatchEvent;

    /** Event to gather up all net drivers and call TickFlush at once */
    FOnNetTickEvent TickFlushEvent;
    
    /** Event to gather up all net drivers and call PostTickFlush at once */
    FOnTickFlushEvent PostTickFlushEvent;
    
    /** Called when the number of levels changes. */
    DECLARE_EVENT(UWorld, FOnLevelsChangedEvent);
    
    /** Broadcasts whenever the number of levels changes */
    FOnLevelsChangedEvent LevelsChangedEvent;
    
    DECLARE_EVENT_OneParam(UWorld, FOnGameStateSetEvent, AGameStateBase*);
    /** Called whenever the gamestate is set on the world. */
    FOnGameStateSetEvent GameStateSetEvent;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Engine\Source\Runtime\Engine\Public\GameDelegates.h */
class ENGINE_API FGameDelegates
{
    /** Return a single FGameDelegates object */
    static FGameDelegates& Get();

    // Called when an exit command is received
    DEFINE_GAME_DELEGATE_TYPED(ExitCommandDelegate, FSimpleMulticastDelegate);

    // Called when ending playing a map
    DEFINE_GAME_DELEGATE_TYPED(EndPlayMapDelegate, FSimpleMulticastDelegate);

    // Called when a matinee is canceled 
    DEFINE_GAME_DELEGATE_TYPED(MatineeCancelledDelegate, FSimpleMulticastDelegate);

    // Called when a pending connection has been lost 
    DEFINE_GAME_DELEGATE_TYPED(PendingConnectionLostDelegate, FPendingConnectionLostDelegate);

    // Called when a player is disconnecting due to network failure
    DEFINE_GAME_DELEGATE(HandleDisconnectDelegate);
};

 

引擎子系统

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API FNetDelegates
{
    /**
     * Delegate fired when a pending net game has created a UNetConnection to the server but hasn't sent the initial join message yet.
     *
     * @param PendingNetGame pointer to the PendingNetGame that is initializing its connection to a server.
     */
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnPendingNetGameConnectionCreated, UPendingNetGame* /*PendingNetGame*/);
    static FOnPendingNetGameConnectionCreated OnPendingNetGameConnectionCreated;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_VTABLE UNetDriver : public UObject, public FExec 
{
#if !UE_BUILD_SHIPPING
    /** Delegate for hooking ProcessRemoteFunction */
    FOnSendRPC    SendRPCDel;
#endif
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_VTABLE UNetConnection : public UPlayer 
{
#if !UE_BUILD_SHIPPING
    /** Delegate for hooking ReceivedRawPacket */
    FOnReceivedRawPacket    ReceivedRawPacketDel;

    /** Delegate for hooking LowLevelSend */
    FOnLowLevelSend            LowLevelSendDel;
#endif
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API ULevelStreaming : public UObject 
{
    /** Called when level is streamed in  */
    UPROPERTY(BlueprintAssignable)
    FLevelStreamingLoadedStatus            OnLevelLoaded;
    
    /** Called when level is streamed out  */
    UPROPERTY(BlueprintAssignable)
    FLevelStreamingLoadedStatus            OnLevelUnloaded;
    
    /** Called when level is added to the world  */
    UPROPERTY(BlueprintAssignable)
    FLevelStreamingVisibilityStatus        OnLevelShown;
    
    /** Called when level is removed from the world  */
    UPROPERTY(BlueprintAssignable)
    FLevelStreamingVisibilityStatus        OnLevelHidden;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API FPhysicsDelegates
{
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnPhysSceneInit, FPhysScene*);
    static FOnPhysSceneInit OnPhysSceneInit;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FPhysScene_PhysX 
{
    DECLARE_MULTICAST_DELEGATE_TwoParams(FOnPhysScenePreTick, FPhysScene_PhysX*, float /*DeltaSeconds*/);
    FOnPhysScenePreTick OnPhysScenePreTick;

    DECLARE_MULTICAST_DELEGATE_TwoParams(FOnPhysSceneStep, FPhysScene_PhysX*, float /*DeltaSeconds*/);
    FOnPhysSceneStep OnPhysSceneStep;

    DECLARE_MULTICAST_DELEGATE_OneParam(FOnPhysScenePostTick, FPhysScene*);
    FOnPhysScenePostTick OnPhysScenePostTick;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CORE_API FModuleManager : private FSelfRegisteringExec 
{
    /**
     * Gets an event delegate that is executed when the set of known modules changed, i.e. upon module load or unload.
     *
     * The first parameter is the name of the module that changed.
     * The second parameter is the reason for the change.
     *
     * @return The event delegate.
     */
    DECLARE_EVENT_TwoParams(FModuleManager, FModulesChangedEvent, FName, EModuleChangeReason);
    FModulesChangedEvent& OnModulesChanged( )
    {
        return ModulesChangedEvent;
    }

    /**
     * Gets a multicast delegate that is executed when any UObjects need processing after a module was loaded.
     *
     * @return The delegate.
     */
    DECLARE_EVENT_TwoParams(FModuleManager, ProcessLoadedObjectsEvent, FName, bool);
    ProcessLoadedObjectsEvent& OnProcessLoadedObjectsCallback()
    {
        return ProcessLoadedObjectsCallback;
    }

    /**
     * Gets a delegate that is executed when a module containing UObjects has been loaded.
     *
     * The first parameter is the name of the loaded module.
     *
     * @return The event delegate.
     */
    DECLARE_DELEGATE_RetVal_OneParam(bool, FIsPackageLoadedCallback, FName);
    FIsPackageLoadedCallback& IsPackageLoadedCallback()
    {
        return IsPackageLoaded;
    }
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class IGameMoviePlayer 
{
    /** Called before playing a movie if the loading screen has not been prepared. */
    DECLARE_EVENT(IGameMoviePlayer, FOnPrepareLoadingScreen)
    virtual FOnPrepareLoadingScreen& OnPrepareLoadingScreen() = 0;
    
    /* Callback for when the LoadingScreen setup above in WidgetLoadingScreen is displayed **/
    DECLARE_EVENT(IGameMoviePlayer, FOnMoviePlaybackStarted)
    virtual FOnMoviePlaybackStarted& OnMoviePlaybackStarted() = 0;

    DECLARE_EVENT(IGameMoviePlayer, FOnMoviePlaybackFinished)
    virtual FOnMoviePlaybackFinished& OnMoviePlaybackFinished() = 0;

    DECLARE_EVENT_OneParam(IGameMoviePlayer, FOnMovieClipFinished, const FString&)
    virtual FOnMovieClipFinished& OnMovieClipFinished() = 0;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ONLINESUBSYSTEM_API FOnlineSubsystemDelegates
{

public:

    /**
     * Notification that a new online subsystem instance has been created
     * 
     * @param NewSubsystem the new instance created
     */
    DECLARE_MULTICAST_DELEGATE_OneParam(FOnOnlineSubsystemCreated, class IOnlineSubsystem* /*NewSubsystem*/);
    static FOnOnlineSubsystemCreated OnOnlineSubsystemCreated;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class GenericApplication 
{
    DECLARE_EVENT_OneParam(GenericApplication, FOnDisplayMetricsChanged, const FDisplayMetrics&);
    
    /** Notifies subscribers when any of the display metrics change: e.g. resolution changes or monitor sare re-arranged. */
    FOnDisplayMetricsChanged& OnDisplayMetricsChanged(){ return OnDisplayMetricsChangedEvent; }
    
    /** Delegate for virtual keyboard being shown/hidden in case UI wants to slide out of the way */
    DECLARE_EVENT_OneParam(FSlateApplication, FVirtualKeyboardShownEvent, FPlatformRect);
    FVirtualKeyboardShownEvent& OnVirtualKeyboardShown()  { return VirtualKeyboardShownEvent; }
    
    DECLARE_EVENT(FSlateApplication, FVirtualKeyboardHiddenEvent);
    FVirtualKeyboardHiddenEvent& OnVirtualKeyboardHidden()  { return VirtualKeyboardHiddenEvent; }
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class SLATE_API FSlateApplication
{
    static FSlateApplication& Get()
    {
        check( IsInGameThread() || IsInSlateThread() || IsInAsyncLoadingThread() );
        return *CurrentApplication;
    }
    
    /** Event before slate application ticks. */
    DECLARE_EVENT_OneParam(FSlateApplication, FSlateTickEvent, float);
    FSlateTickEvent& OnPreTick()  { return PreTickEvent; }

    /** Event after slate application ticks. */
    FSlateTickEvent& OnPostTick()  { return PostTickEvent; }
    
    /** Delegate called when a window is about to be destroyed */
    DECLARE_EVENT_OneParam(FSlateApplication, FOnWindowBeingDestroyed, const SWindow&);
    FOnWindowBeingDestroyed& OnWindowBeingDestroyed() { return WindowBeingDestroyedEvent; }
    
    /** Sets the handler for otherwise unhandled key down events. This is used by the editor to provide a global action list, if the key was not consumed by any widget. */
    void SetUnhandledKeyDownEventHandler( const FOnKeyEvent& NewHandler );
    
    /** Delegate for when a key down event occurred but was not handled in any other way by ProcessKeyDownMessage */
    FOnKeyEvent UnhandledKeyDownEventHandler;
    
    DECLARE_EVENT_OneParam(FSlateApplication, FApplicationActivationStateChangedEvent, const bool /*IsActive*/)
    virtual FApplicationActivationStateChangedEvent& OnApplicationActivationStateChanged() { return ApplicationActivationStateChangedEvent; }
    
    FApplicationActivationStateChangedEvent ApplicationActivationStateChangedEvent;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API UGameViewportClient : public UScriptViewportClient, public FExec
{
    #if WITH_EDITOR
    /** Delegate called when game viewport client received input key */
    FOnGameViewportInputKey GameViewportInputKeyDelegate;
#endif

    /** Delegate called at the end of the frame when a screenshot is captured */
    static FOnScreenshotCaptured ScreenshotCapturedDelegate;
    
    /** Delegate called right after the viewport is rendered */
    static FOnViewportRendered ViewportRenderedDelegate;

    /** Delegate called when a request to close the viewport is received */
    FOnCloseRequested CloseRequestedDelegate;

    /** Delegate called when the window owning the viewport is requested to close */
    FOnWindowCloseRequested WindowCloseRequestedDelegate;

    /** Delegate called when the game viewport is created. */
    static FSimpleMulticastDelegate CreatedDelegate;

    /** Delegate called when a player is added to the game viewport */
    FOnGameViewportClientPlayerAction PlayerAddedDelegate;

    /** Delegate called when a player is removed from the game viewport */
    FOnGameViewportClientPlayerAction PlayerRemovedDelegate;

    /** Delegate called when the engine starts drawing a game viewport */
    FSimpleMulticastDelegate BeginDrawDelegate;

    /** Delegate called when the game viewport is drawn, before drawing the console */
    FSimpleMulticastDelegate DrawnDelegate;

    /** Delegate called when the engine finishes drawing a game viewport */
    FSimpleMulticastDelegate EndDrawDelegate;

    /** Delegate called when ticking the game viewport */
    FOnGameViewportTick TickDelegate;

    /** Delegate called when the engine toggles fullscreen */
    FOnToggleFullscreen ToggleFullscreenDelegate;
};

 

GamePlay框架

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API FGameModeEvents
{
public:

    /**
     * GameMode initialization has occurred
     * - Called at the end of AGameModeBase::InitGame 
     * - AGameSession has also been initialized
     * - Possible some child level initialization hasn't finished
     *
     * @param GameMode the game mode actor that has been initialized
     */
    DECLARE_EVENT_OneParam(AGameModeBase, FGameModeInitializedEvent, AGameModeBase* /*GameMode*/);

    /**
     * Client pre login event, triggered when a client first contacts a server
     *
     * @param GameMode the game mode actor that has been initialized
     * @param NewPlayer the unique id of the player attempting to join
     * @param ErrorMessage current state of any error messages, setting this value non empty will reject the player
     */
    DECLARE_EVENT_ThreeParams(AGameModeBase, FGameModePreLoginEvent, AGameModeBase* /*GameMode*/, const FUniqueNetIdRepl& /*NewPlayer*/, FString& /*ErrorMessage*/);

    /** 
     * Post login event, triggered when a player joins the game as well as after non-seamless ServerTravel
     *
     * This is called after the player has finished initialization
     */
    DECLARE_EVENT_TwoParams(AGameModeBase, FGameModePostLoginEvent, AGameModeBase* /*GameMode*/, APlayerController* /*NewPlayer*/);

    /**
     * Logout event, triggered when a player leaves the game as well as during non-seamless ServerTravel
     *
     * Note that this is called before performing any cleanup of the specified AController
     */
    DECLARE_EVENT_TwoParams(AGameModeBase, FGameModeLogoutEvent, AGameModeBase* /*GameMode*/, AController* /*Exiting*/);

    /**
     * Match state has changed via SetMatchState()
     *
     * @param MatchState new match state
     */
    DECLARE_EVENT_OneParam(AGameModeBase, FGameModeMatchStateSetEvent, FName /*MatchState*/);

public: 
    
    static FGameModeInitializedEvent& OnGameModeInitializedEvent() { return GameModeInitializedEvent; } 
    static FGameModePreLoginEvent& OnGameModePreLoginEvent() { return GameModePreLoginEvent; }
    static FGameModePostLoginEvent& OnGameModePostLoginEvent() { return GameModePostLoginEvent; }
    static FGameModeLogoutEvent& OnGameModeLogoutEvent() { return GameModeLogoutEvent; }
    static FGameModeMatchStateSetEvent& OnGameModeMatchStateSetEvent() { return GameModeMatchStateSetEvent; }

    static FGameModeInitializedEvent GameModeInitializedEvent;
    static FGameModePreLoginEvent GameModePreLoginEvent;
    static FGameModePostLoginEvent GameModePostLoginEvent;
    static FGameModeLogoutEvent GameModeLogoutEvent;
    static FGameModeMatchStateSetEvent GameModeMatchStateSetEvent;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API AActor : public UObject 
{
    //~==============================================================================================
    // Delegates
    
    /** Called when the actor is damaged in any way. */
    UPROPERTY(BlueprintAssignable, Category="Game|Damage")
    FTakeAnyDamageSignature OnTakeAnyDamage;

    /** Called when the actor is damaged by point damage. */
    UPROPERTY(BlueprintAssignable, Category="Game|Damage")
    FTakePointDamageSignature OnTakePointDamage;

    /** Called when the actor is damaged by radial damage. */
    UPROPERTY(BlueprintAssignable, Category="Game|Damage")
    FTakeRadialDamageSignature OnTakeRadialDamage;
    
    /** 
     * Called when another actor begins to overlap this actor, for example a player walking into a trigger.
     * For events when objects have a blocking collision, for example a player hitting a wall, see 'Hit' events.
     * @note Components on both this and the other Actor must have bGenerateOverlapEvents set to true to generate overlap events.
     */
    UPROPERTY(BlueprintAssignable, Category="Collision")
    FActorBeginOverlapSignature OnActorBeginOverlap;

    /** 
     * Called when another actor stops overlapping this actor. 
     * @note Components on both this and the other Actor must have bGenerateOverlapEvents set to true to generate overlap events.
     */
    UPROPERTY(BlueprintAssignable, Category="Collision")
    FActorEndOverlapSignature OnActorEndOverlap;

    /** Called when the mouse cursor is moved over this actor if mouse over events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input")
    FActorBeginCursorOverSignature OnBeginCursorOver;

    /** Called when the mouse cursor is moved off this actor if mouse over events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input")
    FActorEndCursorOverSignature OnEndCursorOver;

    /** Called when the left mouse button is clicked while the mouse is over this actor and click events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input")
    FActorOnClickedSignature OnClicked;

    /** Called when the left mouse button is released while the mouse is over this actor and click events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input")
    FActorOnReleasedSignature OnReleased;

    /** Called when a touch input is received over this actor when touch events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Touch Input")
    FActorOnInputTouchBeginSignature OnInputTouchBegin;
        
    /** Called when a touch input is received over this component when touch events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Touch Input")
    FActorOnInputTouchEndSignature OnInputTouchEnd;

    /** Called when a finger is moved over this actor when touch over events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Touch Input")
    FActorBeginTouchOverSignature OnInputTouchEnter;

    /** Called when a finger is moved off this actor when touch over events are enabled in the player controller. */
    UPROPERTY(BlueprintAssignable, Category="Input|Touch Input")
    FActorEndTouchOverSignature OnInputTouchLeave;

    /** 
     *    Called when this Actor hits (or is hit by) something solid. This could happen due to things like Character movement, using Set Location with 'sweep' enabled, or physics simulation.
     *    For events when objects overlap (e.g. walking into a trigger) see the 'Overlap' event.
     *    @note For collisions during physics simulation to generate hit events, 'Simulation Generates Hit Events' must be enabled.
     */
    UPROPERTY(BlueprintAssignable, Category="Collision")
    FActorHitSignature OnActorHit;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API UActorComponent : public UObject, public IInterface_AssetUserData
{
    /** Create component physics state global delegate.*/
    static FActorComponentGlobalCreatePhysicsSignature GlobalCreatePhysicsDelegate;
    /** Destroy component physics state global delegate.*/
    static FActorComponentGlobalDestroyPhysicsSignature GlobalDestroyPhysicsDelegate;
    
    /** Called when the component has been activated, with parameter indicating if it was from a reset */
    UPROPERTY(BlueprintAssignable, Category = "Components|Activation")
    FActorComponentActivatedSignature OnComponentActivated;

    /** Called when the component has been deactivated */
    UPROPERTY(BlueprintAssignable, Category = "Components|Activation")
    FActorComponentDeactivateSignature OnComponentDeactivated;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DECLARE_MULTICAST_DELEGATE_OneParam(FPawnChangedSignature, APawn* /*NewPawn*/);

class ENGINE_API ULocalPlayer : public UPlayer
{
    DECLARE_EVENT_TwoParams(ULocalPlayer, FOnControllerIdChanged, int32 /*NewId*/, int32 /*OldId*/);
    FOnControllerIdChanged& OnControllerIdChanged() const { return OnControllerIdChangedEvent; }
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API AController : public AActor, public INavAgentInterface 
{
    FInstigatedAnyDamageSignature OnInstigatedAnyDamage;

    FPawnChangedSignature& GetOnNewPawnNotifier() { return OnNewPawn; }
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API ACharacter : public APawn 
{
    /** Multicast delegate for MovementMode changing. */
    UPROPERTY(BlueprintAssignable, Category=Character)
    FMovementModeChangedSignature MovementModeChangedDelegate;
    
    /**
     * Event triggered at the end of a CharacterMovementComponent movement update.
     * This is the preferred event to use rather than the Tick event when performing custom updates to CharacterMovement properties based on the current state.
     * This is mainly due to the nature of network updates, where client corrections in position from the server can cause multiple iterations of a movement update,
     * which allows this event to update as well, while a Tick event would not.
     *
     * @param    DeltaSeconds        Delta time in seconds for this update
     * @param    InitialLocation        Location at the start of the update. May be different than the current location if movement occurred.
     * @param    InitialVelocity        Velocity at the start of the update. May be different than the current velocity.
     */
    UPROPERTY(BlueprintAssignable, Category=Character)
    FCharacterMovementUpdatedSignature OnCharacterMovementUpdated;
    
    /** Broadcast when Character's jump reaches its apex. Needs CharacterMovement->bNotifyApex = true */
    UPROPERTY(BlueprintAssignable, Category=Character)
    FCharacterReachedApexSignature OnReachedJumpApex;
    
    /**
     * Called upon landing when falling, to perform actions based on the Hit result.
     * Note that movement mode is still "Falling" during this event. Current Velocity value is the velocity at the time of landing.
     * Consider OnMovementModeChanged() as well, as that can be used once the movement mode changes to the new mode (most likely Walking).
     *
     * @param Hit Result describing the landing that resulted in a valid landing spot.
     * @see OnMovementModeChanged()
     */
    FLandedSignature LandedDelegate;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API AHUD : public AActor 
{
    // Callback allowing external systems to register to show debug info
    static FOnShowDebugInfo OnShowDebugInfo;

    // Called from ::PostRender. For less player/actor centered debugging
    static FOnHUDPostRender OnHUDPostRender;
};

 

功能库

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DECLARE_DELEGATE_ThreeParams(FLoadPackageAsyncDelegate, const FName& /*PackageName*/, UPackage* /*LoadedPackage*/, EAsyncLoadingResult::Type /*Result*/)

/* Engine\Source\Runtime\CoreUObject\Public\UObject\UObjectGlobals.h **/

/**
 * Delegate called on completion of async package loading
 * @param    PackageName            Package name we were trying to load
 * @param    LoadedPackage        Loaded package if successful, nullptr otherwise    
 * @param    Result        Result of async loading.
 */
DECLARE_DELEGATE_ThreeParams(FLoadPackageAsyncDelegate, const FName& /*PackageName*/, UPackage* /*LoadedPackage*/, EAsyncLoadingResult::Type /*Result*/)

/**
 * Asynchronously load a package and all contained objects that match context flags. Non-blocking.
 * This version is useful when loading multiple copies of the same package.
 *
 * @param    InName                    Name of package to load
 * @param    InGuid                    GUID of the package to load, or nullptr for "don't care"
 * @param    InPackageToLoadFrom        If non-null, this is another package name. We load from this package name, into a (probably new) package named InName
 * @param    InCompletionDelegate    Delegate to be invoked when the packages has finished streaming
 * @param    InPackageFlags            Package flags used to construct loaded package in memory
 * @param    InPIEInstanceID            Play in Editor instance ID
 * @param    InPackagePriority        Loading priority
 * @return Unique ID associated with this load request (the same package can be associated with multiple IDs).
 */
COREUOBJECT_API int32 LoadPackageAsync(const FString& InName, const FGuid* InGuid = nullptr, const TCHAR* InPackageToLoadFrom = nullptr, FLoadPackageAsyncDelegate InCompletionDelegate = FLoadPackageAsyncDelegate(), EPackageFlags InPackageFlags = PKG_None, int32 InPIEInstanceID = INDEX_NONE, TAsyncLoadPriority InPackagePriority = 0);

/**
 * Asynchronously load a package and all contained objects that match context flags. Non-blocking.
 *
 * @param    InName                    Name of package to load
 * @param    InCompletionDelegate    Delegate to be invoked when the packages has finished streaming
 * @param    InPackagePriority        Loading priority
 * @param    InPackageFlags            Package flags used to construct loaded package in memory
 * @param    InPIEInstanceID            Play in Editor instance ID
 * @return Unique ID associated with this load request (the same package can be associated with multiple IDs).
 *
 * @see FStreamableManager for an engine-level wrapper
 */
COREUOBJECT_API int32 LoadPackageAsync(const FString& InName, FLoadPackageAsyncDelegate InCompletionDelegate, TAsyncLoadPriority InPackagePriority = 0, EPackageFlags InPackageFlags = PKG_None, int32 InPIEInstanceID = INDEX_NONE);

/**
* Cancels all async package loading requests.
*/
COREUOBJECT_API void CancelAsyncLoading();

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class UObjectLibrary : public UObject
{
    DECLARE_EVENT_OneParam(UObjectLibrary, FObjectLibraryOnObjectAdded, UObject* /*NewObject*/);
    FObjectLibraryOnObjectAdded& OnObjectAdded() { return OnObjectAddedEvent; }

    DECLARE_EVENT_OneParam(UObjectLibrary, FObjectLibraryOnObjectRemoved, UObject* /*ObjectToRemove*/);
    FObjectLibraryOnObjectRemoved& OnObjectRemoved() { return OnObjectRemovedEvent; }
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class UMG_API UWidgetBlueprintLibrary : public UBlueprintFunctionLibrary
{
    DECLARE_DYNAMIC_DELEGATE(FOnGameWindowCloseButtonClickedDelegate);

    UFUNCTION(BlueprintCallable, Category = "Widget|Window Title Bar")
    static void SetWindowTitleBarOnCloseClickedDelegate(FOnGameWindowCloseButtonClickedDelegate Delegate);
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ENGINE_API UKismetSystemLibrary : public UBlueprintFunctionLibrary
{
    DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAssetLoaded, class UObject*, Loaded);

    UFUNCTION(BlueprintCallable, meta = (Latent, LatentInfo = "LatentInfo", WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true"), Category = "Utilities")
    static void LoadAsset(UObject* WorldContextObject, TSoftObjectPtr<UObject> Asset, FOnAssetLoaded OnLoaded, FLatentActionInfo LatentInfo);

    DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAssetClassLoaded, TSubclassOf<UObject>, Loaded);

    UFUNCTION(BlueprintCallable, meta = (Latent, LatentInfo = "LatentInfo", WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true"), Category = "Utilities")
    static void LoadAssetClass(UObject* WorldContextObject, TSoftClassPtr<UObject> AssetClass, FOnAssetClassLoaded OnLoaded, FLatentActionInfo LatentInfo);
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Delegate called when a notify was replaced */
DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnNotifyReplaced, UAnimNotify*, OldNotify, UAnimNotify*, NewNotify);

/** Delegate called when a notify state was replaced */
DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnNotifyStateReplaced, UAnimNotifyState*, OldNotifyState, UAnimNotifyState*, NewNotifyState);

/** Blueprint library for altering and analyzing animation / skeletal data */
class ANIMATIONMODIFIERS_API UAnimationBlueprintLibrary : public UBlueprintFunctionLibrary
{
    /** Replaces animation notifies in the specified Animation Sequence */
    UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
    static void ReplaceAnimNotifyStates(UAnimSequenceBase* AnimationSequence, TSubclassOf<UAnimNotifyState> OldNotifyClass, TSubclassOf<UAnimNotifyState> NewNotifyClass, FOnNotifyStateReplaced OnNotifyStateReplaced);

    /** Replaces animation notifies in the specified Animation Sequence */
    UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents")
    static void ReplaceAnimNotifies(UAnimSequenceBase* AnimationSequence, TSubclassOf<UAnimNotify> OldNotifyClass, TSubclassOf<UAnimNotify> NewNotifyClass, FOnNotifyReplaced OnNotifyReplaced);
};

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!