Unity BuffSystem buff系统

news2024/9/24 9:28:31

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 FixedUpdate

    private 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 update
    void 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数据为null
        if (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系统总结写出来的,如果有问题或者不明白的地方可以联系我,同事也感谢大家一直以来的支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1439427.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源项目的三年,我的项目经历了哪些变化?

0.前言 自己一个项目写了三年&#xff0c;到底写了什么东西了&#xff0c;这个项目经历了哪些变化呢&#xff1f;其中的心路历程如何&#xff1f; 兄弟们&#xff0c;要是感觉我的项目有价值&#xff0c;去b站给俺点点关注呐。我更新的更快。点击下面的了解就可以跳转去b站。…

电路设计(14)——奥运纪念日显示装置的proteus仿真

1.设计要求 北京奥运于2008年8月8日开幕&#xff0c;假设倒计时还剩69天&#xff0c;请你&#xff0c;制作一个电子作品&#xff0c;用以显示上述意思 采用三个数码管&#xff0c;其中一个数码管反复显示2008 8.8&#xff1b;该数码管下方并排放置另两个数码管&#xff0c;这二…

PyTorch 2.2 中文官方教程(十一)

使用 PyTorch C 前端 原文&#xff1a;pytorch.org/tutorials/advanced/cpp_frontend.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 PyTorch C 前端是 PyTorch 机器学习框架的纯 C 接口。虽然 PyTorch 的主要接口自然是 Python&#xff0c;但这个 Python API 坐…

【flink状态管理(2)各状态初始化入口】状态初始化流程详解与源码剖析

文章目录 1. 状态初始化总流程梳理2.创建StreamOperatorStateContext3. StateInitializationContext的接口设计。4. 状态初始化举例&#xff1a;UDF状态初始化 在TaskManager中启动Task线程后&#xff0c;会调用StreamTask.invoke()方法触发当前Task中算子的执行&#xff0c;在…

嵌入式学习之Linux入门篇笔记——15,Linux编写第一个自己的命令

配套视频学习链接&#xff1a;http://【【北京迅为】嵌入式学习之Linux入门篇】 https://www.bilibili.com/video/BV1M7411m7wT/?p4&share_sourcecopy_web&vd_sourcea0ef2c4953d33a9260910aaea45eaec8 1.什么是命令&#xff1f; 命令就是可执行程序。 比如 ls -a…

专栏《数据结构与算法:初学者入门指南》序言

&#x1f389;&#x1f389;欢迎光临我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入…

解决flex gap兼容性问题

前言 一个项目写下来&#xff0c;在网页端预览的时候正常&#xff0c;结果到产品经理手上。 设计稿样式 实际产品手机上样式 产品&#xff1a;“你这玩意儿怎么没间距&#xff1f;” 我&#xff1a;“为什么我的正常&#xff1f;&#xff1f;&#xff1f;呐呐呐你看我手机&a…

CDN相关和HTTP代理

CDN相关和HTTP代理 参考&#xff1a; 《透视 HTTP 协议》——chrono 把这两个放在一起是因为容易搞混&#xff0c;我一开始总以为CDN就是HTTP代理&#xff0c;但是看了极客时间里透视HTTP协议的讲解&#xff0c;感觉又不仅于此&#xff0c;于是专门写下来。 先说结论&#xf…

Redis篇之redis是单线程

一、redis是单线程 Redis是单线程的&#xff0c;但是为什么还那么快&#xff1f;主要原因有下面3点原因&#xff1a; 1. Redis是纯内存操作&#xff0c;执行速度非常快。 2. 采用单线程&#xff0c;避免不必要的上下文切换可竞争条件&#xff0c;多线程还要考虑线程安全问题。 …

YOLOv8改进 | 利用训练好权重文件计算YOLOv8的FPS、推理每张图片的平均时间(科研必备)

一、本文介绍 本文给大家带来的改进机制是利用我们训练好的权重文件计算FPS,同时打印每张图片所利用的平均时间,模型大小(以MB为单位),同时支持batch_size功能的选择,对于轻量化模型的读者来说,本文的内容对你一定有帮助,可以清晰帮你展示出模型速度性能的提升以及轻量…

python coding with ChatGPT 打卡第18天| 二叉树:从中序与后序遍历序列构造二叉树、最大二叉树

相关推荐 python coding with ChatGPT 打卡第12天| 二叉树&#xff1a;理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 python coding with ChatGPT 打卡第15天| 二叉树&#xff1a;翻转…

在Visual Studio中引用和链接OpenSceneGraph (OSG) 库

在Visual Studio中引用和链接OpenSceneGraph (OSG) 库&#xff0c;按照以下步骤操作&#xff1a; 构建或安装OSG库 下载OpenSceneGraph源代码&#xff08;如3.0版本&#xff09;并解压。使用CMake配置项目&#xff0c;为Visual Studio生成解决方案文件。通常您需要设置CMake中的…

ctfshow-命令执行(web73-web77)

web73 用不了上一题的通用poc了 因为禁用了strlen 但是可以改一个函数自定义一个函数只要是能实现strlen效果即可 cvar_export(scandir(/));exit(0); 根目录下有一个flagc.txt文件 cinclude(/flagc.txt);exit(0); web74 禁用了scandir函数 那就使用web72的glob协议 查看目录下…

Wireshark不显示Thrift协议

使用Wireshark对thrift协议进行抓包&#xff0c;但是只显示了传输层的tcp协议&#xff1a; "右键" -> "Decode As" 选择thrift的tcp端口 将“当前”修改为Thrift&#xff0c;然后点击“确定” 设置后&#xff0c;可以发现Wireshark里面显示的协议从Tcp变…

【每日一题】LeetCode——链表的中间结点

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…

Unity3d Shader篇(五)— Phong片元高光反射着色器

文章目录 前言一、Phong片元高光反射着色器是什么&#xff1f;1. Phong片元高光反射着色器的工作原理2. Phong片元高光反射着色器的优缺点优点缺点 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数 三、效果四、总…

vue对于安装依赖时不好习惯的反省

因为一个不好的习惯&#xff0c;我总是喜欢–save去安装依赖包&#xff0c;然后发现最后打包后的内容总是很大。就想着怎么能让包小一些&#xff0c;就发现我遗漏了vue安装依赖的一个小知识点 安装依赖的时候可以-s -d -g去安装&#xff0c;要根据使用的内容选择去安装&#xf…

第一个 Angular 项目 - 静态页面

第一个 Angular 项目 - 静态页面 之前的笔记&#xff1a; [Angular 基础] - Angular 渲染过程 & 组件的创建 [Angular 基础] - 数据绑定(databinding) [Angular 基础] - 指令(directives) 这是在学完了上面这三个内容后能够完成的项目&#xff0c;目前因为还没有学到数…

【漏洞复现】多语言药房管理系统MPMS文件上传漏洞

Nx01 产品简介 多语言药房管理系统 (MPMS) 是用 PHP 和 MySQL 开发的, 该软件的主要目的是在药房和客户之间提供一套接口&#xff0c;客户是该软件的主要用户。该软件有助于为药房业务创建一个综合数据库&#xff0c;并根据到期、产品等各种参数提供各种报告。 Nx02 漏洞描述 …

【服务器数据恢复】HP EVA虚拟化磁盘阵列数据恢复原理方案

EVA存储结构&原理&#xff1a; EVA是虚拟化存储&#xff0c;在工作过程中&#xff0c;EVA存储中的数据会不断地迁移&#xff0c;再加上运行在EVA上的应用都比较繁重&#xff0c;磁盘负载高&#xff0c;很容易出现故障。EVA是通过大量磁盘的冗余空间和故障后rss冗余磁盘动态…