Unity BuffSystem buff系统

Unity BuffSystem 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中看。

csharp 复制代码
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
}
csharp 复制代码
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,这样方便来管理。

csharp 复制代码
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的管理类。

csharp 复制代码
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系统总结写出来的,如果有问题或者不明白的地方可以联系我,同事也感谢大家一直以来的支持。

相关推荐
90后小陈老师2 小时前
Unity教学 项目2 2D闯关游戏
游戏·unity·游戏引擎
噗噗夹的TA之旅3 小时前
Unity Shader 学习20:URP LitForwardPass PBR 解析
学习·unity·游戏引擎·图形渲染·技术美术
nnsix3 小时前
Unity ReferenceFinder插件 多选资源查找bug解决
unity·游戏引擎·bug
gzroy5 小时前
Unity Shader Graph实现全息瞄准器
unity·游戏引擎
90后小陈老师8 小时前
Unity教学 基础介绍
unity·游戏引擎
90后小陈老师8 小时前
Unity教学 项目3 3D坦克大战
3d·unity·游戏引擎
秦奈10 小时前
Unity复习学习随笔(五):Unity基础
学习·unity·游戏引擎
nnsix10 小时前
Unity ReferenceFinder插件 窗口中选择资源时 同步选择Assets下的资源
java·unity·游戏引擎
麷飞花12 小时前
unity3d scene窗口选中物体, 在 hierarchy高光显示
unity·editor·unity3d·u3d·hierarchy
ۓ明哲ڪ12 小时前
Unity功能——关闭脚本自动编译(Unity2021.3)
unity·游戏引擎