# 事件分发
# 基本概念
# 作用
- 数据传递
- UI和HUD数据更新
- 其他角色状态更新
- 驱动行为
- 网络协议处理
- 拾取金币处理
# 优势
# 模块目标
- 模块之间要尽量解耦合,一个模块不要干预其他模块的具体实现。
- 模块之间要异步,同步会出现长时间等待资源释放,降低效率。
下面是使用事件分发和常规调用的区别:
使用事件分发能:
- 降低模块间耦合,降低沟通成本,提高每个模块工作效率。
- 模块之间异步调用,一个模块不用等待其他模块测试完毕才能使用。修改一个模块不用牵扯其他模块逻辑。
# 观察者模式
观察者模式很像定报纸,只要你向出版社订阅了该报纸,就会收到该报纸。如果取消订阅则收不到报纸。类比在游戏中:
# 定义
观察者模式定义了对象之间的一对多关系,当一个对象改变状态时,它的所有观察者都会收到通知并自动更新。
# 实现
主要类图有:
# CPP实现
添加事件接口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添加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
# 蓝图实例
创建一个父类为Object蓝图,并创建数据:
在主动触发的地方发送事件:
在接收的对象接受事件: