# 事件分发

# 基本概念

# 作用

  1. 数据传递
    1. UI和HUD数据更新
    2. 其他角色状态更新
  2. 驱动行为
    1. 网络协议处理
    2. 拾取金币处理

# 优势

# 模块目标

  1. 模块之间要尽量解耦合,一个模块不要干预其他模块的具体实现。
  2. 模块之间要异步,同步会出现长时间等待资源释放,降低效率。

下面是使用事件分发和常规调用的区别:

EventDispatchCompare

使用事件分发能:

  1. 降低模块间耦合,降低沟通成本,提高每个模块工作效率。
  2. 模块之间异步调用,一个模块不用等待其他模块测试完毕才能使用。修改一个模块不用牵扯其他模块逻辑。

# 观察者模式

观察者模式很像定报纸,只要你向出版社订阅了该报纸,就会收到该报纸。如果取消订阅则收不到报纸。类比在游戏中:

KillMonster

# 定义

观察者模式定义了对象之间的一对多关系,当一个对象改变状态时,它的所有观察者都会收到通知并自动更新。

# 实现

主要类图有:

ObserverDesign

# CPP实现

  1. 添加事件接口EventInterface.h:

    //==============EventInterface.h==============
    #pragma once
    
    #include "CoreMinimal.h"
    #include "UObject/Interface.h"
    #include "EventInterface.generated.h"
    
    // This class does not need to be modified.
    UINTERFACE(MinimalAPI)
    class UEventInterface : public UInterface
    {
        GENERATED_BODY()
    };
    
    /**
     * 
     */
    class LEARNEVENTDISPATCH_API IEventInterface
    {
        GENERATED_BODY()
    
        // Add interface functions to this class. This is the class that will be inherited to implement this interface.
    public:
        UFUNCTION(BlueprintImplementableEvent,Category="EventDistributionUtility")
        void ExecuteFun(UObject* Datas);
    };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
  2. 添加MyEventManager:

    //===============MyEventManager.h===============
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Kismet/BlueprintFunctionLibrary.h"
    #include "Engine.h"
    #include "MyEventManager.generated.h"
    
    /**
     * 
     */
    UCLASS()
    class LEARNEVENTDISPATCH_API UMyEventManager : public UBlueprintFunctionLibrary
    {
        GENERATED_BODY()
    private:
        static TMap<FString, TArray<UObject*>> AllListener;
    public :
        UFUNCTION(BlueprintCallable, Category = "EventDistributionUtility")
        static void AddEventListener(FString EventName, UObject* Listener);
        UFUNCTION(BlueprintCallable, Category = "EventDistributionUtility")
        static void RemoveEventListener(FString EventName, UObject* Listener);
        UFUNCTION(BlueprintCallable, Category = "EventDistributionUtility")
        static FString DispatchEvent(FString EventName,UObject* Datas);
        UFUNCTION(BlueprintCallable, Category = "EventDistributionUtility")
        static UObject* NewAsset(UClass* ClassType);
    };
    
    //===============MyEventManager.cpp================
    #include "MyEventManager.h"
    
    TMap<FString, TArray<UObject*>> UMyEventManager::AllListener;
    
    void UMyEventManager::AddEventListener(FString EventName, UObject* Listener)
    {
        if (EventName == "" || Listener == NULL) {
            return;
        }
        Listener->AddToRoot();
        TArray<UObject*>* arr = UMyEventManager::AllListener.Find(EventName);
        if (arr == NULL || arr->Num() == 0) {
            TArray<UObject*> arr1 = { Listener };
            UMyEventManager::AllListener.Add(EventName, arr1);
        }
        else {
            arr->Add(Listener);
        }
    }
    
    void UMyEventManager::RemoveEventListener(FString EventName, UObject* Listener)
    {
        TArray<UObject*>* arr = UMyEventManager::AllListener.Find(EventName);
        if (arr != NULL || arr->Num()==0) {
            arr->Remove(Listener);
            Listener->RemoveFromRoot();
            Listener = NULL;
        }
    }
    
    FString UMyEventManager::DispatchEvent(FString EventName, UObject* Datas)
    {
        TArray<UObject*>* arr = UMyEventManager::AllListener.Find(EventName);
        if (arr == NULL || arr->Num() == 0) {
            return "'" + EventName + "' No Listener!";
        }
        FString errorInfo = "";
        for (int i = 0; i < arr->Num(); i++) {
            UObject* obj = (*arr)[i];
            UFunction* fun = obj->FindFunction("ExecuteFun");
            if (fun == NULL) {
                errorInfo += "'" + obj->GetName() + "'No ExecuteFun Function\n";
            }
            else {
                obj->ProcessEvent(fun, &Datas);
            }
        }
        return errorInfo;
    }
    
    UObject* UMyEventManager::NewAsset(UClass* ClassType)
    {
        UObject* obj = NewObject<UObject>(GetTransientPackage(), ClassType);
        obj->AddToRoot();
        return obj;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85

# 蓝图实例

  1. 创建一个父类为Object蓝图,并创建数据:

    DataStructure

  2. 在主动触发的地方发送事件:

    TriggerEvent

  3. 在接收的对象接受事件:

    ReceiveEvent1

    ReceiveEvent2