1.分析游戏中的Buff系统
2.Buff系统的类结构
3.游戏中存在很多种buff, 是否需要创建不同的buff实体
1.分析游戏中的Buff系统
a.Buff系统的类结构b.游戏中存在很多种buff, 是否需要创建不同的buff实体
2.Buff系统的类结构
将Buff分为三个部分: 数据, 行为, 表现a.Buff数据(BuffData): 定义Buff的静态属性, 如BuffID、持续时间、效果类型、效果值等; 这些数据可以从配置表读取b.Buff实例(BuffInstance): 每个Buff在角色身上的一个实例, 它包含动态数据, 如剩余时间、层数等, 并持有对BuffData的引用c.Buff行为(BuffBehavior): 负责Buff的效果逻辑, 如应用效果、移除效果、定时更新等; 这部分可以放在BuffInstance中也可以分离出来d.Buff表现(BuffView): 负责Buff的视觉和听觉表现, 如特效、音效等; 这部分应该与行为分离, 通过监听Buff的状态变化来触发表现
public class BuffEvent
{public static event Action<Buff, GameObject> OnBuffApply;public static event Action<Buff, GameObject> OnBuffRefresh; public static event Action<Buff, GameObject> OnBuffRemove;public static event Action<Buff, GameObject> OnBuffExpire;public static void TriggerApply(Buff buff, GameObject target) => OnBuffApply?.Invoke(buff, target);
}
public abstract class Buff
{public BuffData Data { get; protected set; }public virtual void Apply(GameObject target){BuffEvent.TriggerApply(this, target);}public virtual void Remove(GameObject target){BuffEvent.TriggerRemove(this, target);}
}
public class BuffVisualController : MonoBehaviour
{private Dictionary<Buff, GameObject> activeVisuals = new Dictionary<Buff, GameObject>();private void OnEnable(){BuffEvent.OnBuffApply += OnBuffApplied;BuffEvent.OnBuffRemove += OnBuffRemoved;BuffEvent.OnBuffRefresh += OnBuffRefreshed;}private void OnDisable(){BuffEvent.OnBuffApply -= OnBuffApplied;BuffEvent.OnBuffRemove -= OnBuffRemoved;BuffEvent.OnBuffRefresh -= OnBuffRefreshed;}private void OnBuffApplied(Buff buff, GameObject target){PlayOneShotEffect(buff.Data.applyEffect, target.transform);if(buff.Data.loopEffect != null){var effect = Instantiate(buff.Data.loopEffect, target.transform);activeVisuals[buff] = effect;}UIManager.Instance.ShowBuffIcon(buff);}private void OnBuffRemoved(Buff buff, GameObject target){PlayOneShotEffect(buff.Data.removeEffect, target.transform);if(activeVisuals.TryGetValue(buff, out var effect)){Destroy(effect);activeVisuals.Remove(buff);}UIManager.Instance.HideBuffIcon(buff);}private void OnBuffRefreshed(Buff buff, GameObject target){PlayOneShotEffect(buff.Data.refreshEffect, target.transform);}
}
3.游戏中存在很多种buff, 是否需要创建不同的buff实体
a.继承体系: 创建一个抽象的Buff基类, 然后为每种不同类型的Buff创建子类; 这种方式直观, 但当Buff行为复杂且组合多变时, 会导致类层次过深或子类数量过多b.组件化(策略模式): 将Buff的行为拆分成多个组件(例如:效果应用、持续时间管理、叠加规则等), 然后通过组合这些组件来构建不同的Buff; 这种方式更灵活, 易于扩展
将Buff的行为拆分为多个可组合的部分a.效果(IEffect): 定义Buff的具体效果, 如伤害、修改属性等b.持续时间(IDuration): 管理Buff的持续时间c.叠加规则(IStacking): 定义Buff如何叠加
public interface IEffect
{void OnApply(GameObject target);void OnUpdate(GameObject target, float deltaTime);void OnRemove(GameObject target);
}public interface IDuration
{float Duration { get; set; }bool IsExpired { get; }void Update(float deltaTime);
}public interface IStacking
{int Stacks { get; set; }void Stack(Buff buff);
}public class Buff
{public GameObject Target { get; private set; }public IEffect Effect { get; private set; }public IDuration Duration { get; private set; }public IStacking Stacking { get; private set; }public Buff(IEffect effect, IDuration duration, IStacking stacking){Effect = effect;Duration = duration;Stacking = stacking;}public void Apply(GameObject target){Target = target;Effect.OnApply(target);}public void Update(float deltaTime){Duration.Update(deltaTime);Effect.OnUpdate(Target, deltaTime);}public void Remove(){Effect.OnRemove(Target);}public void Stack(Buff other){Stacking.Stack(other);}
}
public class DamageOverTimeEffect : IEffect
{private float tickInterval;private float timeSinceLastTick;private float damagePerTick;public DamageOverTimeEffect(float tickInterval, float damagePerTick){this.tickInterval = tickInterval;this.damagePerTick = damagePerTick;timeSinceLastTick = 0f;}public void OnApply(GameObject target) { }public void OnUpdate(GameObject target, float deltaTime){timeSinceLastTick += deltaTime;if (timeSinceLastTick >= tickInterval){Health health = target.GetComponent<Health>();if (health != null){health.TakeDamage(damagePerTick);}timeSinceLastTick = 0f;}}public void OnRemove(GameObject target) { }
}
public class FixedDuration : IDuration
{public float Duration { get; set; }public bool IsExpired => Duration <= 0f;public FixedDuration(float duration){Duration = duration;}public void Update(float deltaTime){Duration -= deltaTime;}
}
public class SimpleStacking : IStacking
{public int Stacks { get; set; } = 1;public void Stack(Buff other){Stacks++;if (other.Duration is FixedDuration fixedDuration){}}
}