BuffSystem的简单实现
设计
首先我们需要一个 BuffManager
,管理所有的 BuffComponent
;
首先,对于一个 BuffSystem
,我们需要有一个挂在各个 Actor
上的 BuffComponent
,我们通过这个 BuffComponent
管理该 Actor
自身的 Buff
,对它们做一些 Add
/ Remove
/ Sync
等处理;这个 BuffComponent
会同步信息到每一个客户端上,用于访问其 Buff
信息;
同时,需要有一个 BuffManager
管理所有的 BuffComponent
,从 BuffManager
发起 Commit
/ Query
/ Remove
的调用,同时记录下 BuffSetting
。
最后需要一个 BuffBase
作为 Buff
的基类;

BuffManager

-
Commit
:判断 BuffSettings
里是否有对应 BuffID
的 Buff
,若存在则创建该实例;
判断一下 BuffComponent
里是否原本已经有相同 BuffID
的 Buff
,若存在,并且该 Buff
需要 Merge
的话,执行 OldBuff
的 Merge
,并将新创建的 Buff
给 Remove
一下;
否则直接执行 BuffComponent
的 AddBuff
。
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
| UGameplayBuffBase* UGameplayBuffManager::CommitBuff(UGameplayBuffComponent* Target, int BuffID) { if (Target == nullptr) { return nullptr; }
UGameplayBuffBase* Buff = CreateBuff(Target, BuffID); if (Buff == nullptr) { return nullptr; }
auto SpecBuffGroup = Target->GetBuffGroupByBuffID(BuffID); if (SpecBuffGroup.Num() && BuffSettings[BuffID].bNeedToMerge == true) { UGameplayBuffBase* OldBuff = SpecBuffGroup[0]; OldBuff->Merge(Buff); Buff->Remove(); return OldBuff; } else { Target->AddBuff(Buff); return Buff; } }
UGameplayBuffBase* UGameplayBuffManager::CreateBuff(UGameplayBuffComponent* Target, int BuffID) { if (!BuffSettings.Contains(BuffID) || !IsValid(BuffSettings[BuffID].BuffAsset)) { return nullptr; }
UGameplayBuffBase* BuffInst = NewObject<UGameplayBuffBase>( Target, BuffSettings[BuffID].BuffAsset ); if (BuffInst == nullptr) { return nullptr; }
BuffInst->Create(Target, BuffID);
return BuffInst; }
|
Query
:判断BuffComponent
上是否有对应ID的Buff
,返回对应 Handler
;
1 2 3 4 5 6 7 8 9 10 11
| TArray<UGameplayBuffBase*> UGameplayBuffManager::QueryBuff(UGameplayBuffComponent* Target, int BuffID) { if (Target == nullptr) { return TArray<UGameplayBuffBase*>(); }
auto SpecBuffGroup = Target->GetBuffGroupByBuffID(BuffID); return SpecBuffGroup; }
|
Remove
:通过 BuffID
或者 Handler
Remove掉 BuffComponent
上存在的对应 Buff
,执行 RemoveBuff
。
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
| void UGameplayBuffManager::RemoveBuff(UGameplayBuffComponent* Target, int BuffID) { if (Target == nullptr) { return; }
auto SpecBuffGroup = Target->GetBuffGroupByBuffID(BuffID); if (!SpecBuffGroup.Num()) { return; }
for (int Index = SpecBuffGroup.Num() - 1; Index >= 0; Index--) { Target->RemoveBuff(SpecBuffGroup[Index]); } }
void UGameplayBuffManager::RemoveBuff(UGameplayBuffComponent* Target, UGameplayBuffBase* Buff) { if (Target == nullptr) { return; } Target->RemoveBuff(Buff); }
|
Tick
:遍历BuffComponent
,遍历其中的 BuffGroup
;对每一个Buff
执行 Tick
,并且检查是否需要 Stop
。同时,Tick
一般只在服务器运行。
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
| void UGameplayBuffManager::Tick() { if (IsClient(this)) return;
for (auto Target : BuffComponentArray) { if (Target == nullptr) continue;
const auto& BuffGroup = Target->GetBuffGroup();
for (auto Buff : BuffGroup) { if (Buff == nullptr) continue; if (!Buff->CheckNeedToStop()) { Buff->Tick(DeltaTime); } }
for (int Index = BuffGroup.Num() - 1; Index >= 0; Index--) { auto& Buff = BuffGroup[Index]; if (Buff->CheckNeedToStop()) { Target->RemoveBuff(Buff); } } } }
|
BuffComponent
AddBuff
:将 Buff
添加到 BuffGroup
/ BuffIDArray
,通过 BuffIDArray
做客户端的同步(仅同步 BuffID
到客户端)
RemoveBuff
:移除 Buff
,并执行该 Buff
的 Remove
方法,同步对应信息;
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
| FORCEINLINE const TArray <USGGameplayBuffBase*>& GetBuffGroup() { return BuffGroup; } FORCEINLINE const TArray <int>& GetBuffIDArray() { return BuffIDArray; }
void UGameplayBuffComponent::AddBuff(UGameplayBuffBase* InBuff) { BuffGroup.Add( InBuff ); BuffIDArray().Add( InBuff->GetBuffID() ); MARK_PROPERTY_DIRTY(this, BuffIDArray);
if (IsStandaloneOrDS(this)) { OnRep_BuffIDArray(); } }
void UGameplayBuffComponent::RemoveBuff(UGameplayBuffBase* InBuff) { if (InBuff == nullptr) return; for (int Index = BuffGroup.Num() - 1; Index >= 0; Index--) { if (BuffGroup[Index] == InBuff) { BuffGroup[Index]->Remove(); BuffGroup.RemoveAt( Index ); BuffIDArray.RemoveAt( Index ); } } MARK_PROPERTY_DIRTY(this, BuffIDArray); if (IsStandaloneOrDS(this)) { OnRep_BuffIDArray(); } }
void UGameplayBuffComponent::OnRep_BuffIDArray() { OnGameplayBuffIDArrayChanged.Broadcast( BuffIDArray ); }
|
BuffBase
Create
:执行 OnCreate
,保存 BuffID
、Owner
信息;
Remove
:执行 OnRemove
,并且清空信息;
Merge
:执行 OnMerge
;
Tick
:执行 OnTick
;
每个 Buff
的生命周期由 BuffComponent
来管理。
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
| void UGameplayBuffBase::Create(UGameplayBuffComponent* InOwner, int InBuffID) { if (InOwner == nullptr) return; Owner = InOwner; BuffID = InBuffID; OnCreate(); }
void UGameplayBuffBase::OnCreate() { }
void UGameplayBuffBase::Remove() { OnRemove();
Owner = nullptr; BuffID = 0; }
void UGameplayBuffBase::OnRemove() { }
void UGameplayBuffBase::Merge(UGameplayBuffBase* InBuff) { OnMerge(InBuff); }
void UGameplayBuffBase::OnMerge(UGameplayBuffBase* InBuff) { }
void UGameplayBuffBase::Tick(float DeltaTime) { OnTick(); }
void UGameplayBuffBase::OnTick() { }
|