先来看看最终效果
前言
当今大多数游戏都拥有一些形式的Buff系统,利用这种系统可以增强或削弱游戏角色的特定属性。在Unity中,我们可以使用脚本轻松地创建这样的Buff系统。
在本教程中,我们将探索如何实现一种基本的Buff系统,其中包括对游戏中的玩家或敌对角色施加各种不同类型的Buff。我们还将学习如何设置时间限制和叠加限制,以及如何实现Buff效果的应用和移除。
通过本教程,您将学习如何在Unity中创建一个完整的Buff系统,为您的游戏增加全新的深度和策略性。
开始
新增脚本PlayerController,添加玩家血量和攻击力变量,并实时显示
public class PlayerController : MonoBehaviour { [Header("生命值")] public float HP; [Header("攻击力")] public float AD; public TextMeshProUGUI HPText; public TextMeshProUGUI ADText; private void Update() { HPText.text = $"生命值:{HP}"; ADText.text = $"攻击力:{AD}"; } }
效果
绘制BUFF显示界面
状态栏
遮罩
最终效果
BUFF系统
定义BUFF类型枚举
public enum BuffType { /// <summary> /// 正面buff /// </summary> Buff, /// <summary> /// 负面buff /// </summary> Debuff, /// <summary> /// 没有buff /// </summary> None, }
BUFF冲突方式枚举类型
/// <summary> /// 当两个不同单位向同一个单位施加同一个buff时的冲突处理 /// </summary> public enum ConflictResolution { /// <summary> /// 合并为一个buff,叠层(提高等级) /// </summary> combine, /// <summary> /// 独立存在 /// </summary> separate, /// <summary> /// 覆盖,后者覆盖前者 /// </summary> cover, }
新建BuffBase,Buff系统中的基类
public class BuffBase { private GameObject m_Owner; private string m_Provider = ""; private float m_MaxDuration = 3; private float m_TimeScale = 1; private int m_MaxLevel = 1; private BuffType m_BuffType = BuffType.None; private ConflictResolution m_ConflictResolution = ConflictResolution.cover; private bool m_Dispellable = true; private string m_Name = "默认名称"; private string m_Description = "这个Buff没有介绍"; private int m_Demotion = 1; private string m_IconPath = ""; private int m_CurrentLevel = 0; private float m_ResidualDuration = 3; private bool m_Initialized = false; /// <summary> /// 此buff的持有者 /// </summary> public GameObject Owner { get { return m_Owner; } protected set { m_Owner = value; } } /// <summary> /// 此Buff的提供者 /// </summary> public string Provider { get { return m_Provider; } protected set { m_Provider = value; } } /// <summary> /// Buff的初始持续时间 /// </summary> public float MaxDuration { get { return m_MaxDuration; } protected set { m_MaxDuration = Math.Clamp(value, 0, float.MaxValue); } } /// <summary> /// buff的时间流失速度,最小为0,最大为10。 /// </summary> public float TimeScale { get { return m_TimeScale; } set { m_TimeScale = Math.Clamp(value, 0, 10); } } /// <summary> /// buff的最大堆叠层数,最小为1,最大为2147483647 /// </summary> public int MaxLevel { get { return m_MaxLevel; } protected set { m_MaxLevel = Math.Clamp(value, 1, int.MaxValue); } } /// <summary> /// Buff的类型,分为正面、负面、中立三种 /// </summary> public BuffType BuffType { get { return m_BuffType; } protected set { m_BuffType = value; } } /// <summary> /// 当两个不同单位向同一个单位施加同一个buff时的冲突处理 /// 分为三种: /// combine,合并为一个buff,叠层(提高等级) /// separate,独立存在 /// cover, 覆盖,后者覆盖前者 /// </summary> public ConflictResolution ConflictResolution { get { return m_ConflictResolution; } protected set { m_ConflictResolution = value; } } /// <summary> /// 可否被驱散 /// </summary> public bool Dispellable { get { return m_Dispellable; } protected set { m_Dispellable = value; } } /// <summary> /// Buff对外显示的名称 /// </summary> public string Name { get { return m_Name; } protected set { m_Name = value; } } /// <summary> /// Buff的介绍文本 /// </summary> public string Description { get { return m_Description; } protected set { m_Description = value; } } /// <summary> /// 图标资源的路径 /// </summary> public string IconPath { get { return m_IconPath; } protected set { m_IconPath = value; } } /// <summary> /// 每次Buff持续时间结束时降低的等级,一般降低1级或者降低为0级。 /// </summary> public int Demotion { get { return m_Demotion; } protected set { m_Demotion = Math.Clamp(value, 0, MaxLevel); } } /// <summary> /// Buff的当前等级 /// </summary> public int CurrentLevel { get { return m_CurrentLevel; } set { //计算出改变值 int change = Math.Clamp(value, 0, MaxLevel) - m_CurrentLevel; OnLevelChange(change); m_CurrentLevel += change; } } /// <summary> /// Buff的当前剩余时间 /// </summary> public float ResidualDuration { get { return m_ResidualDuration; } set { m_ResidualDuration = Math.Clamp(value, 0, float.MaxValue); } } /// <summary> /// 当Owner获得此buff时触发 /// 由BuffManager在合适的时候调用 /// </summary> public virtual void OnGet() { } /// <summary> /// 当Owner失去此buff时触发 /// 由BuffManager在合适的时候调用 /// </summary> public virtual void OnLost() { } /// <summary> /// Update,由BuffManager每物理帧调用 /// </summary> public virtual void FixedUpdate() { } /// <summary> /// 当等级改变时调用 /// </summary> /// <param name="change">改变了多少级</param> protected virtual void OnLevelChange(int change) { } /// <summary> /// 初始化 /// </summary> /// <param name="owner"></param> /// <param name="provider"></param> /// <exception cref="Exception"></exception> public virtual void Initialize(GameObject owner, string provider) { if (m_Initialized) { throw new Exception("不能对已经初始化的buff再次初始化"); } if (owner == null || provider == null) { throw new Exception("初始化值不能为空"); } Owner = owner; Provider = provider; m_Initialized = true; } }
新建ShowBuff,控制BUFF的显示
public class ShowBuff : MonoBehaviour { [SerializeField, Header("Buff项预制体")] private GameObject m_BuffItemTemplate; [SerializeField, Header("对象池")] private GameObject m_Pool; [SerializeField, Header("Buff项父物体")] private GameObject m_Buffs; [SerializeField, Header("与Buff相关联的游戏对象")] private PlayerController m_Hero; private ObjectPool<UI_BuffItem> m_BuffItemPool;// Buff项对象池 // Buff项对象池的创建函数,用于实例化Buff项 private UI_BuffItem Pool_CreateFunc() { return Instantiate(m_BuffItemTemplate, this.transform).GetComponent<UI_BuffItem>(); } // Buff项对象池的获取时回调,用于激活对象并设置父物体 private void Pool_ActionOnGet(UI_BuffItem UI_BuffItem) { UI_BuffItem.gameObject.SetActive(true); UI_BuffItem.transform.SetParent(m_Buffs.transform); } // Buff项对象池的回收时回调,用于隐藏对象并设置父物体 private void Pool_ActionOnRelease(UI_BuffItem UI_BuffItem) { UI_BuffItem.gameObject.SetActive(false); UI_BuffItem.transform.SetParent(m_Pool.transform); } // Buff项对象池的销毁时回调,用于销毁对象 private void Pool_ActionOnDestroy(UI_BuffItem UI_BuffItem) { Destroy(UI_BuffItem.gameObject); } // Buff监听器,当有新的Buff时调用ShowBuffCore方法 private void BuffListener(BuffBase newBuff) { ShowBuffCore(newBuff); } private void ShowBuffCore(BuffBase buff) { m_BuffItemPool.Get().Initialize(buff, m_BuffItemPool); } private void Awake() { m_BuffItemPool = new ObjectPool<UI_BuffItem>( Pool_CreateFunc, Pool_ActionOnGet, Pool_ActionOnRelease, Pool_ActionOnDestroy, true, 100, 10000 ); // 遍历BuffManager中与m_Hero关联的所有Buff,并调用ShowBuffCore方法显示它们 foreach (BuffBase item in BuffManager.Instance.StartObserving(m_Hero.gameObject, BuffListener)) { ShowBuffCore(item); } } }
挂载脚本并配置参数
新增UI_BuffItem,控制Buff信息UI显示
public class UI_BuffItem : MonoBehaviour { [SerializeField, Header("遮罩层")] private Image m_Mask_M; [SerializeField, Header("等级文本")] private TextMeshProUGUI m_Level; [SerializeField, Header("边框")] private Image m_Frame; [SerializeField, Header("图标")] private Image m_Icon; [Space] [Header("Buff详情")] [SerializeField, Header("详情弹窗")] private GameObject m_BuffInfo; [SerializeField, Header("Buff名称文本")] private TextMeshProUGUI m_BuffName; [SerializeField, Header("Buff描述文本")] private TextMeshProUGUI m_Description; [SerializeField, Header("Buff来源文本")] private TextMeshProUGUI m_Provider; private ObjectPool<UI_BuffItem> m_RecyclePool; private bool m_Initialized = false;// 是否已经初始化 private bool m_NeedNumber = false;// 是否需要显示等级 private bool m_NeedLine = false;// 是否需要显示计时工具 private BuffBase m_TargetBuff; public void OnPointerEnter() { m_BuffInfo.gameObject.SetActive(true); ShowInfo(m_TargetBuff); } // 显示Buff详细信息 public void ShowInfo(BuffBase buff) { m_BuffName.text = buff.Name; m_Description.text = buff.Description; m_Provider.text = "来自:" + buff.Provider; } public void OnPointerExit() { m_BuffInfo.gameObject.SetActive(false); } public void Initialize(BuffBase buff, ObjectPool<UI_BuffItem> recyclePool) { m_Icon.sprite = Resources.Load<Sprite>(buff.IconPath); m_TargetBuff = buff; m_RecyclePool = recyclePool; if (m_TargetBuff.MaxLevel > 1) { m_NeedNumber = true; m_Level.gameObject.SetActive(true); } else { m_NeedNumber = false; m_Level.gameObject.SetActive(false); } if (m_TargetBuff.TimeScale > 0) { m_NeedLine = true; m_Mask_M.gameObject.SetActive(true); } else { m_NeedLine = false; m_Mask_M.gameObject.SetActive(false); } switch (buff.BuffType) { case BuffType.Buff: m_Frame.color = Color.green; break; case BuffType.Debuff: m_Frame.color = Color.red; break; case BuffType.None: m_Frame.color = Color.white; break; default: break; } m_Initialized = true; } private void Update() { if (m_Initialized) { //需要显示计时工具才显示 if (m_NeedLine) { m_Mask_M.fillAmount = 1 - (m_TargetBuff.ResidualDuration / m_TargetBuff.MaxDuration); } //需要显示等级才显示 if (m_NeedNumber) { m_Level.text = m_TargetBuff.CurrentLevel.ToString(); } //如果当前等级等于零说明他已经被废弃了,所以就可以回收了 if (m_TargetBuff.CurrentLevel == 0 ) { m_RecyclePool.Release(this); } } } }
绑定脚本,配置参数并添加鼠标移入移出事件
新增ShowBuff,控制BUFFBuff的显示
public class ShowBuff : MonoBehaviour { [SerializeField, Header("Buff项预制体")] private GameObject m_BuffItemTemplate; [SerializeField, Header("对象池")] private GameObject m_Pool; [SerializeField, Header("Buff项父物体")] private GameObject m_Buffs; [SerializeField, Header("与Buff相关联的游戏对象")] private PlayerController m_Hero; private ObjectPool<UI_BuffItem> m_BuffItemPool;// Buff项对象池 // Buff项对象池的创建函数,用于实例化Buff项 private UI_BuffItem Pool_CreateFunc() { return Instantiate(m_BuffItemTemplate, this.transform).GetComponent<UI_BuffItem>(); } // Buff项对象池的获取时回调,用于激活对象并设置父物体 private void Pool_ActionOnGet(UI_BuffItem UI_BuffItem) { UI_BuffItem.gameObject.SetActive(true); UI_BuffItem.transform.SetParent(m_Buffs.transform); } // Buff项对象池的回收时回调,用于隐藏对象并设置父物体 private void Pool_ActionOnRelease(UI_BuffItem UI_BuffItem) { UI_BuffItem.gameObject.SetActive(false); UI_BuffItem.transform.SetParent(m_Pool.transform); } // Buff项对象池的销毁时回调,用于销毁对象 private void Pool_ActionOnDestroy(UI_BuffItem UI_BuffItem) { Destroy(UI_BuffItem.gameObject); } // Buff监听器,当有新的Buff时调用ShowBuffCore方法 private void BuffListener(BuffBase newBuff) { ShowBuffCore(newBuff); } private void ShowBuffCore(BuffBase buff) { m_BuffItemPool.Get().Initialize(buff, m_BuffItemPool); } private void Awake() { m_BuffItemPool = new ObjectPool<UI_BuffItem>( Pool_CreateFunc, Pool_ActionOnGet, Pool_ActionOnRelease, Pool_ActionOnDestroy, true, 100, 10000 ); // 遍历BuffManager中与m_Hero关联的所有Buff,并调用ShowBuffCore方法显示它们 foreach (BuffBase item in BuffManager.Instance.StartObserving(m_Hero.gameObject, BuffListener)) { ShowBuffCore(item); } } }
挂载脚本,配置参数
新增BuffManager,BUFF管理类
public class BuffManager : MonoBehaviour { /// <summary> /// 固定时间更新的更新频率,此值不宜过高,可以过低(会增加性能消耗)。 /// </summary> public const float FixedDeltaTime = 0.1f; #region 单例 private static BuffManager m_Instance; public static BuffManager Instance { get { if (m_Instance == null) { GameObject l_GameObject = new GameObject("Buff Manager"); m_Instance = l_GameObject.AddComponent<BuffManager>(); DontDestroyOnLoad(l_GameObject); } return m_Instance; } } #endregion /// <summary> /// 存储了所有的buff,key为buff持有者,value为他所持有的所有buff。 /// </summary> private Dictionary<GameObject, List<BuffBase>> m_BuffDictionary = new Dictionary<GameObject, List<BuffBase>>(25); private Dictionary<GameObject, Action<BuffBase>> m_ObserverDicitinary = new Dictionary<GameObject, Action<BuffBase>>(25); #region Public方法 /// <summary> /// 返回要观察的对象现有的buff,并且在对象被添加新buff时通知你 /// (如果现在对象身上没有buff会返回空列表,不会返回null) /// </summary> /// <returns></returns> public List<BuffBase> StartObserving(GameObject target, Action<BuffBase> listener) { List<BuffBase> list; //添加监听 if (!m_ObserverDicitinary.ContainsKey(target)) { m_ObserverDicitinary.Add(target, null); } m_ObserverDicitinary[target] += listener; //查找已有buff if (m_BuffDictionary.ContainsKey(target)) { list = m_BuffDictionary[target]; } else { list = new List<BuffBase>(); } //返回 return list; } /// <summary> /// 停止观察某一对象,请传入与调用开始观察方法时使用的相同参数。 /// </summary> /// <param name="target"></param> /// <param name="listener"></param> /// <exception cref="Exception"></exception> public void StopObsveving(GameObject target, Action<BuffBase> listener) { if (!m_ObserverDicitinary.ContainsKey(target)) { throw new Exception("要停止观察的对象不存在"); } m_ObserverDicitinary[target] -= listener; if (m_ObserverDicitinary[target] == null) { m_ObserverDicitinary.Remove(target); } } /// <summary> /// 在目标身上挂buff /// </summary> /// <typeparam name="T"></typeparam> /// <param name="target"></param> /// <param name="provider"></param> /// <param name="level"></param> public void AddBuff<T>(GameObject target, string provider, int level = 1) where T : BuffBase, new() { //如果我们的字典里没有存储这个key,就进行初始化 if (!m_BuffDictionary.ContainsKey(target)) { m_BuffDictionary.Add(target, new List<BuffBase>(5)); //目标身上自然没有任何buff,直接挂一个新buff即可 AddNewBuff<T>(target, provider, level); return; } //如果目标身上没有任何buff,直接挂一个新buff即可 if (m_BuffDictionary[target].Count == 0) { AddNewBuff<T>(target, provider, level); return; } //遍历看看目标身上有没有已存在的要挂的buff。 List<T> temp01 = new List<T>(); foreach (BuffBase item in m_BuffDictionary[target]) { if (item is T) { temp01.Add(item as T); } } //如果没有直接挂一个新buff就行了 //如果有已存在的要挂的buff,就要进行冲突处理了 if (temp01.Count == 0) { AddNewBuff<T>(target, provider, level); } else { switch (temp01[0].ConflictResolution) { //如果是独立存在,那也直接挂buff case ConflictResolution.separate: bool temp = true; foreach (T item in temp01) { if (item.Provider == provider) { item.CurrentLevel += level; temp = false; continue; } } if (temp) { AddNewBuff<T>(target, provider, level); } break; //如果是合并,则跟已有的buff叠层。 case ConflictResolution.combine: temp01[0].CurrentLevel += level; break; //如果是覆盖,则移除旧buff,然后添加这个buff。 case ConflictResolution.cover: RemoveBuff(target, temp01[0]); AddNewBuff<T>(target, provider, level); break; } } } /// <summary> /// 获得单位身上指定类型的buff的列表 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="Owner"></param> /// <returns></returns> public List<T> FindBuff<T>(GameObject Owner) where T : BuffBase, new() { List<T> result = new List<T>(); if (m_BuffDictionary.ContainsKey(Owner)) { List<BuffBase> buff = m_BuffDictionary[Owner]; foreach (BuffBase item in buff) { if (item is T) { result.Add(item as T); } } } return result; } /// <summary> /// 获得单位身上所有的buff /// 如果单位身上没有任何buff则返回空列表 /// </summary> /// <param name="Owner"></param> /// <returns></returns> public List<BuffBase> FindAllBuff(GameObject Owner) { List<BuffBase> result = new List<BuffBase>(); if (m_BuffDictionary.ContainsKey(Owner)) { result = m_BuffDictionary[Owner]; } return result; } /// <summary> /// 移除单位身上指定的一个buff /// </summary> /// <param name="owner"></param> /// <param name="buff"></param> /// <returns>是否成功,如果失败说明目标不存在</returns> public bool RemoveBuff(GameObject owner, BuffBase buff) { if (!m_BuffDictionary.ContainsKey(owner)) { return false; } bool haveTarget = false; foreach (BuffBase item in m_BuffDictionary[owner]) { if (item == buff) { haveTarget = true; item.CurrentLevel -= item.CurrentLevel; item.OnLost(); m_BuffDictionary[owner].Remove(item); break; } } if (!haveTarget) { return false; } return true; } #endregion #region Private方法 private void AddNewBuff<T>(GameObject target, string provider, int level) where T : BuffBase, new() { T buff = new T(); buff.Initialize(target, provider); m_BuffDictionary[target].Add(buff); buff.ResidualDuration = buff.MaxDuration; buff.CurrentLevel = level; buff.OnGet(); if (m_ObserverDicitinary.ContainsKey(target)) { m_ObserverDicitinary[target]?.Invoke(buff); } } #endregion private WaitForSeconds m_WaitForFixedDeltaTimeSeconds = new WaitForSeconds(FixedDeltaTime); private IEnumerator ExecuteFixedUpdate() { while (true) { yield return m_WaitForFixedDeltaTimeSeconds; //执行所有buff的update; foreach (KeyValuePair<GameObject, List<BuffBase>> item1 in m_BuffDictionary) { foreach (BuffBase item2 in item1.Value) { if (item2.CurrentLevel > 0 && item2.Owner != null) { item2.FixedUpdate(); } } } } } private WaitForSeconds m_WaitFor10Seconds = new WaitForSeconds(10f); private Dictionary<GameObject, List<BuffBase>> m_BuffDictionaryCopy = new Dictionary<GameObject, List<BuffBase>>(25); private IEnumerator ExecuteGrabageCollection() { while (true) { yield return m_WaitFor10Seconds; //复制一份 m_BuffDictionaryCopy.Clear(); foreach (KeyValuePair<GameObject, List<BuffBase>> item in m_BuffDictionary) { m_BuffDictionaryCopy.Add(item.Key, item.Value); } //清理无用对象 foreach (KeyValuePair<GameObject, List<BuffBase>> item in m_BuffDictionaryCopy) { //如果owner被删除,我们这边也跟着删除 if (item.Key == null) { m_BuffDictionary.Remove(item.Key); continue; } //如果一个owner身上没有任何buff,就没必要留着他了 if (item.Value.Count == 0) { m_BuffDictionary.Remove(item.Key); continue; } } } } private void Awake() { StartCoroutine(ExecuteFixedUpdate()); StartCoroutine(ExecuteGrabageCollection()); } private BuffBase m_Transfer_Buff; private void FixedUpdate() { //清理无用对象 foreach (KeyValuePair<GameObject, List<BuffBase>> item in m_BuffDictionary) { //清理无用buff //降低持续时间 for (int i = item.Value.Count - 1; i >= 0; i--) { m_Transfer_Buff = item.Value[i]; //如果等级为0,则移除 if (m_Transfer_Buff.CurrentLevel == 0) { RemoveBuff(item.Key, m_Transfer_Buff); continue; } //如果持续时间为0,则降级, //降级后如果等级为0则移除,否则刷新持续时间 if (m_Transfer_Buff.ResidualDuration == 0) { m_Transfer_Buff.CurrentLevel -= m_Transfer_Buff.Demotion; if (m_Transfer_Buff.CurrentLevel == 0) { RemoveBuff(item.Key, m_Transfer_Buff); continue; } else { m_Transfer_Buff.ResidualDuration = m_Transfer_Buff.MaxDuration; } } //降低持续时间 m_Transfer_Buff.ResidualDuration -= Time.fixedDeltaTime; } } } }
加几个BUFF测试
1. 逐层消失,升级不重置剩余时间的BUFF
public class Buff001 : BuffBase { // Buff每秒钟恢复的生命值 private float m_HealingPerSecond = 20f; // 作用目标,即被添加Buff的角色 private PlayerController playerController; // 初始化Buff的属性和状态 public override void Initialize(GameObject owner, string provider) { base.Initialize(owner, provider); // 获取作用目标的PlayerController组件 playerController = owner.GetComponent<PlayerController>(); // 设置Buff的基本属性 MaxDuration = 15; // 最大持续时间为15秒 TimeScale = 1f; // 时间流失速度为正常值 MaxLevel = 5; // 最大等级为5级 BuffType = BuffType.Buff; // Buff类型为增益效果 ConflictResolution = ConflictResolution.combine; // Buff冲突时采用合并方式 Dispellable = false; // 不可被驱散 Name = "生命值"; // Buff的名称 Description = $"每秒恢复{m_HealingPerSecond}点生命值"; // Buff的描述 Demotion = 1; // 每次Buff持续时间结束时降低的等级 IconPath = "Icon/2003"; // Buff的图标路径 } // 在固定时间间隔内更新Buff的效果 public override void FixedUpdate() { // 每秒钟恢复指定的生命值 playerController.HP += m_HealingPerSecond * BuffManager.FixedDeltaTime; } }
调用测试
public class Test : MonoBehaviour { public PlayerController playerController; void Update() { if (Input.GetKeyDown(KeyCode.Alpha1)) { //作用目标 来源:自己,每次加1层 BuffManager.Instance.AddBuff<Buff001>(playerController.gameObject, "自己", 1); } } }
效果
2. 一次性全部消失,升级重置剩余时间的BUFF
public class Buff002 : BuffBase { // 攻击力增加的数值 private float m_ADUp = 10f; private PlayerController playerController; public override void Initialize(GameObject owner, string provider) { base.Initialize(owner, provider); MaxDuration = 5f;// 最大持续时间为5秒 MaxLevel = 10;// 最大等级为10级 BuffType = BuffType.Buff;// Buff类型为增益效果 ConflictResolution = ConflictResolution.combine;// Buff冲突时采用合并方式 Dispellable = false;// 不可被驱散 Name = "借来的短剑";// Buff的名称 Description = "每层增加10点攻击力";// Buff的描述 IconPath = "Icon/1036";// Buff的图标路径 Demotion = MaxLevel;// 每次Buff持续时间结束时降低的等级 playerController = Owner.GetComponent<PlayerController>(); } //当等级改变时调用 protected override void OnLevelChange(int change) { // 根据变化的等级调整角色的攻击力 playerController.AD += m_ADUp * change; //每次升级,重置Buff的当前剩余时间 ResidualDuration = MaxDuration; } }
调用
BuffManager.Instance.AddBuff<Buff002>(playerController.gameObject, "自己", 1);
效果
3. 永久BUFF,类似被动BUFF
public class Buff003 : BuffBase { PlayerController playerController; public override void Initialize(GameObject owner, string provider) { base.Initialize(owner, provider); TimeScale = 0f;// 时间缩放为0,暂停游戏中的时间流逝 MaxLevel = int.MaxValue;// 最大等级设置为int的最大值,表示无限等级 BuffType = BuffType.Buff;// Buff类型为增益效果 ConflictResolution = ConflictResolution.separate;// Buff冲突时采用分离方式 Dispellable = false;// 不可被驱散 Name = "盛宴"; Description = "增加生命值"; IconPath = "Icon/Feast"; Demotion = 0;// 每次Buff持续时间结束时降低的等级 playerController = owner.GetComponent<PlayerController>(); } // 当Buff等级发生变化时触发 protected override void OnLevelChange(int change) { // 根据变化的等级调整角色的生命值 playerController.HP += change; } }
调用
BuffManager.Instance.AddBuff<Buff003>(playerController.gameObject, "自己", 80);
效果
4. 负面BUFF,根据当前BUFF等级计算每秒收到伤害值,当两个不同单位向同一个单位施加同一个buff时BUFF独立存在
public class Buff004 : BuffBase { PlayerController playerController; // 每秒受到的伤害值 float m_DamagePerSeconds = 30; public override void Initialize(GameObject owner, string provider) { base.Initialize(owner, provider); playerController = owner.GetComponent<PlayerController>(); MaxDuration = 5f;// Buff的最大持续时间为5秒 TimeScale = 1f;// 时间缩放为1,正常流逝时间 MaxLevel = 5;// 最大等级设置为5 BuffType = BuffType.Debuff;// Buff类型为减益效果 ConflictResolution = ConflictResolution.separate;// Buff冲突时采用分离方式 Dispellable = true;// 可以被驱散 Name = "流血"; Description = "每层每秒受到30点伤害"; IconPath = "Icon/Darius_PassiveBuff"; Demotion = MaxLevel;// 每次Buff持续时间结束时降低的等级 } // 当Buff等级发生变化时触发 protected override void OnLevelChange(int change) { //每次升级,重置Buff的当前剩余时间 ResidualDuration = MaxDuration; } public override void FixedUpdate() { // 根据当前等级、每秒伤害值和固定时间步长来计算角色受到的伤害 playerController.HP -= m_DamagePerSeconds * CurrentLevel * BuffManager.FixedDeltaTime; } }
调用
if (Input.GetKeyDown(KeyCode.Alpha4)) { BuffManager.Instance.AddBuff<Buff004>(playerController.gameObject, "敌人1", 1); } if (Input.GetKeyDown(KeyCode.Alpha5)) { BuffManager.Instance.AddBuff<Buff004>(playerController.gameObject, "敌人2", 1); }
效果
5. 一级叠加两层,后面都叠加一层
public class Buff005 : BuffBase { PlayerController playerController; // 每秒受到的伤害值 float m_DamagePerSeconds = 10; public override void Initialize(GameObject owner, string provider) { base.Initialize(owner, provider); playerController = owner.GetComponent<PlayerController>(); MaxDuration = 1f;// Buff的最大持续时间为1秒 TimeScale = 1f;// 时间缩放为1,正常流逝时间 MaxLevel = int.MaxValue;// 最大等级设置为int.MaxValue,即无限大 BuffType = BuffType.Debuff;// Buff类型为减益效果 ConflictResolution = ConflictResolution.combine;// Buff冲突时采用合并方式 Dispellable = true;// 可以被驱散 Name = "被点燃"; Description = "每秒受到10点伤害,首次受到该BUFF伤害,一次叠加2层,后续叠加1层"; IconPath = "Icon/Darius_PassiveBuff"; Demotion = 1;// 每次Buff持续时间结束时降低的等级 } public override void FixedUpdate() { // 根据每秒伤害值和固定时间步长来计算角色受到的伤害 playerController.HP -= m_DamagePerSeconds * BuffManager.FixedDeltaTime; } }
调用
if (Input.GetKeyDown(KeyCode.Alpha6)) { int number = 1; //获取叠加的BUff层数 if(BuffManager.Instance.FindBuff<Buff005>(playerController.gameObject).Count == 0 ) { number = 2; } BuffManager.Instance.AddBuff<Buff005>(playerController.gameObject, "敌人1", number); }
效果
最终效果
参考
【视频】https://www.bilibili.com/video/BV1Xy4y1N7Cb
源码
https://gitcode.net/unity1/buffsystem