【unity实战】实现一个buff系统(附项目源码)
当今大多数游戏都拥有一些形式的Buff系统,利用这种系统可以增强或削弱游戏角色的特定属性。在Unity中,我们可以使用脚本轻松地创建这样的Buff系统。在本教程中,我们将探索如何实现一种基本的Buff系统,其中包括对游戏中的玩家或敌对角色施加各种不同类型的Buff。我们还将学习如何设置时间限制和叠加限制,以及如何实现Buff效果的应用和移除。通过本教程,您将学习如何在Unity中创建一个完整的Bu
参考原视频链接
【视频】:https://www.bilibili.com/video/BV1Xy4y1N7Cb
注意
:本文为学习笔记记录,推荐支持原作者,去看原视频自己手敲代码理解更加深入
文章目录
先来看看最终效果
前言
当今大多数游戏都拥有一些形式的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
参考
【视频】https://www.bilibili.com/video/BV1Xy4y1N7Cb
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)