BuffHandler可以是用于处理角色身上buff的Mono类,任何具备跟Buff交互的角色,都要携带这个BuffHandler脚本。如果你的Buff有额外的处理机制,比如互斥Buff(如:免疫负面效果的霸体),需要在AddBuff方法中额外处理。当然 也可以不作为mono转为BaseFightObj的一个引用的实例,在BaseFightObj这一类中的生命周期进行调用
csharp
/// <summary>
/// Buff处理器的接口
/// </summary>
public interface BuffSystem_IBuffHandler
{
/// <summary>
/// 添加Buff
/// </summary>
/// <param name="buffId">施加Buff的ID</param>
/// <param name="caster">施加Buff者</param>
public void AddBuff(int buffId, GameObject caster);
/// <summary>
/// 移除Buff
/// </summary>
/// <param name="buffId">要移除的Buff id</param>
/// <param name="removeAll">如果对象同时存在多个同id的buff,是否将所有一并移除</param>
public void RemoveBuff(int buffId, bool removeAll = true);
/// <summary>
/// 移除Buff(不执行OnBuffRemove)
/// </summary>
/// <param name="buffId">要移除的Buff id</param>
/// <param name="removeAll">如果对象同时存在多个同id的buff,是否将所有一并移除</param>
public void InterruptBuff(int buffId, bool interuptAll = true);
/// <summary>
/// 注册事件:添加Buff时
/// </summary>
/// <param name="act">注册的行为</param>
public void RegisterOnAddBuff(Action act);
/// <summary>
/// 删除事件:添加Buff时
/// </summary>
/// <param name="act">注册的行为</param>
public void RemoveOnAddBuff(Action act);
/// <summary>
/// 注册事件:删除Buff时
/// </summary>
/// <param name="act">注册的行为</param>
public void RegisterOnRemoveBuff(Action act);
/// <summary>
/// 删除事件:删除Buff时
/// </summary>
/// <param name="act">注册的行为</param>
public void RemoveOnRemoveBuff(Action act);
}
接口实现如上所示,可以看到实现了一些 "trigger" 可以在特定需求下减轻一些主线程的压力。
依照接口,我们可以实现具体的BuffHandler类
1.AddBuff 方法如下 可以看到 对上文的 重复添加同一种Buff时的行为 做了处理。这是按照策划的需求给出的,不必要求在初次编写时考虑所有情况 便于扩展即可
AddBuff的多种情况
csharp
public enum BuffMutilAddType
{
resetTime, //重置Buff时间
multipleLayer, //增加Buff层数
multipleLayerAndResetTime, //增加Buff层数且重置Buff时间
multipleCount //同种Buff同时存在多个,互不影响
}
AddBuff方法的具体实现
csharp
private void AddBuff(IBuff buff, GameObject caster)
{
if (!updated) Update();
Buff bf = (Buff)buff;
if (bf.IsEmpty())
{
Debug.LogError("尝试加入空Buff");
return;
}
//无论是否可以添加都执行初始化和BuffAwake
bf.Initialize(this, caster);
bf.OnBuffAwake();
//确定能添加Buff时
onAddBuff?.Invoke();
//检查是否已有同样的Buff
Buff previous = buffs.Find(p => p.Equals(bf));
//没有则直接添加
if (previous == null)
{
//结算Tag效果
if (bf.BuffTag != BuffTag.none)
{
//首先:如果有已有buff能抵消新buff,则直接抵消
if (buffs.Any(b => BuffManager.GetInstance().TagManager.IsTagCanAddWhenHaveOther(bf.BuffTag, b.BuffTag)))
{
bf.SetEffective(false);
bf.OnBuffDestroy();
return;
}
for (int i = buffs.Count - 1; i >= 0; i--)
{
//之后:如果新buff没有被抵消,则新buff抵消已有的buff
//Debug.Log("Running:" + bf.BuffTag + ":" + buffs[i].BuffTag);
if (BuffManager.GetInstance().TagManager.IsTagRemoveOther(bf.BuffTag, buffs[i].BuffTag))
{
RemoveBuff(buffs[i]);
}
}
}
buffs.Add(bf);
forOnBuffStart += bf.OnBuffStart;
return;
}
//有则根据重复添加的类型处理。
//一个Buff对象的Start不会重复执行
//只有mutilCount类型会同时存在多个同id Buff
switch (previous.MutilAddType)
{
case BuffMutilAddType.resetTime:
previous.ResetTimer();
//forOnBuffStart += previous.OnBuffStart;
break;
case BuffMutilAddType.multipleLayer:
previous.ModifyLayer(1);
//forOnBuffStart += previous.OnBuffStart;
break;
case BuffMutilAddType.multipleLayerAndResetTime:
previous.ResetTimer();
previous.ModifyLayer(1);
//forOnBuffStart += previous.OnBuffStart;
break;
case BuffMutilAddType.multipleCount:
buffs.Add(bf);
forOnBuffStart += bf.OnBuffStart;
break;
default:
break;
}
}
然后是RemoveBuff的两种情况
csharp
/// <summary>
/// 移除一个Buff,移除后执行OnBuffRemove
/// </summary>
/// <param name="buff">要移除的Buff</param>
private void RemoveBuff(IBuff buff)
{
Buff bf = (Buff)buff;
bf.SetEffective(false);
}
/// <summary>
/// 移除一个Buff,移除后不执行OnBuffRemove
/// </summary>
/// <param name="buff">要移除的Buff</param>
private void InteruptBuff(IBuff buff)
{
Buff bf = (Buff)buff;
bf.SetEffective(false);
buffs.Remove(bf);
forOnBuffDestroy += ((Buff)buff).OnBuffDestroy;
}
之所以这么设计是因为 有些负面Buff效果在onRemoveBuff执行 然而 互斥buff或者说实际的净化buff 不希望onRemoveBuff执行,这会导致一些预期之外的后果 可能不便于实现一些需求,所以编写这两种本质上均为RemoveBuff的方法,为了方便理解 命名为InteruptBuff 打断buff
上述的私有方法AddBuff(IBuff buff, GameObject caster),RemoveBuff(IBuff buff),和InteruptBuff(IBuff buff)封装了实际的Buff处理逻辑。这些方法实现了添加、移除和打断Buff的具体细节。
将复杂的逻辑封装在私有方法中,可以更容易地进行维护和修改。任何更改都只需要在私有方法内部进行,而不影响公有接口
csharp
public void AddBuff(int buffId, GameObject caster)
{
var b = BuffManager.GetInstance().GetBuff(buffId);
AddBuff(b, caster);
}
public void RemoveBuff(int buffId, bool removeAll = true)
{
var b = buffs.FirstOrDefault(b => b.ID == buffId);
if (b == null)
{
Debug.Log("尝试从" + this.name + "移除没有添加的Buff。 id:" + buffId);
return;
}
else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll)
{
var bs = buffs.Where(b => b.ID == buffId);
foreach (var bf in bs)
{
RemoveBuff(bf);
}
}
else RemoveBuff(b);
}
public void InterruptBuff(int buffId, bool removeAll = true)
{
var b = buffs.FirstOrDefault(b => b.ID == buffId);
if (b == null)
{
Debug.Log("尝试从" + this.name + "打断没有添加的Buff。 id:" + buffId);
return;
}
else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll)
{
var bs = buffs.Where(b => b.ID == buffId);
foreach (var bf in bs)
{
InteruptBuff(bf);
}
}
else InteruptBuff(b);
}
然后我们用公有方法将内部复杂的逻辑封装起来,外部只需简单调用。例如,外部调用者只需提供Buff ID和施法者(caster),而不需要关心具体的Buff对象和其处理细节。
完整代码如下
csharp
public class BuffHandler : MonoBehaviour, BuffSystem_IBuffHandler
{
private List<Buff> buffs = new List<Buff>();
private Action onAddBuff;
private Action onRemoveBuff;
public List<Buff> GetBuffs => new List<Buff>(buffs);
public void RegisterOnAddBuff(Action act) { onAddBuff += act; }
public void RemoveOnAddBuff(Action act) { onRemoveBuff -= act; }
public void RegisterOnRemoveBuff(Action act) { onRemoveBuff += act; }
public void RemoveOnRemoveBuff(Action act) { onRemoveBuff -= act; }
#region 私有方法
private void AddBuff(IBuff buff, GameObject caster)
{
if (!updated) Update();
Buff bf = (Buff)buff;
if (bf.IsEmpty())
{
Debug.LogError("尝试加入空Buff");
return;
}
//无论是否可以添加都执行初始化和BuffAwake
bf.Initialize(this, caster);
bf.OnBuffAwake();
//确定能添加Buff时
onAddBuff?.Invoke();
//检查是否已有同样的Buff
Buff previous = buffs.Find(p => p.Equals(bf));
//没有则直接添加
if (previous == null)
{
//结算Tag效果
if (bf.BuffTag != BuffTag.none)
{
//首先:如果有已有buff能抵消新buff,则直接抵消
if (buffs.Any(b => BuffManager.GetInstance().TagManager.IsTagCanAddWhenHaveOther(bf.BuffTag, b.BuffTag)))
{
bf.SetEffective(false);
bf.OnBuffDestroy();
return;
}
for (int i = buffs.Count - 1; i >= 0; i--)
{
//之后:如果新buff没有被抵消,则新buff抵消已有的buff
//Debug.Log("Running:" + bf.BuffTag + ":" + buffs[i].BuffTag);
if (BuffManager.GetInstance().TagManager.IsTagRemoveOther(bf.BuffTag, buffs[i].BuffTag))
{
RemoveBuff(buffs[i]);
}
}
}
buffs.Add(bf);
forOnBuffStart += bf.OnBuffStart;
return;
}
//有则根据重复添加的类型处理。
//一个Buff对象的Start不会重复执行
//只有mutilCount类型会同时存在多个同id Buff
switch (previous.MutilAddType)
{
case BuffMutilAddType.resetTime:
previous.ResetTimer();
//forOnBuffStart += previous.OnBuffStart;
break;
case BuffMutilAddType.multipleLayer:
previous.ModifyLayer(1);
//forOnBuffStart += previous.OnBuffStart;
break;
case BuffMutilAddType.multipleLayerAndResetTime:
previous.ResetTimer();
previous.ModifyLayer(1);
//forOnBuffStart += previous.OnBuffStart;
break;
case BuffMutilAddType.multipleCount:
buffs.Add(bf);
forOnBuffStart += bf.OnBuffStart;
break;
default:
break;
}
}
/// <summary>
/// 移除一个Buff,移除后执行OnBuffRemove
/// </summary>
/// <param name="buff">要移除的Buff</param>
private void RemoveBuff(IBuff buff)
{
Buff bf = (Buff)buff;
bf.SetEffective(false);
}
/// <summary>
/// 移除一个Buff,移除后不执行OnBuffRemove
/// </summary>
/// <param name="buff">要移除的Buff</param>
private void InteruptBuff(IBuff buff)
{
Buff bf = (Buff)buff;
bf.SetEffective(false);
buffs.Remove(bf);
forOnBuffDestroy += ((Buff)buff).OnBuffDestroy;
}
#endregion
public void AddBuff(int buffId, GameObject caster)
{
var b = BuffManager.GetInstance().GetBuff(buffId);
AddBuff(b, caster);
}
public void RemoveBuff(int buffId, bool removeAll = true)
{
var b = buffs.FirstOrDefault(b => b.ID == buffId);
if (b == null)
{
Debug.Log("尝试从" + this.name + "移除没有添加的Buff。 id:" + buffId);
return;
}
else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll)
{
var bs = buffs.Where(b => b.ID == buffId);
foreach (var bf in bs)
{
RemoveBuff(bf);
}
}
else RemoveBuff(b);
}
public void InterruptBuff(int buffId, bool removeAll = true)
{
var b = buffs.FirstOrDefault(b => b.ID == buffId);
if (b == null)
{
Debug.Log("尝试从" + this.name + "打断没有添加的Buff。 id:" + buffId);
return;
}
else if (b.MutilAddType == BuffMutilAddType.multipleCount && removeAll)
{
var bs = buffs.Where(b => b.ID == buffId);
foreach (var bf in bs)
{
InteruptBuff(bf);
}
}
else InteruptBuff(b);
}
private bool updated = false;
private Action forOnBuffDestroy; //用于在下一帧执行onBuffDestory
private Action forOnBuffStart;
private void Update()
{
if (updated) return;
updated = true;
forOnBuffDestroy?.Invoke();
forOnBuffStart?.Invoke();
forOnBuffDestroy = null;
forOnBuffStart = null;
}
private void LateUpdate()
{
updated = false;
Buff bf;
bool buffRemoved = false;
for (int i = buffs.Count - 1; i >= 0; i--)
{
bf = buffs[i];
//Debug.Log(bf);
bf.OnBuffUpdate();
if (!bf.IsEffective)
{
bf.OnBuffRemove();
buffRemoved = true;
buffs.Remove(bf);
forOnBuffDestroy += bf.OnBuffDestroy;
}
}
if (buffRemoved) onRemoveBuff?.Invoke();
}
}
}
Update 每帧更新Buff状态,执行所有记录的销毁和开始方法。
LateUpdate检查并更新每个Buff的状态,如果Buff无效,则移除并记录其销毁方法。
BuffHandler类通过管理游戏对象上的所有Buff,实现了Buff的添加、移除、打断和更新等功能。其核心逻辑包括Buff的初始化、处理相同Buff的多种添加类型、管理Buff的生命周期以及调用相关回调方法。