0
点赞
收藏
分享

微信扫一扫

[Unity] 战斗系统学习 11:Buff 框架 1

未定义变量 2022-04-17 阅读 85

1. Time

一开始我是希望有一个 ScriptableObject 可以用来计时的
对于一些需要持续计时的事情可以用

1.1 ScriptableTimer

Assets/MeowFramework/Core/Scriptable/ScriptableTimer/ScriptableTimer.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 02/04/2022 23:19
// 最后一次修改于: 11/04/2022 10:31
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.Scriptable
{
    /// <summary>
    /// 计时器
    /// </summary>
    [InlineEditor]
    [CreateAssetMenu(menuName = "MeowFramework/Scriptable Timer/Create Scriptable Timer")]
    public class ScriptableTimer : SerializedScriptableObject
    {
        /// <summary>
        /// 是否暂停
        /// </summary>
        [ShowInInspector]
        private bool isPasue;
        
        /// <summary>
        /// 是否暂停
        /// </summary>
        public bool IsPasue => isPasue;
        
        /// <summary>
        /// 是否停止
        /// </summary>
        [ShowInInspector]
        private bool isStop;
        
        /// <summary>
        /// 是否停止
        /// </summary>
        public bool IsStop => isStop;
        
        /// <summary>
        /// 流逝时间
        /// </summary>
        [ShowInInspector]
        private float elapsedTime;
        
        /// <summary>
        /// 流逝时间
        /// </summary>
        public float ElapsedTime 
        {
            get => elapsedTime;
            set
            {
                if (!isStop && !isPasue) 
                    elapsedTime = value;
            }
        }

        /// <summary>
        /// 时长
        /// </summary>
        [ShowInInspector]
        private float duration;
        
        /// <summary>
        /// 时长
        /// </summary>
        public float Duration => duration;

        /// <summary>
        /// 是否循环
        /// </summary>
        [ShowInInspector]
        private bool isLoop;
        
        /// <summary>
        /// 是否循环
        /// </summary>
        public bool IsLoop => isLoop;
        
        /// <summary>
        /// 委托回调
        /// </summary>
        [ShowInInspector]
        private Action<object[]> callback;
        
        /// <summary>
        /// 回调参数
        /// </summary>
        private object[] args;

        /// <summary>
        /// 计时器的构造函数
        /// </summary>
        /// <param name="duration">时长</param>
        /// <param name="isLoop">是否循环</param>
        /// <param name="callback">委托回调</param>
        /// <param name="args">回调参数</param>
        public ScriptableTimer(float duration, bool isLoop, Action<object[]> callback,
            params object[] args)
        {
            this.isPasue = true;
            this.isStop = false;
            this.duration = duration;
            this.isLoop = isLoop;
            this.callback = callback;
            this.args = args;
        }

        /// <summary>
        /// 重置计时器
        /// </summary>
        public void Reset()
        {
            elapsedTime = 0;
        }

        /// <summary>
        /// 启动计时器
        /// </summary>
        public void Start()
        {
            isPasue = false;
        }
        
        /// <summary>
        /// 暂停计时器
        /// </summary>
        public void Pause()
        {
            isPasue = true;
        }
        
        /// <summary>
        /// 停止计时器
        /// </summary>
        public void Stop()
        {
            callback?.Invoke(args);
            if (isLoop)
            {
                elapsedTime -= duration;
            }
            else
            {
                isPasue = true;
                isStop = true;
            }
        }
    }
}

1.2 ScriptableTimerManager

Assets/MeowFramework/Core/Scriptable/ScriptableTimer/ScriptableTimerManager.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 02/04/2022 23:14
// 最后一次修改于: 11/04/2022 10:31
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.Scriptable
{
    /// <summary>
    /// 可资产化计时器管理器
    /// </summary>
    [InlineEditor]
    [CreateAssetMenu(menuName = "MeowFramework/Scriptable Timer/Create Scriptable Timer Manager")]
    public class ScriptableTimerManager : SerializedScriptableObject
    {
        /// <summary>
        /// 可资产化计时器管理器的时间缩放比例
        /// </summary>
        private float timeScale = 1f;
        
        /// <summary>
        /// 可资产化计时器管理器的时间缩放比例
        /// </summary>
        public float TimeScale => timeScale;

        /// <summary>
        /// 计时器列表 可以在 ForEach 中删除元素
        /// </summary>
        public static List<ScriptableTimer> ScriptableTimerList = new List<ScriptableTimer>();
        
        /// <summary>
        /// 创建计时器
        /// </summary>
        /// <param name="duration">时长</param>
        /// <param name="isLoop">是否循环</param>
        /// <param name="callback">回调函数</param>
        /// <returns></returns>
        public ScriptableTimer CreateScriptableTimer(float duration, bool isLoop, Action<object[]> callback)
        {
            return CreateScriptableTimer(duration, isLoop, callback, null);
        }
        
        /// <summary>
        /// 创建计时器
        /// </summary>
        /// <param name="duration">时长</param>
        /// <param name="isLoop">是否循环</param>
        /// <param name="callback">回调函数</param>
        /// <param name="args">回调参数</param>
        /// <returns></returns>
        public ScriptableTimer CreateScriptableTimer(float duration, bool isLoop, Action<object[]> callback,
            params object[] args)
        {
            if (duration < 0f)
                return null;
            var timer =  new ScriptableTimer(duration, isLoop, callback, args);
            ScriptableTimerList.Add(timer);
            return timer;
        }

        /// <summary>
        /// 更新计时器
        /// </summary>
        private void UpdateAllScriptableTimers()
        {
            // 从尾到头遍历,可以方便在遍历中删除元素
            for (int i = ScriptableTimerList.Count; i >= 0; --i)
            {
                ScriptableTimerList[i].ElapsedTime += Time.deltaTime * timeScale;
                if (ScriptableTimerList[i].ElapsedTime >= ScriptableTimerList[i].Duration)
                    ScriptableTimerList[i].Stop();
            }
        }
    }
}

但是后来我悟了,想要记录一个时间,完全可以用一个 ScriptableFloatVariable
要存的委托在游戏退出之后应该都会丢失
所以这两个类就显得很鸡肋了

1.3 TimeComponent v1

所以关于时间唯一需要特意写的就是运行时的数据
运行时的数据就是一个时间缩放系数
虽然也可以做成 ScriptableDictionary……但是不知道有什么需求,就先搁置把

Assets/MeowFramework/Core/FrameworkComponent/TimeComponent.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 12/04/2022 17:16
// 最后一次修改于: 12/04/2022 17:35
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.FrameworkComponent
{
    public class TimeComponent : BaseComponent
    {
        /// <summary>
        /// 时间缩放系数字典
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("时间缩放系数字典")]
        public static Dictionary<string, float> TimeScaleList = new Dictionary<string, float>();
        
    }
}

然后我希望在 ScriptableBuff 中写个 string 记录这个键

        /// <summary>
        /// 时间缩放系数在时间缩放系数字典中的字符串键
        /// </summary>
        [ShowIf("@DurationType == BuffDurationType.Durable || DurationType == BuffDurationType.Infinite")]
        [BoxGroup("Time")]
        [Tooltip("时间缩放系数在时间缩放系数字典中的字符串键")]
        public string TimeScaleName = "";

但是这样做的话有一个问题就是,每当我申请一个 string 键之后,如果这个键不再使用了,那么我还要设计一套 GC 回收这个键
还有可能有共用的问题,比如原来一个技能 A1 给敌人的 Buff1 的时间缩放系数命名为 T1,那么如果我给敌人堆 E1 加上了 Buff1,再给敌人堆 E2 加上 Buff1 ,我希望这两个敌人堆的时间缩放系数是不同的,但是由于 Buff1 的时间缩放系数名字我已经写好了,所以我还需要多一步操作,在释放 Buff 的时候能够修改时间缩放系数的名字
所以我想想还是不做这个了

2. Buff

2.1 ScriptableBuff v1

ScriptableBuff 负责存 Buff 初始化数据

Assets/MeowFramework/Core/Scriptable/ScriptableBuff/ScriptableBuff.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 27/03/2022 9:51
// 最后一次修改于: 12/04/2022 19:39
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System.Collections.Generic;
using FlowCanvas;
using MeowFramework.Core.FrameworkComponent;
using NodeCanvas.Framework;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.Scriptable
{
    /// <summary>
    /// 可资产化 Buff
    /// </summary>
    [CreateAssetMenu(fileName = "New Scriptable Buff", menuName = "MeowFramework/Scriptable Buff/Create Scriptable Buff")]
    public class ScriptableBuff : SerializedScriptableObject
    {
        /// <summary>
        /// Buff ID
        /// </summary>
        [BoxGroup("Basic")]
        [ValidateInput("IDValidate")]
        [Tooltip("Buff ID")]
        public int BuffID;
        
        /// <summary>
        /// 俗名
        /// </summary>
        [BoxGroup("Basic")]
        [Tooltip("俗名")]
        public string FriendlyName;
        
        /// <summary>
        /// 概述
        /// </summary>
        [BoxGroup("Basic")]
        [TextArea]
        [Tooltip("概述")]
        public string Description = "";
        
        /// <summary>
        /// Buff FlowScript
        /// </summary>
        [BoxGroup("Basic")]
        [Tooltip("FlowScript")]
        public FlowScript BuffFlowScript;
        
        /// <summary>
        /// 堆叠层数限制
        /// </summary>
        [EnumToggleButtons]
        [BoxGroup("Layer")]
        [Tooltip("堆叠层数限制")]
        public BuffLayerStackLimitType LayerStackLimitType;

        /// <summary>
        /// 最大堆叠层数
        /// </summary>
        [ShowIf("@LayerStackLimitType == BuffLayerStackLimitType.Limited")]
        [ValidateInput("MaxLayersValidate")]
        [BoxGroup("Layer")]
        [Tooltip("最大堆叠层数")]
        public int MaxLayers;

        /// <summary>
        /// 指令持续时间种类
        /// </summary>
        [EnumToggleButtons]
        [BoxGroup("Time")]
        [Tooltip("指令持续时间种类")]
        public BuffDurationType DurationType;

        /// <summary>
        /// 指令持续时间
        /// </summary>
        [ShowIf("DurationType",BuffDurationType.Durable)]
        [BoxGroup("Time")]
        [ValidateInput("DurationValidate")]
        [Tooltip("指令持续时间")]
        public float Duration;

        /// <summary>
        /// FlowScript 更新模式
        /// </summary>
        [EnumToggleButtons]
        [BoxGroup("Time")]
        [Tooltip("FlowScript 更新模式")]
        public Graph.UpdateMode UpdateMode = Graph.UpdateMode.NormalUpdate;
            
        /// <summary>
        /// Buff 元素 Tag 字典
        /// </summary>
        [Tooltip("元素标签字典")]
        public Dictionary<ElementType, bool> ElementTypeTagDictionary = new Dictionary<ElementType, bool>
        {
            {ElementType.Pyro, false},
            {ElementType.Hydro, false},
            {ElementType.Anemo, false},
            {ElementType.Electro, false},
            {ElementType.Cryo, false},
            {ElementType.Geo, false},
        };

        /// <summary>
        /// 初始时注册 Buff ID
        /// </summary>
        private void OnEnable()
        {
            // 根据新的 ID 添加键值对
            BuffComponent.ScriptableBuffDictionary[BuffID] = this;
        }

        /// <summary>
        /// 验证函数:是否为非负数
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private bool IDValidate(int value) => value >= 0;

        /// <summary>
        /// 验证函数:是否为正数
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private bool MaxLayersValidate(int value) => value > 0;
        
        /// <summary>
        /// 验证函数:是否为非负数
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private bool DurationValidate(float value) => value >= 0;
    }
}

本来想加一个初始层数的
现在想想似乎这个是要在 BornBuff 里面配置的
再一想想,其实在 TryAddBuff 里面提供可以叠加的层数,然后在 ActorEntity 的 OnStart 里面用 TryAddBuff 就行了
所以 ScriptableBuff 和 Actor 都不需要初始层数这个东西了,Actor更是不需要初始 Buff 这东西了

2.2 FlowScriptEntity v1

FlowScriptEntity 是所有逻辑依赖于 FlowScript 实现的实体的基类

Assets/MeowFramework/Core/Entity/FlowScriptEntity.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 17:49
// 最后一次修改于: 12/04/2022 0:17
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using FlowCanvas;
using Sirenix.OdinInspector;

namespace MeowFramework.Core.Entity
{
    /// <summary>
    /// 挂载 FlowScript 的实体
    /// </summary>
    public class FlowScriptEntity : SerializedMonoBehaviour
    {
        /// <summary>
        /// FlowScript 控制器
        /// </summary>
        public FlowScriptController flowScriptController;
        
        private void Awake()
        {
            flowScriptController = GetComponent<FlowScriptController>();
        }
    }
}

2.3 ActorEntity v1

ActorEntity 是可以保存 Buff 的实体

Assets/MeowFramework/Core/Entity/ActorEntity.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 12/04/2022 14:44
// 最后一次修改于: 12/04/2022 20:36
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System.Collections.Generic;
using UnityEngine;

namespace MeowFramework.Core.Entity
{
    public class ActorEntity : FlowScriptEntity
    {
        /// <summary>
        /// 运行时的 Buff 的字典
        /// </summary>
        [Sirenix.OdinInspector.ReadOnly]
        [Tooltip("运行时的 Buff 的字典")]
        public Dictionary<int, BuffEntity> AliveBuffDictionary = new Dictionary<int, BuffEntity>();
    }
}

本来想用 private List<BuffEntity> aliveBuffList = new List<BuffEntity>();
但是想到要方便某一类型的 Buff 的查找,还是根据 Buff 的 BuffID 作为 Key 比较好

2.4 BuffEntity v1

BuffEntity 是 Buff 执行逻辑的实体

Assets/MeowFramework/Core/Entity/BuffEntity.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 23:41
// 最后一次修改于: 12/04/2022 20:28
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System;
using MeowFramework.Core.Scriptable;
using NodeCanvas.Framework;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.InputSystem.XR.Haptics;

namespace MeowFramework.Core.Entity
{
    /// <summary>
    /// 挂载 FlowScript 的实体
    /// </summary>
    public partial class BuffEntity : FlowScriptEntity
    {
        /// <summary>
        /// 可资产化 Buff
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("可资产化 Buff")]
        private ScriptableBuff scriptableBuff;
        
        /// <summary>
        /// Buff 释放者
        /// 不考虑释放着为多人的情况
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("Buff 释放者")]
        private ActorEntity caster;

        /// <summary>
        /// Buff 释放者
        /// 不考虑释放着为多人的情况
        /// </summary>
        public ActorEntity Caster
        {
            get => caster;
            set
            {
                AfterCasterChange?.Invoke(caster, value);
                caster = value;
            }
        }
        
        /// <summary>
        /// Buff 接受者
        /// 不考虑接受者为多人的情况
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("Buff 接受者")]
        private ActorEntity receiver;

        /// <summary>
        /// Buff 接受者
        /// 不考虑接受者为多人的情况
        /// </summary>
        public ActorEntity Receiver
        {
            get => receiver;
            set
            {
                AfterReceiverChange?.Invoke(receiver, value);
                receiver = value;
            }
        }

        /// <summary>
        /// 层级
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("层级")]
        private int layer;

        /// <summary>
        /// 层级
        /// </summary>
        public int Layer
        {
            get => layer;
            set
            {
                // 如果有层级限制,并且超过了层级限制,那么触发层级变化失败委托
                if (scriptableBuff.LayerStackLimitType == BuffLayerStackLimitType.Limited &&
                    value > scriptableBuff.MaxLayers)
                {
                    AfterLayerChangeFailure?.Invoke(layer, value);
                    return;
                }
                // 否则触发层级变化成功委托
                AfterLayerChangeSuccess?.Invoke(layer, value);
                layer = value;
            }
        }

        /// <summary>
        /// 时长
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("时长")]
        private float duration;

        /// <summary>
        /// 时长
        /// 允许将时长设置为 0
        /// </summary>
        public float Duration
        {
            get => duration;
            set
            {
                var validValue = Mathf.Clamp(value, 0, float.MaxValue);
                AfterDurationChange?.Invoke(duration, validValue);
                duration = validValue;
            }
        }

        /// <summary>
        /// 已流逝时间
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("已流逝时间")]
        private float elapsedTime;

        /// <summary>
        /// 已流逝时间
        /// </summary>
        public float ElapsedTime
        {
            get => elapsedTime;
            set
            {
                elapsedTime = value;
                if (elapsedTime < 0)
                {
                    elapsedTime += Duration;
                    Layer -= 1;
                    AfterOneLayerTimeRunOut(Layer);
                    if (Layer == 0 && scriptableBuff.DurationType == BuffDurationType.Durable)
                        EndBuff();
                }
            }
        }

        /// <summary>
        /// FlowScript 更新模式
        /// </summary>
        [ShowInInspector]
        [ReadOnly]
        [Tooltip("已流逝时间")]
        private Graph.UpdateMode updateMode;

        /// <summary>
        /// FlowScript 更新模式
        /// </summary>
        public Graph.UpdateMode UpdateMode
        {
            get => updateMode;
            set
            {
                AfterUpdateModeChange?.Invoke();
                updateMode = value;
            }
        }
        
        /// <summary>
        /// 释放者改变时触发的委托
        /// </summary>
        [HideInInspector]
        public Action<ActorEntity, ActorEntity> AfterCasterChange;

        /// <summary>
        /// 接受者改变时触发的委托
        /// </summary>
        [HideInInspector]
        public Action<ActorEntity, ActorEntity> AfterReceiverChange;
        
        /// <summary>
        /// 层级变化失败时触发的委托
        /// </summary>
        [HideInInspector]
        public Action<int, int> AfterLayerChangeFailure; 
        
        /// <summary>
        /// 层级变化成功时触发的委托
        /// </summary>
        [HideInInspector]
        public Action<int, int> AfterLayerChangeSuccess;

        /// <summary>
        /// 时长变化成功时触发的委托
        /// </summary>
        [HideInInspector]
        public Action<float, float> AfterDurationChange;
        
        /// <summary>
        /// 每个层级时间耗尽时
        /// 采用每层时间独立计算
        /// 不考虑多层 Buff 只有一个时间的情况
        /// 可以在触发时间耗尽事件时将层数清零来实现多层 Buff 只有一个时间
        /// </summary>
        [HideInInspector]
        public Action<int> AfterOneLayerTimeRunOut;

        /// <summary>
        /// FlowScript 更新模式改变之后触发的委托
        /// </summary>
        public Action AfterUpdateModeChange;
    }
}

Assets/MeowFramework/Core/Entity/BuffEntity.Flow.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 12/04/2022 19:31
// 最后一次修改于: 12/04/2022 20:42
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using System;
using MeowFramework.Core.Scriptable;
using NodeCanvas.Framework;
using UnityEngine;

namespace MeowFramework.Core.Entity
{
    /// <summary>
    /// 挂载 FlowScript 的实体
    /// </summary>
    public partial class BuffEntity
    {

        /// <summary>
        /// 初始化 Buff
        /// </summary>
        public void BuffInitialize(ActorEntity caster, ActorEntity receiver, ScriptableBuff scriptableBuff, int layer = 0)
        {
            this.caster = caster;
            this.receiver = receiver;
            this.scriptableBuff = scriptableBuff;
            this.layer = layer;
            updateMode = scriptableBuff.UpdateMode;
        }
        
        /// <summary>
        /// 启动 Buff
        /// </summary>
        public void StartBuffFlow()
        {
            flowScriptController.StartBehaviour(updateMode);
        }

        /// <summary>
        /// 更新 Buff
        /// </summary>
        public void UpdateBuffFlow()
        {
            flowScriptController.UpdateBehaviour();
        }
        
        /// <summary>
        /// 暂停 Buff
        /// </summary>
        public void PauseBuffFlow()
        {
            flowScriptController.PauseBehaviour();
        }
        
        /// <summary>
        /// 结束 Buff
        /// </summary>
        public void StopBuffFlow()
        {
            flowScriptController.StopBehaviour();
        }

        /// <summary>
        /// 重置 Buff
        /// </summary>
        public void ResetBuffFlow()
        {
            flowScriptController.RestartBehaviour();
        }

        /// <summary>
        /// Buff 结束
        /// </summary>
        public void EndBuff()
        {
            GameObject.Destroy(this);
        }
    }
}

2.5 BuffUtility v1

BuffUtility 是 Buff 执行逻辑的通用函数

Assets/MeowFramework/Core/Utility/BuffUtility.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 23:27
// 最后一次修改于: 12/04/2022 20:42
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using FlowCanvas;
using MeowFramework.Core.Entity;
using MeowFramework.Core.FrameworkComponent;
using UnityEngine;

namespace MeowFramework.Core.Utility
{
    public static class BuffUtility
    {
        /// <summary>
        /// 尝试释放 Buff
        /// </summary>
        /// <param name="caster">Buff 释放者</param>
        /// <param name="receiver">Buff 接受者</param>
        /// <param name="buffID"> Buff ID</param>
        /// <returns>Buff 实体</returns>
        public static BuffEntity TryAddBuff(ActorEntity caster, ActorEntity receiver, int buffID, int layer)
        {
            // 要检查这个 Buff 是否已经被生成了
            // 如果每一次 TryAddBuff 都生成一个 Buff 物体,那就没办法做到层数的叠加
            // 也不用在 root 下面找,因为可能会有很多 Buff
            // 所以那就直接找 receiver 吧
            // 所以要约定 receiver 不为 null
            if (receiver == null)
            {
                Debug.LogError($"{caster} 释放的 ID 为 {buffID} 的 Buff 没有接受者!");
                return null;
            }
            
            // 如果没有这个 Buff,就返回空
            if (!BuffComponent.ScriptableBuffDictionary.ContainsKey(buffID))
            {
                Debug.LogError($"{caster} 释放的 ID 为 {buffID} 的 Buff 在 Buff 组件的字典中不存在!");
                return null;
            }

            // 如果接受者身上已经有了相同 id 的 buff,那么直接增加层数
            if (receiver.AliveBuffDictionary.ContainsKey(buffID))
            {
                var buff = receiver.AliveBuffDictionary[buffID];
                buff.Layer += layer;
                return buff;
            }
            
            // 接受者身上没有相同 id 的 buff
            // 获得 Buff 数据
            var scriptableBuff = BuffComponent.ScriptableBuffDictionary[buffID];

            if(!BuffComponent.BuffPoolRoot)
                Debug.LogError("Buff 组件下面没有对象池的根节点!");
            
            // 创建空物体作为 Buff 物体
            GameObject entity = new GameObject();
            
            // Buff 物体放在统一的 root 下
            entity.transform.SetParent(BuffComponent.BuffPoolRoot);
            entity.name = scriptableBuff.FriendlyName == "" ? "NewBuffEntity" : scriptableBuff.FriendlyName + "Entity";
            
            // 初始化 FlowScript 控制器
            FlowScriptController flowScriptController = entity.AddComponent<FlowScriptController>();
            flowScriptController.StopBehaviour();
            flowScriptController.behaviour = scriptableBuff.BuffFlowScript;
            
            // 为 Buff 物体添加 BuffEntity,方便控制
            var buffEntity =  entity.AddComponent<BuffEntity>();
            buffEntity.BuffInitialize(caster, receiver, scriptableBuff, layer);
            
            // 执行 Buff
            buffEntity.StartBuffFlow();
            
            return buffEntity;
        }
    }
}
举报

相关推荐

0 条评论