參考原視頻鏈接
【視頻】:https://www.bilibili.com/video/BV1Xy4y1N7Cb注意
:本文為學(xué)習(xí)筆記記錄,推薦支持原作者,去看原視頻自己手敲代碼理解更加深入
先來看看最終效果
前言
當(dāng)今大多數(shù)游戲都擁有一些形式的Buff系統(tǒng),利用這種系統(tǒng)可以增強(qiáng)或削弱游戲角色的特定屬性。在Unity中,我們可以使用腳本輕松地創(chuàng)建這樣的Buff系統(tǒng)。
在本教程中,我們將探索如何實(shí)現(xiàn)一種基本的Buff系統(tǒng),其中包括對(duì)游戲中的玩家或敵對(duì)角色施加各種不同類型的Buff。我們還將學(xué)習(xí)如何設(shè)置時(shí)間限制和疊加限制,以及如何實(shí)現(xiàn)Buff效果的應(yīng)用和移除。
通過本教程,您將學(xué)習(xí)如何在Unity中創(chuàng)建一個(gè)完整的Buff系統(tǒng),為您的游戲增加全新的深度和策略性。
開始
新增腳本PlayerController,添加玩家血量和攻擊力變量,并實(shí)時(shí)顯示
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顯示界面
狀態(tài)欄
遮罩
最終效果
BUFF系統(tǒng)
定義BUFF類型枚舉
public enum BuffType
{
/// <summary>
/// 正面buff
/// </summary>
Buff,
/// <summary>
/// 負(fù)面buff
/// </summary>
Debuff,
/// <summary>
/// 沒有buff
/// </summary>
None,
}
BUFF沖突方式枚舉類型
/// <summary>
/// 當(dāng)兩個(gè)不同單位向同一個(gè)單位施加同一個(gè)buff時(shí)的沖突處理
/// </summary>
public enum ConflictResolution
{
/// <summary>
/// 合并為一個(gè)buff,疊層(提高等級(jí))
/// </summary>
combine,
/// <summary>
/// 獨(dú)立存在
/// </summary>
separate,
/// <summary>
/// 覆蓋,后者覆蓋前者
/// </summary>
cover,
}
新建BuffBase,Buff系統(tǒng)中的基類
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 = "默認(rèn)名稱";
private string m_Description = "這個(gè)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的初始持續(xù)時(shí)間
/// </summary>
public float MaxDuration
{
get { return m_MaxDuration; }
protected set { m_MaxDuration = Math.Clamp(value, 0, float.MaxValue); }
}
/// <summary>
/// buff的時(shí)間流失速度,最小為0,最大為10。
/// </summary>
public float TimeScale
{
get { return m_TimeScale; }
set { m_TimeScale = Math.Clamp(value, 0, 10); }
}
/// <summary>
/// buff的最大堆疊層數(shù),最小為1,最大為2147483647
/// </summary>
public int MaxLevel
{
get { return m_MaxLevel; }
protected set { m_MaxLevel = Math.Clamp(value, 1, int.MaxValue); }
}
/// <summary>
/// Buff的類型,分為正面、負(fù)面、中立三種
/// </summary>
public BuffType BuffType
{
get { return m_BuffType; }
protected set { m_BuffType = value; }
}
/// <summary>
/// 當(dāng)兩個(gè)不同單位向同一個(gè)單位施加同一個(gè)buff時(shí)的沖突處理
/// 分為三種:
/// combine,合并為一個(gè)buff,疊層(提高等級(jí))
/// separate,獨(dú)立存在
/// cover, 覆蓋,后者覆蓋前者
/// </summary>
public ConflictResolution ConflictResolution
{
get { return m_ConflictResolution; }
protected set { m_ConflictResolution = value; }
}
/// <summary>
/// 可否被驅(qū)散
/// </summary>
public bool Dispellable
{
get { return m_Dispellable; }
protected set { m_Dispellable = value; }
}
/// <summary>
/// Buff對(duì)外顯示的名稱
/// </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>
/// 圖標(biāo)資源的路徑
/// </summary>
public string IconPath
{
get { return m_IconPath; }
protected set { m_IconPath = value; }
}
/// <summary>
/// 每次Buff持續(xù)時(shí)間結(jié)束時(shí)降低的等級(jí),一般降低1級(jí)或者降低為0級(jí)。
/// </summary>
public int Demotion
{
get { return m_Demotion; }
protected set { m_Demotion = Math.Clamp(value, 0, MaxLevel); }
}
/// <summary>
/// Buff的當(dāng)前等級(jí)
/// </summary>
public int CurrentLevel
{
get { return m_CurrentLevel; }
set
{
//計(jì)算出改變值
int change = Math.Clamp(value, 0, MaxLevel) - m_CurrentLevel;
OnLevelChange(change);
m_CurrentLevel += change;
}
}
/// <summary>
/// Buff的當(dāng)前剩余時(shí)間
/// </summary>
public float ResidualDuration
{
get { return m_ResidualDuration; }
set { m_ResidualDuration = Math.Clamp(value, 0, float.MaxValue); }
}
/// <summary>
/// 當(dāng)Owner獲得此buff時(shí)觸發(fā)
/// 由BuffManager在合適的時(shí)候調(diào)用
/// </summary>
public virtual void OnGet() { }
/// <summary>
/// 當(dāng)Owner失去此buff時(shí)觸發(fā)
/// 由BuffManager在合適的時(shí)候調(diào)用
/// </summary>
public virtual void OnLost() { }
/// <summary>
/// Update,由BuffManager每物理幀調(diào)用
/// </summary>
public virtual void FixedUpdate() { }
/// <summary>
/// 當(dāng)?shù)燃?jí)改變時(shí)調(diào)用
/// </summary>
/// <param name="change">改變了多少級(jí)</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("不能對(duì)已經(jīng)初始化的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項(xiàng)預(yù)制體")]
private GameObject m_BuffItemTemplate;
[SerializeField, Header("對(duì)象池")]
private GameObject m_Pool;
[SerializeField, Header("Buff項(xiàng)父物體")]
private GameObject m_Buffs;
[SerializeField, Header("與Buff相關(guān)聯(lián)的游戲?qū)ο?)]
private PlayerController m_Hero;
private ObjectPool<UI_BuffItem> m_BuffItemPool;// Buff項(xiàng)對(duì)象池
// Buff項(xiàng)對(duì)象池的創(chuàng)建函數(shù),用于實(shí)例化Buff項(xiàng)
private UI_BuffItem Pool_CreateFunc()
{
return Instantiate(m_BuffItemTemplate, this.transform).GetComponent<UI_BuffItem>();
}
// Buff項(xiàng)對(duì)象池的獲取時(shí)回調(diào),用于激活對(duì)象并設(shè)置父物體
private void Pool_ActionOnGet(UI_BuffItem UI_BuffItem)
{
UI_BuffItem.gameObject.SetActive(true);
UI_BuffItem.transform.SetParent(m_Buffs.transform);
}
// Buff項(xiàng)對(duì)象池的回收時(shí)回調(diào),用于隱藏對(duì)象并設(shè)置父物體
private void Pool_ActionOnRelease(UI_BuffItem UI_BuffItem)
{
UI_BuffItem.gameObject.SetActive(false);
UI_BuffItem.transform.SetParent(m_Pool.transform);
}
// Buff項(xiàng)對(duì)象池的銷毀時(shí)回調(diào),用于銷毀對(duì)象
private void Pool_ActionOnDestroy(UI_BuffItem UI_BuffItem)
{
Destroy(UI_BuffItem.gameObject);
}
// Buff監(jiān)聽器,當(dāng)有新的Buff時(shí)調(diào)用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關(guān)聯(lián)的所有Buff,并調(diào)用ShowBuffCore方法顯示它們
foreach (BuffBase item in BuffManager.Instance.StartObserving(m_Hero.gameObject, BuffListener))
{
ShowBuffCore(item);
}
}
}
掛載腳本并配置參數(shù)
新增UI_BuffItem,控制Buff信息UI顯示
public class UI_BuffItem : MonoBehaviour
{
[SerializeField, Header("遮罩層")]
private Image m_Mask_M;
[SerializeField, Header("等級(jí)文本")]
private TextMeshProUGUI m_Level;
[SerializeField, Header("邊框")]
private Image m_Frame;
[SerializeField, Header("圖標(biāo)")]
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;// 是否已經(jīng)初始化
private bool m_NeedNumber = false;// 是否需要顯示等級(jí)
private bool m_NeedLine = false;// 是否需要顯示計(jì)時(shí)工具
private BuffBase m_TargetBuff;
public void OnPointerEnter()
{
m_BuffInfo.gameObject.SetActive(true);
ShowInfo(m_TargetBuff);
}
// 顯示Buff詳細(xì)信息
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)
{
//需要顯示計(jì)時(shí)工具才顯示
if (m_NeedLine)
{
m_Mask_M.fillAmount = 1 - (m_TargetBuff.ResidualDuration / m_TargetBuff.MaxDuration);
}
//需要顯示等級(jí)才顯示
if (m_NeedNumber)
{
m_Level.text = m_TargetBuff.CurrentLevel.ToString();
}
//如果當(dāng)前等級(jí)等于零說明他已經(jīng)被廢棄了,所以就可以回收了
if (m_TargetBuff.CurrentLevel == 0 )
{
m_RecyclePool.Release(this);
}
}
}
}
綁定腳本,配置參數(shù)并添加鼠標(biāo)移入移出事件
新增ShowBuff,控制BUFFBuff的顯示
public class ShowBuff : MonoBehaviour
{
[SerializeField, Header("Buff項(xiàng)預(yù)制體")]
private GameObject m_BuffItemTemplate;
[SerializeField, Header("對(duì)象池")]
private GameObject m_Pool;
[SerializeField, Header("Buff項(xiàng)父物體")]
private GameObject m_Buffs;
[SerializeField, Header("與Buff相關(guān)聯(lián)的游戲?qū)ο?)]
private PlayerController m_Hero;
private ObjectPool<UI_BuffItem> m_BuffItemPool;// Buff項(xiàng)對(duì)象池
// Buff項(xiàng)對(duì)象池的創(chuàng)建函數(shù),用于實(shí)例化Buff項(xiàng)
private UI_BuffItem Pool_CreateFunc()
{
return Instantiate(m_BuffItemTemplate, this.transform).GetComponent<UI_BuffItem>();
}
// Buff項(xiàng)對(duì)象池的獲取時(shí)回調(diào),用于激活對(duì)象并設(shè)置父物體
private void Pool_ActionOnGet(UI_BuffItem UI_BuffItem)
{
UI_BuffItem.gameObject.SetActive(true);
UI_BuffItem.transform.SetParent(m_Buffs.transform);
}
// Buff項(xiàng)對(duì)象池的回收時(shí)回調(diào),用于隱藏對(duì)象并設(shè)置父物體
private void Pool_ActionOnRelease(UI_BuffItem UI_BuffItem)
{
UI_BuffItem.gameObject.SetActive(false);
UI_BuffItem.transform.SetParent(m_Pool.transform);
}
// Buff項(xiàng)對(duì)象池的銷毀時(shí)回調(diào),用于銷毀對(duì)象
private void Pool_ActionOnDestroy(UI_BuffItem UI_BuffItem)
{
Destroy(UI_BuffItem.gameObject);
}
// Buff監(jiān)聽器,當(dāng)有新的Buff時(shí)調(diào)用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關(guān)聯(lián)的所有Buff,并調(diào)用ShowBuffCore方法顯示它們
foreach (BuffBase item in BuffManager.Instance.StartObserving(m_Hero.gameObject, BuffListener))
{
ShowBuffCore(item);
}
}
}
掛載腳本,配置參數(shù)
新增BuffManager,BUFF管理類
public class BuffManager : MonoBehaviour
{
/// <summary>
/// 固定時(shí)間更新的更新頻率,此值不宜過高,可以過低(會(huì)增加性能消耗)。
/// </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>
/// 存儲(chǔ)了所有的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>
/// 返回要觀察的對(duì)象現(xiàn)有的buff,并且在對(duì)象被添加新buff時(shí)通知你
/// (如果現(xiàn)在對(duì)象身上沒有buff會(huì)返回空列表,不會(huì)返回null)
/// </summary>
/// <returns></returns>
public List<BuffBase> StartObserving(GameObject target, Action<BuffBase> listener)
{
List<BuffBase> list;
//添加監(jiān)聽
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>
/// 停止觀察某一對(duì)象,請(qǐng)傳入與調(diào)用開始觀察方法時(shí)使用的相同參數(shù)。
/// </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("要停止觀察的對(duì)象不存在");
}
m_ObserverDicitinary[target] -= listener;
if (m_ObserverDicitinary[target] == null)
{
m_ObserverDicitinary.Remove(target);
}
}
/// <summary>
/// 在目標(biāo)身上掛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()
{
//如果我們的字典里沒有存儲(chǔ)這個(gè)key,就進(jìn)行初始化
if (!m_BuffDictionary.ContainsKey(target))
{
m_BuffDictionary.Add(target, new List<BuffBase>(5));
//目標(biāo)身上自然沒有任何buff,直接掛一個(gè)新buff即可
AddNewBuff<T>(target, provider, level);
return;
}
//如果目標(biāo)身上沒有任何buff,直接掛一個(gè)新buff即可
if (m_BuffDictionary[target].Count == 0)
{
AddNewBuff<T>(target, provider, level);
return;
}
//遍歷看看目標(biāo)身上有沒有已存在的要掛的buff。
List<T> temp01 = new List<T>();
foreach (BuffBase item in m_BuffDictionary[target])
{
if (item is T)
{
temp01.Add(item as T);
}
}
//如果沒有直接掛一個(gè)新buff就行了
//如果有已存在的要掛的buff,就要進(jìn)行沖突處理了
if (temp01.Count == 0)
{
AddNewBuff<T>(target, provider, level);
}
else
{
switch (temp01[0].ConflictResolution)
{
//如果是獨(dú)立存在,那也直接掛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,然后添加這個(gè)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>
/// 移除單位身上指定的一個(gè)buff
/// </summary>
/// <param name="owner"></param>
/// <param name="buff"></param>
/// <returns>是否成功,如果失敗說明目標(biāo)不存在</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;
//執(zhí)行所有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;
//復(fù)制一份
m_BuffDictionaryCopy.Clear();
foreach (KeyValuePair<GameObject, List<BuffBase>> item in m_BuffDictionary)
{
m_BuffDictionaryCopy.Add(item.Key, item.Value);
}
//清理無用對(duì)象
foreach (KeyValuePair<GameObject, List<BuffBase>> item in m_BuffDictionaryCopy)
{
//如果owner被刪除,我們這邊也跟著刪除
if (item.Key == null)
{
m_BuffDictionary.Remove(item.Key);
continue;
}
//如果一個(gè)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()
{
//清理無用對(duì)象
foreach (KeyValuePair<GameObject, List<BuffBase>> item in m_BuffDictionary)
{
//清理無用buff
//降低持續(xù)時(shí)間
for (int i = item.Value.Count - 1; i >= 0; i--)
{
m_Transfer_Buff = item.Value[i];
//如果等級(jí)為0,則移除
if (m_Transfer_Buff.CurrentLevel == 0)
{
RemoveBuff(item.Key, m_Transfer_Buff);
continue;
}
//如果持續(xù)時(shí)間為0,則降級(jí),
//降級(jí)后如果等級(jí)為0則移除,否則刷新持續(xù)時(shí)間
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;
}
}
//降低持續(xù)時(shí)間
m_Transfer_Buff.ResidualDuration -= Time.fixedDeltaTime;
}
}
}
}
加幾個(gè)BUFF測試
1. 逐層消失,升級(jí)不重置剩余時(shí)間的BUFF
public class Buff001 : BuffBase
{
// Buff每秒鐘恢復(fù)的生命值
private float m_HealingPerSecond = 20f;
// 作用目標(biāo),即被添加Buff的角色
private PlayerController playerController;
// 初始化Buff的屬性和狀態(tài)
public override void Initialize(GameObject owner, string provider)
{
base.Initialize(owner, provider);
// 獲取作用目標(biāo)的PlayerController組件
playerController = owner.GetComponent<PlayerController>();
// 設(shè)置Buff的基本屬性
MaxDuration = 15; // 最大持續(xù)時(shí)間為15秒
TimeScale = 1f; // 時(shí)間流失速度為正常值
MaxLevel = 5; // 最大等級(jí)為5級(jí)
BuffType = BuffType.Buff; // Buff類型為增益效果
ConflictResolution = ConflictResolution.combine; // Buff沖突時(shí)采用合并方式
Dispellable = false; // 不可被驅(qū)散
Name = "生命值"; // Buff的名稱
Description = $"每秒恢復(fù){m_HealingPerSecond}點(diǎn)生命值"; // Buff的描述
Demotion = 1; // 每次Buff持續(xù)時(shí)間結(jié)束時(shí)降低的等級(jí)
IconPath = "Icon/2003"; // Buff的圖標(biāo)路徑
}
// 在固定時(shí)間間隔內(nèi)更新Buff的效果
public override void FixedUpdate()
{
// 每秒鐘恢復(fù)指定的生命值
playerController.HP += m_HealingPerSecond * BuffManager.FixedDeltaTime;
}
}
調(diào)用測試
public class Test : MonoBehaviour
{
public PlayerController playerController;
void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha1))
{
//作用目標(biāo) 來源:自己,每次加1層
BuffManager.Instance.AddBuff<Buff001>(playerController.gameObject, "自己", 1);
}
}
}
效果
2. 一次性全部消失,升級(jí)重置剩余時(shí)間的BUFF
public class Buff002 : BuffBase
{
// 攻擊力增加的數(shù)值
private float m_ADUp = 10f;
private PlayerController playerController;
public override void Initialize(GameObject owner, string provider)
{
base.Initialize(owner, provider);
MaxDuration = 5f;// 最大持續(xù)時(shí)間為5秒
MaxLevel = 10;// 最大等級(jí)為10級(jí)
BuffType = BuffType.Buff;// Buff類型為增益效果
ConflictResolution = ConflictResolution.combine;// Buff沖突時(shí)采用合并方式
Dispellable = false;// 不可被驅(qū)散
Name = "借來的短劍";// Buff的名稱
Description = "每層增加10點(diǎn)攻擊力";// Buff的描述
IconPath = "Icon/1036";// Buff的圖標(biāo)路徑
Demotion = MaxLevel;// 每次Buff持續(xù)時(shí)間結(jié)束時(shí)降低的等級(jí)
playerController = Owner.GetComponent<PlayerController>();
}
//當(dāng)?shù)燃?jí)改變時(shí)調(diào)用
protected override void OnLevelChange(int change)
{
// 根據(jù)變化的等級(jí)調(diào)整角色的攻擊力
playerController.AD += m_ADUp * change;
//每次升級(jí),重置Buff的當(dāng)前剩余時(shí)間
ResidualDuration = MaxDuration;
}
}
調(diào)用
BuffManager.Instance.AddBuff<Buff002>(playerController.gameObject, "自己", 1);
效果
3. 永久BUFF,類似被動(dòng)BUFF
public class Buff003 : BuffBase
{
PlayerController playerController;
public override void Initialize(GameObject owner, string provider)
{
base.Initialize(owner, provider);
TimeScale = 0f;// 時(shí)間縮放為0,暫停游戲中的時(shí)間流逝
MaxLevel = int.MaxValue;// 最大等級(jí)設(shè)置為int的最大值,表示無限等級(jí)
BuffType = BuffType.Buff;// Buff類型為增益效果
ConflictResolution = ConflictResolution.separate;// Buff沖突時(shí)采用分離方式
Dispellable = false;// 不可被驅(qū)散
Name = "盛宴";
Description = "增加生命值";
IconPath = "Icon/Feast";
Demotion = 0;// 每次Buff持續(xù)時(shí)間結(jié)束時(shí)降低的等級(jí)
playerController = owner.GetComponent<PlayerController>();
}
// 當(dāng)Buff等級(jí)發(fā)生變化時(shí)觸發(fā)
protected override void OnLevelChange(int change)
{
// 根據(jù)變化的等級(jí)調(diào)整角色的生命值
playerController.HP += change;
}
}
調(diào)用
BuffManager.Instance.AddBuff<Buff003>(playerController.gameObject, "自己", 80);
效果
4. 負(fù)面BUFF,根據(jù)當(dāng)前BUFF等級(jí)計(jì)算每秒收到傷害值,當(dāng)兩個(gè)不同單位向同一個(gè)單位施加同一個(gè)buff時(shí)BUFF獨(dú)立存在
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的最大持續(xù)時(shí)間為5秒
TimeScale = 1f;// 時(shí)間縮放為1,正常流逝時(shí)間
MaxLevel = 5;// 最大等級(jí)設(shè)置為5
BuffType = BuffType.Debuff;// Buff類型為減益效果
ConflictResolution = ConflictResolution.separate;// Buff沖突時(shí)采用分離方式
Dispellable = true;// 可以被驅(qū)散
Name = "流血";
Description = "每層每秒受到30點(diǎn)傷害";
IconPath = "Icon/Darius_PassiveBuff";
Demotion = MaxLevel;// 每次Buff持續(xù)時(shí)間結(jié)束時(shí)降低的等級(jí)
}
// 當(dāng)Buff等級(jí)發(fā)生變化時(shí)觸發(fā)
protected override void OnLevelChange(int change)
{
//每次升級(jí),重置Buff的當(dāng)前剩余時(shí)間
ResidualDuration = MaxDuration;
}
public override void FixedUpdate()
{
// 根據(jù)當(dāng)前等級(jí)、每秒傷害值和固定時(shí)間步長來計(jì)算角色受到的傷害
playerController.HP -= m_DamagePerSeconds * CurrentLevel * BuffManager.FixedDeltaTime;
}
}
調(diào)用
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. 一級(jí)疊加兩層,后面都疊加一層
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的最大持續(xù)時(shí)間為1秒
TimeScale = 1f;// 時(shí)間縮放為1,正常流逝時(shí)間
MaxLevel = int.MaxValue;// 最大等級(jí)設(shè)置為int.MaxValue,即無限大
BuffType = BuffType.Debuff;// Buff類型為減益效果
ConflictResolution = ConflictResolution.combine;// Buff沖突時(shí)采用合并方式
Dispellable = true;// 可以被驅(qū)散
Name = "被點(diǎn)燃";
Description = "每秒受到10點(diǎn)傷害,首次受到該BUFF傷害,一次疊加2層,后續(xù)疊加1層";
IconPath = "Icon/Darius_PassiveBuff";
Demotion = 1;// 每次Buff持續(xù)時(shí)間結(jié)束時(shí)降低的等級(jí)
}
public override void FixedUpdate()
{
// 根據(jù)每秒傷害值和固定時(shí)間步長來計(jì)算角色受到的傷害
playerController.HP -= m_DamagePerSeconds * BuffManager.FixedDeltaTime;
}
}
調(diào)用
if (Input.GetKeyDown(KeyCode.Alpha6))
{
int number = 1;
//獲取疊加的BUff層數(shù)
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
完結(jié)
贈(zèng)人玫瑰,手有余香!如果文章內(nèi)容對(duì)你有所幫助,請(qǐng)不要吝嗇你的點(diǎn)贊評(píng)論和關(guān)注
,以便我第一時(shí)間收到反饋,你的每一次支持
都是我不斷創(chuàng)作的最大動(dòng)力。當(dāng)然如果你發(fā)現(xiàn)了文章中存在錯(cuò)誤
或者有更好的解決方法
,也歡迎評(píng)論私信告訴我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net文章來源:http://www.zghlxwxcb.cn/news/detail-743857.html
一位在小公司默默奮斗的開發(fā)者,出于興趣愛好,于是最近才開始自習(xí)unity。如果你遇到任何問題,也歡迎你評(píng)論私信找我, 雖然有些問題我可能也不一定會(huì),但是我會(huì)查閱各方資料,爭取給出最好的建議,希望可以幫助更多想學(xué)編程的人,共勉~文章來源地址http://www.zghlxwxcb.cn/news/detail-743857.html
到了這里,關(guān)于【unity實(shí)戰(zhàn)】實(shí)現(xiàn)類似英雄聯(lián)盟的buff系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!