当前位置: 首页 > news >正文

Unity BuffSystem buff系统

Unity BuffSystem buff系统

  • 一、介绍
  • 二、buff系统架构
  • 三、架构讲解
  • 四、框架使用
    • buff数据
    • Json数据以及工具
    • ShowType
    • BuffType
    • MountType
    • BuffOverlap
    • BuffShutDownType
    • BuffCalculateType
    • 时间和层数这里也不过多说明了
    • 如何给生物添加buff
  • 五、总结

一、介绍

现在基本做游戏都会需要些buff,之前我也在网上找也看到很多别人写的buff系统,并不是很符合我的心理预期,大部分在网上看到的都是面向过程的而不是面向对象的独立开来的buff,这样每改动一个小地方或者写一个buff基本上就要改动整个框架的部分,这对合作开发来说是比较致命的,就一个人来做的话还问题不大,但是人一单多了一人写几个buff最后就全乱了,今天把我之前写的这套框架发出来,经过验证了,原来的一个项目大概有3000多个buff,能够比较完美的支持下来。
这个buff系统架构我放到CSDN资源中,可以进入BGBuffSystem下的SampleScene查看demo。

二、buff系统架构

在这里插入图片描述
这里大概做一个的架构,细节后面再说。

三、架构讲解

架构这里我就简单说一下整体的逻辑,大家可以下载使用看核心。
这里我选择的面向对象也是面向组件的方式,这意味着我每一个buff都会创建两个类分别是xxxBuffCtrl操作类、xxxBuffEntity数据实体类,当buff挂载时会将对应的xxxBuffCtrl挂载到对应的对象上,而xxxBuffCtrl是负责控制buff的具体效果并且持有xxxBuffEntity数据实体,他们分别也是继承自BuffCtrlBase、BuffEntityBase。这样上层管理的时候只需要管理BuffEntityBase的初始化数据和BuffCtrlBase对应的上层管理即可。数据用的是json。

Buff层数、buff的移除方式(全部移除还是单独移除),buff多挂载,buff执行次数,buff的类型(叠加,永久,重复添加刷新时间,刷新层数)等我在上层提供了集中常用的类型,如果要想添加可以在BuffCtrlBase中写具体逻辑,在BuffEntityBase的BuffOverlap枚举中添加新类型。
这里我也提供了很多的接口具体的可以在BuffCtrlBase中看。

using System.Collections;
using UnityEngine;
using System;public class BuffCtrlBase : MonoBehaviour, IDisposable
{#region 基础属性/// <summary>/// Buff信息/// </summary>public BuffEntityBase m_buffInfo;/// <summary>/// 人物控制器/// </summary>public RoleAttribute m_Self;/// <summary>/// 敌人控制器/// </summary>public RoleAttribute m_Other;/// <summary>/// 是否触发/// </summary>public bool m_IsEnable = false;#endregion#region 辅助计算使用/// <summary>/// buff Ctrl层的限制时长 根据Entity的m_LimitTime获取/// </summary>public float m_CtrlLimitTime = 0;/// <summary>/// 辅助计算使用/// </summary>private float m_CtrlFrequencyTimer = 0;#endregion#region 进入buff(初始化)/// <summary>/// 进入Buff/// </summary>public virtual void BuffOnEnter(RoleAttribute self, RoleAttribute other, string json){m_Self = self;m_Other = other;m_IsEnable = true;}/// <summary>/// 初始化/// </summary>public virtual void InitAttr(){}#endregion#region 暂停继续buff/// <summary>/// 暂停buff/// </summary>public virtual void PauseBuff(){m_IsEnable = false;}/// <summary>/// 继续buff/// </summary>public virtual void ContinueBuff(){m_IsEnable = false;}#endregion#region 持续buff中/// <summary>/// 持续Buff/// </summary>public virtual void BuffOnStay(){if (m_IsEnable){switch (m_buffInfo.buffOverlap){//计时结束移除 重新复制是将时间叠加case BuffOverlap.OnlyStackedTimeWithLimitTime:m_buffInfo.m_TimingTime += Time.deltaTime;m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}if (m_buffInfo.m_TimingTime >= m_buffInfo.m_LimitTime){m_IsEnable = false;BuffOnExit();}break;//计时结束移除 重新复制是将时间重置case BuffOverlap.OnlyStackedResterTimeWithLimitTime:m_buffInfo.m_TimingTime += Time.deltaTime;m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}if (m_buffInfo.m_TimingTime >= m_buffInfo.m_LimitTime){m_IsEnable = false;BuffOnExit();}break;case BuffOverlap.OnlyStackedLimitLayer:m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}break;case BuffOverlap.OnlyStackedLimitLayerWithResetLimitTime:m_buffInfo.m_TimingTime += Time.deltaTime;m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}if (m_buffInfo.m_TimingTime >= m_buffInfo.m_LimitTime){m_IsEnable = false;BuffOnExit();}break;case BuffOverlap.MoreStackedLimitTime:m_buffInfo.m_TimingTime += Time.deltaTime;m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}if (m_buffInfo.m_TimingTime >= m_buffInfo.m_LimitTime){m_IsEnable = false;BuffOnExit();}break;//永久存在 无需层数叠加 只执行一次case BuffOverlap.OnlyStackedOnePermanent:m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}break;//永久存在 无需层数叠加 每间隔时间执行一次case BuffOverlap.OnlyStackedLoopTimeCallPermanent:m_buffInfo.m_TimingTime += Time.deltaTime;if (m_buffInfo.m_TimingTime >= m_buffInfo.m_LimitTime){m_buffInfo.m_TimingTime = m_buffInfo.m_TimingTime - m_buffInfo.m_LimitTime;InsistCallBack();}break;//倒计时结束消失 无重叠case BuffOverlap.OnlyStackedLimitTime:m_buffInfo.m_TimingTime += Time.deltaTime;m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}if (m_buffInfo.m_TimingTime >= m_buffInfo.m_LimitTime){m_IsEnable = false;BuffOnExit();}break;//永久存在现实层数case BuffOverlap.OnlyStackOnePermanentWithLimitLayer:m_CtrlFrequencyTimer += Time.deltaTime;if (m_buffInfo.m_Frequency != 0 && m_buffInfo.buffCalculateType == BuffCalculateType.Loop){if (m_CtrlFrequencyTimer >= m_buffInfo.m_Frequency){m_CtrlFrequencyTimer = m_CtrlFrequencyTimer - m_buffInfo.m_Frequency;InsistCallBack();}}break;default:break;}}}#endregion#region 持续回调 根据Frequency数据间隔进行调用/// <summary>/// 持续回调 根据Frequency数据间隔进行调用/// </summary>public virtual void InsistCallBack(){}#endregion#region 层数回调 根据当前层数进行回调/// <summary>/// 根据层数进行回调/// </summary>/// <param name="layer"></param>public virtual void LayerCallBack(int layer){}/// <summary>/// 减少层数/// </summary>public virtual void RemoveLayerCallBack(){m_buffInfo.m_TimingLayer--;}#endregion#region 离开buff/// <summary>/// 离开buff/// </summary>public virtual void BuffOnExit(){if (m_Self != null){m_Self.RemoveBuff(this);}Dispose();Destroy(this);}#endregion#region 重复添加buff/// <summary>/// 重复添加/// </summary>public virtual void RepeatAdd(){Debug.LogError("重复添加buff");switch (m_buffInfo.buffOverlap){//计时结束移除 重新复制是将时间叠加case BuffOverlap.OnlyStackedTimeWithLimitTime:m_buffInfo.m_LimitTime += m_CtrlLimitTime;break;case BuffOverlap.OnlyStackedResterTimeWithLimitTime:m_buffInfo.m_TimingTime = 0;break;case BuffOverlap.OnlyStackedLimitLayer:if (m_buffInfo.m_TimingLayer < m_buffInfo.m_LimitLayer){m_buffInfo.m_TimingLayer += 1;LayerCallBack(m_buffInfo.m_TimingLayer);}break;case BuffOverlap.OnlyStackedLimitLayerWithResetLimitTime:m_buffInfo.m_TimingTime = 0;if (m_buffInfo.m_TimingLayer < m_buffInfo.m_LimitLayer){m_buffInfo.m_TimingLayer += 1;LayerCallBack(m_buffInfo.m_TimingLayer);}break;case BuffOverlap.MoreStackedLimitTime:break;case BuffOverlap.OnlyStackedOnePermanent:break;case BuffOverlap.OnlyStackedLoopTimeCallPermanent:break;case BuffOverlap.OnlyStackedLimitTime:break;case BuffOverlap.OnlyStackOnePermanentWithLimitLayer:break;default:break;}}#endregion#region FixedUpdateprivate void FixedUpdate(){BuffOnStay();}#endregion#region 释放/// <summary>/// 释放接口/// </summary>public virtual void Dispose(){m_buffInfo.Dispose();m_Self = null;m_Other = null;m_IsEnable = false;m_CtrlLimitTime = 0;m_CtrlFrequencyTimer = 0;Debug.LogError("移除释放buff");}#endregion
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;/// <summary>
/// 展示类型
/// </summary>
public enum ShowType
{None = 0,/// <summary>/// 需要展示UI/// </summary>Show = 1,/// <summary>/// 无需展示UI/// </summary>Hide = 2,
}/// <summary>
/// buff类型 获取buf名 找buf实体类和控制类
/// </summary>
public enum BuffType
{None = 0,/// <summary>/// 破甲buff/// </summary>PoJiaBuff = 1,/// <summary>/// 流血buff/// </summary>LiuXueBuff = 2,/// <summary>/// 中毒buff/// </summary>ZhongDuBuff = 3,
}/// <summary>
/// 挂载类型
/// </summary>
public enum MountType
{None = 0,/// <summary>/// 单挂载/// </summary>Only = 1,/// <summary>/// 多次挂载/// </summary>More = 2,
}/// <summary>
/// buff叠加类型
/// </summary>
public enum BuffOverlap
{None = 0,/// <summary>/// 同时只能挂载单脚本,计时结束移除 重复挂载时将时间进行叠加, (所需字段 LimitTime(限制时间) TimingTime(计时时间))/// </summary>OnlyStackedTimeWithLimitTime = 1,/// <summary>/// 同时只能挂载单脚本,计时结束移除,重复挂载时将时间进行重置 (所需字段 LimitTime(限制时间) TimingTime(计时时间))/// </summary>OnlyStackedResterTimeWithLimitTime = 2,/// <summary>/// 同时只能挂载单脚本,永久存在,重复挂载时将层数进行叠加(有层数上限) (所需字段 LimitLayer(限制层数) TimingLayer(计算层数))/// </summary>OnlyStackedLimitLayer = 3,/// <summary>/// 同时只能挂载单脚本,计时结束移除,重复挂载时将层数进行叠加并将时间重置(有层数上限)(所需字段 LimitLayer(限制时间) TimingTime(计时时间) LimitLayer(限制层数) TimingLayer(计算层数))/// </summary>OnlyStackedLimitLayerWithResetLimitTime = 4,/// <summary>/// 同时多次挂载同脚本,计时结束移除,可以多次重复挂载(所需字段 LimitTime() TimingTime(计时时间))/// </summary>MoreStackedLimitTime = 5,/// <summary>/// 仅堆叠一次 永久存在 /// </summary>OnlyStackedOnePermanent = 6,/// <summary>/// 仅堆叠一次 永久存在 每间隔时间执行一次 (所需字段 LimitTime(限制时间) TimingTime(计时时间))/// </summary>OnlyStackedLoopTimeCallPermanent = 7,/// <summary>/// 仅堆叠一次 倒计时结束 (所需字段 LimitTime(限制时间) TimingTime(计时时间))/// </summary>OnlyStackedLimitTime = 8,/// <summary>/// 仅堆叠一次永久存在并且需要展示层数 (所需字段 LimitLayer(限制层数) TimingLayer(计算层数))/// </summary>OnlyStackOnePermanentWithLimitLayer = 9,
}/// <summary>
/// 执行次数类型
/// </summary>
public enum BuffCalculateType
{None = 0,/// <summary>/// 一次/// </summary>Once = 1,/// <summary>/// 每次都执行跟随时间间隔走/// </summary>Loop = 2,
}/// <summary>
/// 关闭类型
/// </summary>
public enum BuffShutDownType
{None = 0,/// <summary>/// 关闭所有/// </summary>All = 1,/// <summary>/// 单层关闭/// </summary>Layer = 2,
}/// <summary>
/// Buff基类
/// </summary>
public class BuffEntityBase : IDisposable
{/// <summary>/// buff Id/// </summary>public int buffID;/// <summary>/// buff路径/// </summary>public string buffUrl;/// <summary>/// buff Name/// </summary>public string buffName;/// <summary>/// buff 描述/// </summary>public string buffDesc;/// <summary>/// 此buff是否有UI展示/// </summary>public ShowType showType = ShowType.None;/// <summary>/// buff 类型名 反射string为class使用/// </summary>public BuffType buffType = BuffType.None;/// <summary>/// buff 挂载类型是否可以挂载多个/// </summary>public MountType mountType = MountType.None;/// <summary>/// buff重叠类型/// </summary>public BuffOverlap buffOverlap = BuffOverlap.None;/// <summary>/// 执行次数/// </summary>public BuffCalculateType buffCalculateType = BuffCalculateType.None;/// <summary>/// buff关闭类型/// </summary>public BuffShutDownType buffShutDownType = BuffShutDownType.None;/// <summary>/// 限制时间/// </summary>public float m_LimitTime;/// <summary>/// 计时时间/// </summary>public float m_TimingTime;/// <summary>/// 限制层数/// </summary>public int m_LimitLayer;/// <summary>/// 计算层数/// </summary>public int m_TimingLayer;/// <summary>/// 间隔时间 0代表不跟间隔走/// </summary>public float m_Frequency = 1;/// <summary>/// 执行数值 比如召唤怪物1次 增加攻速5% 攻击力翻倍/// </summary>public float m_NumValue;/// <summary>/// 释放接口/// </summary>public virtual void Dispose(){buffID = 0;buffUrl = null;buffName = null;buffDesc = null;showType =  ShowType.None;buffType = BuffType.None;mountType = MountType.None;buffOverlap = BuffOverlap.None;buffCalculateType = BuffCalculateType.None;buffShutDownType = BuffShutDownType.None;m_LimitTime = 0;m_TimingTime = 0;m_LimitLayer = 0;m_TimingLayer = 0;m_Frequency = 0;m_NumValue = 0;}
}

RoleAttribute这个类主要是存放记录当前生物所包含的buff,这样方便来管理。

using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 人物基类
/// </summary>
public class RoleAttribute: MonoBehaviour
{/// <summary>/// buff控制列表/// </summary>public List<BuffCtrlBase> m_buffLst = new List<BuffCtrlBase> ();/// <summary>/// 添加Buff/// </summary>/// <param name="buffCtrlBase"></param>public void AddBuff(BuffCtrlBase buffCtrlBase) {m_buffLst.Add(buffCtrlBase);}/// <summary>/// 移除Buff/// </summary>public void RemoveBuff(BuffCtrlBase buffCtrlBase) {if(m_buffLst.Contains(buffCtrlBase)) m_buffLst.Remove(buffCtrlBase);}/// <summary>/// 是否包含该buff/// </summary>/// <param name="buffCtrlBase"></param>/// <returns></returns>public bool IsContainsBuff(BuffCtrlBase buffCtrlBase) {return m_buffLst.Contains (buffCtrlBase);}/// <summary>/// 是否包含该Id的buff/// </summary>/// <param name="Id"></param>/// <returns></returns>public bool IsContainsBuff(int Id) {for (int i = 0; i < m_buffLst.Count; i++) {if (m_buffLst[i].m_buffInfo.buffID == Id) return true;}return false;}/// <summary>/// 是否包含该类型的buff/// </summary>/// <param name="buffType"></param>/// <returns></returns>public bool IsContainsBuff(BuffType buffType) {for (int i = 0; i < m_buffLst.Count; i++){Debug.LogError(m_buffLst[i].m_buffInfo.buffType.ToString());if (m_buffLst[i].m_buffInfo.buffType == buffType) return true;}return false;}/// <summary>/// 获取buff控制类/// </summary>/// <param name="buffType"></param>/// <returns></returns>public BuffCtrlBase GetBuffCtrl(BuffType buffType) {for (int i = 0; i < m_buffLst.Count; i++){if (m_buffLst[i].m_buffInfo.buffType == buffType) return m_buffLst[i];}return null;}/// <summary>/// 获取buff控制类/// </summary>/// <param name="buffType"></param>/// <returns></returns>public BuffCtrlBase GetBuffCtrl(int Id){for (int i = 0; i < m_buffLst.Count; i++){if (m_buffLst[i].m_buffInfo.buffID == Id) return m_buffLst[i];}return null;}/// <summary>/// 获取buff控制类集合/// </summary>/// <param name="buffType"></param>/// <returns></returns>public List<BuffCtrlBase> GetBuffCtrls(BuffType buffType) {List<BuffCtrlBase> lst = new List<BuffCtrlBase> ();for (int i = 0; i < m_buffLst.Count; i++){if (m_buffLst[i].m_buffInfo.buffType == buffType) lst.Add(m_buffLst[i]);}return lst;}
}

BuffManager这个则是管理具体给谁添加buff和移除buff的管理类。

using LitJson;
using System;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// Buff管理器
/// </summary>
public class BuffManager : MonoBehaviour
{/// <summary>/// buff组件单例/// </summary>public static BuffManager Instance;// Start is called before the first frame updatevoid Awake(){Instance = this;}#region 添加Buff/// <summary>/// 创建buff/// </summary>public void AddBuff(RoleAttribute self, RoleAttribute other, BuffType buffType){Type t = Type.GetType(buffType.ToString() + "Ctrl");//buff数据string buffData = GetBuffJsonStr(buffType);//如果buff数据为nullif (string.IsNullOrEmpty(buffData)){Debug.LogError("当前buff还未配置无法添加buff");return;}JsonData data = JsonMapper.ToObject(buffData);//挂载类型MountType mount = (MountType)int.Parse(data["mountType"].ToString());//buff控制层脚本BuffCtrlBase bcb = null;//多个挂载if (mount == MountType.More){bcb = self.gameObject.AddComponent(t) as BuffCtrlBase;self.AddBuff(bcb);bcb.BuffOnEnter(self, other, GetBuffJsonStr(buffType));}//单挂载else{bool IsAdd = self.IsContainsBuff(buffType);Debug.LogError("IsAdd = " + IsAdd);//未挂载过if (!IsAdd){bcb = self.gameObject.AddComponent(t) as BuffCtrlBase;self.AddBuff(bcb);bcb.BuffOnEnter(self, other, GetBuffJsonStr(buffType));}//已经挂载过else{bcb = self.GetBuffCtrl(buffType);bcb.RepeatAdd();}}}#endregion#region 移除buf(主角、敌人)/// <summary>/// 移除人物身上的buf/// </summary>/// <param name="role"></param>/// <param name="buffType"></param>public void RemoveBuff(RoleAttribute role, BuffType buffType){role.GetBuffCtrl(buffType)?.BuffOnExit();}/// <summary>/// 移除人物身上的全部该buf/// </summary>/// <param name="role"></param>/// <param name="buffType"></param>public void RemoveAllBuff(RoleAttribute role, BuffType buffType){List<BuffCtrlBase> lst = role.GetBuffCtrls(buffType);lst.ForEach(cb => cb.BuffOnExit());}#endregion#region 获取buff信息/// <summary>/// 根据buff类型 获取buff的json数据/// </summary>public string GetBuffJsonStr(BuffType buffType){TextAsset buffdata = Resources.Load<TextAsset>(string.Format("BuffData/{0}/{0}", buffType.ToString()));if (buffdata == null){Debug.LogErrorFormat("未找到对应的{0}{1} ", buffType.ToString(), " buff数据,检查是否配置buff文件");return null;}return buffdata.text;}/// <summary>/// 根据buff类型 获取buff的JsonData/// </summary>public JsonData GetBuffJsonData(BuffType buffType){TextAsset buffdata = Resources.Load<TextAsset>(string.Format("BuffData/{0}/{0}", buffType.ToString()));if (buffdata == null){Debug.LogErrorFormat("未找到对应的{0}{1} ", buffType.ToString(), " buff数据,检查是否配置buff文件");return null;}return JsonMapper.ToObject(buffdata.text);}/// <summary>/// 根据buff的Id 获取buff的json数据/// </summary>/// <returns></returns>public string GetBuffJsonStr(int Id){if (Id > Enum.GetNames(typeof(BuffType)).Length - 1){Debug.LogError("Id超过buff上限,未配置对应的buff,请先配置");return null;}BuffType bt = (BuffType)Id;return GetBuffJsonStr(bt);}/// <summary>/// 根据buff的Id 获取buff的JsonData/// </summary>/// <returns></returns>public JsonData GetBuffJsonData(int Id){//buff数据string buffData = GetBuffJsonStr(Id);if (string.IsNullOrEmpty(buffData)){return null;}return JsonMapper.ToObject(buffData);}#endregion}

四、框架使用

buff数据

文中我放了三个不同类型的buff,具体的json如下图
在这里插入图片描述

Json数据以及工具

json如果太长看不太明白可以用在线解析工具
解析的如下图
在这里插入图片描述
这里我只讲几个比较关键的点,至于一眼能看懂的我就不详细说了。

ShowType

这里主要是后面接入UI准备(是否展示接口)
在这里插入图片描述

BuffType

这里也不需要多说,如果你要添加新的buff的话需要在这里创建一个新枚举,按照我下面创建的命名方式,创建的json文件放在下面的文件夹下(需要自行创建)
在这里插入图片描述
在这里插入图片描述

MountType

这个意思是你创建的脚本是否可以在同一个对象上挂载多个,如果你想能挂载无数个则用多挂载,如果想要单挂载跌层数则选择单挂载
在这里插入图片描述

BuffOverlap

这里主要是buff的叠加类型这里我创建了几个比较常用的方式,具体的逻辑是在BuffCtrlBase中的RepeatAdd方法和BuffOnStay方法
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

BuffShutDownType

这个参数也是为后面接入做准备留的接口,因为现在关闭其实都是有的,可以关闭多个也可以关闭一个,所以这里暂时是不需要,具体的方法都在BuffManager中。
在这里插入图片描述

BuffCalculateType

这里是关于buff回调执行的问题,如果是持续的buff则可以选择Loop在设置固定时间进行回调,如果只有一次(比如属性提升的buff)则可以选择Once。这里需要配合json的"m_Frequency"来使用,这里如果不为0并且 BuffCalculateType类型为Loop则相当于多少秒执行一次回调如下。

在这里插入图片描述
在这里插入图片描述

时间和层数这里也不过多说明了

"m_LimitTime": 0,
"m_TimingTime": 0,
"m_LimitLayer": 0,
"m_TimingLayer": 0,

这几个参数大概看下就明白了,具体逻辑也在BuffCtrlBase中
在这里插入图片描述

如何给生物添加buff

通过BuffManager来对生物添加移除buff,这里注意:需要挂载的生物是需要集成RoleAttribute的
在这里插入图片描述

五、总结

以上是我对网上一些面向过程的buff系统总结写出来的,如果有问题或者不明白的地方可以联系我,同事也感谢大家一直以来的支持。

相关文章:

Unity BuffSystem buff系统

Unity BuffSystem buff系统 一、介绍二、buff系统架构三、架构讲解四、框架使用buff数据Json数据以及工具ShowTypeBuffTypeMountTypeBuffOverlapBuffShutDownTypeBuffCalculateType时间和层数这里也不过多说明了如何给生物添加buff 五、总结 一、介绍 现在基本做游戏都会需要些…...

Android rom定制 修改system分区的容量大小

1、写在前面 系统ROM定制化,预置app太多,会导致系统rom很大,原生系统system分区已经不够用了,要加大系统systemui分区 2.修改system分区的容量大小的核心类 device/mediatekprojects/$project/BoardConfig.mk build/make/core/Makefile3、修改system 分区的容量大小的核…...

速盾:服务器接入免备案CDN节点的好处有哪些

本文将探讨服务器接入免备案CDN节点的好处&#xff0c;包括提高网站的访问速度、增加网站的稳定性和可靠性、降低带宽成本等方面的优势。同时&#xff0c;还将提供一些相关问题的解答&#xff0c;帮助读者更好地了解这一技术。 随着互联网的迅猛发展&#xff0c;网站的访问速度…...

Redisson看门狗机制

一、背景 网上redis分布式锁的工具方法&#xff0c;大都满足互斥、防止死锁的特性&#xff0c;有些工具方法会满足可重入特性。如果只满足上述3种特性会有哪些隐患呢&#xff1f;redis分布式锁无法自动续期&#xff0c;比如&#xff0c;一个锁设置了1分钟超时释放&#xff0c;…...

【Java数据结构】双向 不带头 非循环 链表实现(模拟实现LinkedList类)

LinkedList底层实际上是双向、不带头结点、非循环的链表 链表的分类有八种&#xff0c;常用的有两种&#xff1a;一是单向、不带头结点、非循环的&#xff08;基本上网上的题型都是这种&#xff09;&#xff1b;二是双向、不带头结点、非循环&#xff08;LinkedList的底层实现…...

深度学习系列55:深度学习加速技术概述

总体有两个方向&#xff1a;模型优化 / 框架优化 1. 模型优化 1.1 量化 最常见的量化方法为线性量化&#xff0c;权重从float32量化为int8&#xff0c;将输入数据映射在[-128,127]的范围内。在 nvdia gpu&#xff0c;x86、arm 和 部分 AI 芯片平台上&#xff0c;均支持 8bit…...

使用python启动一个roslaunch文件

roslaunch 的实现源码主要位于 ROS 的 ros_comm 仓库中的 tools/roslaunch 目录下。源码主要由 Python 脚本和少量的 C 代码组成。 在Python程序中导入roslaunch包并启动一个ROS launch文件&#xff0c;你需要确保ROS环境已经设置好&#xff0c;并且相关的roslaunch包已经安装…...

JavaEE企业级应用软件开发—Spring框架入门学习笔记(一)

一、认识框架 实际开发中&#xff0c;随着业务的发展&#xff0c;软件系统变得越来越复杂&#xff0c;如果所有的软件都从底层功能开始开发&#xff0c;那将是一个漫长而繁琐的过程。此外&#xff0c;团队协作开发时&#xff0c;由于没有统一的调用规范&#xff0c;系统会出现大…...

ElasticSearch-SpringBoot整合ElasticSearch

六、SpringBoot整合ElasticSearch 1、浏览官方文档 1、查找跟ES客户端相关的文档 使用Java REST Client 选择Java Hight Level REST Client 2、创建项目的准备 1.找到原生的依赖 2.找到对象 3.分析这个类里面的方法 3、正式创建项目 1.创建工程 2.导入依赖 注意依赖版本…...

用云手机打造tiktok账号需要注意些什么?

随着tiktok平台的火热&#xff0c;越来越多的商家开始尝试更高效的tiktok运营方法。其中&#xff0c;tiktok云手机作为一种新科技引起了很多人的注意&#xff0c;那么用云手机运营tiktok需要注意些什么&#xff1f;下文将对此进行详细解析。 1. 不是所有的云手机都适合做tiktok…...

MySQL基础查询篇(9)-数学函数在查询中的应用

在MySQL数据库中&#xff0c;数学函数在查询中扮演了非常重要的角色。这些函数可以帮助我们进行各种数学计算和处理&#xff0c;使得我们能够更有效地处理和分析数据。本文将介绍一些常用的MySQL数学函数及其在查询中的应用。 1. ABS函数 ABS函数用于返回一个数值的绝对值。在…...

c#内置委托

C#语言中有许多内置的委托&#xff0c;其中一些是常用的&#xff0c;包括&#xff1a; Action&#xff1a;表示不带返回值的方法的委托。它可以接受多个参数&#xff0c;但不返回任何值。 Action<int, string> actionDelegate (x, y) > Console.WriteLine("Ac…...

【自动化测试】---Selenium+Java

1.自动化测试分类 接口自动化测试UI自动化测试&#xff08;移动端自动化测试、Web端自动化测试&#xff09; 2.选择Selenium作为web自动化工具原因&#xff08;面试题&#xff09; 开源免费支持多个浏览器支持多个系统支持多语言Selenium包提供很多供测试使用的API 3.自动化是什…...

uniapp新增一条数据增加一个折叠栏

//折叠栏 <uni-collapse classcollapse refcollapse><uni-collapse-item v-for"(item, index) in dataForm.beefCattleNums" :key"index" :title"item.fatCalfNum" classcollapse-item title-bordershow :borderfalse clicktoggleItem(…...

【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战

Netty强大特性之Native transports技术原理分析 背景介绍JNI概念介绍不同平台的JNI实现 使用Native transports库Maven的分类器&#xff08;Classifier&#xff09;使用Linux native transport使用MacOS/BSD native transport库构建native transport库Linux版本要求MacOS/BSD版…...

1-1 动手学深度学习v2-线性回归-笔记

简化核心模型 假设1: 影响房价的关键因素是卧室个数&#xff0c;卫生间个数和居住面积&#xff0c;记为 x 1 x_{1} x1​&#xff0c; x 2 x_{2} x2​&#xff0c; x 3 x_{3} x3​假设2: 成交价是关键因素的加权和 y w 1 x 1 w 2 x 2 w 3 x 3 b yw_{1}x_{1}w_{2}x_{2}w_{3…...

算法每日一题: 使用循环数组所有元素相等的最少秒数 | 哈希

大家好&#xff0c;我是星恒&#xff0c;今天给大家带来的是一道需要感觉规律的题目&#xff0c;只要读懂题目中的规律&#xff0c;就可以做出来了 这道题用到了哈希&#xff0c;还有一个关键点比较类似循环队列 题目&#xff1a;leetcode 2808 给你一个下标从 0 开始长度为 n…...

canvas实现涂鸦画板功能

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…...

6-3、T型加减速单片机程序【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;根据前两节内容&#xff0c;已完成所有计算工作&#xff0c;本节内容介绍具体单片机程序流程及代码 一、程序流程图 根据前两节文章内容可知&#xff0c;T型加减速的关键内容是运动类型的判断以及定时…...

Flutter组件 StatefulWidget、StatelessWidget 可继承写法

前言 学过Java的同学&#xff0c;应该都知道面向对象语言的三大特征&#xff0c;封装、继承、多态&#xff1b; Dart也是面向对象的语言&#xff0c;但是在Flutter中的很多组件都被下划线 _ 标记为私有&#xff0c;导致无法继承&#xff0c;本文将介绍一种非私有的创建组件写…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)

旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据&#xff01;该数据集源自2025年4月发表于《地理学报》的论文成果…...