【unity实战】实现一个buff系统(附项目源码)

2024-01-08 00:50

本文主要是介绍【unity实战】实现一个buff系统(附项目源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考原视频链接
【视频】:https://www.bilibili.com/video/BV1Xy4y1N7Cb
注意:本文为学习笔记记录,推荐支持原作者,去看原视频自己手敲代码理解更加深入

文章目录

  • 先来看看最终效果
  • 前言
  • 开始
  • BUFF系统
  • 加几个BUFF测试
    • 1. 逐层消失,升级不重置剩余时间的BUFF
    • 2. 一次性全部消失,升级重置剩余时间的BUFF
    • 3. 永久BUFF,类似被动BUFF
    • 4. 负面BUFF,根据当前BUFF等级计算每秒收到伤害值,当两个不同单位向同一个单位施加同一个buff时BUFF独立存在
    • 5. 一级叠加两层,后面都叠加一层
  • 最终效果
  • 参考
  • 源码
  • 参考
  • 完结

先来看看最终效果

在这里插入图片描述

前言

当今大多数游戏都拥有一些形式的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;//查找已有buffif (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){//如果是独立存在,那也直接挂buffcase 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);}}#endregionprivate 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;// 最大等级设置为5BuffType = 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
在这里插入图片描述

参考

【视频】https://www.bilibili.com/video/BV1Xy4y1N7Cb

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

这篇关于【unity实战】实现一个buff系统(附项目源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/581796

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景