[Unity] 战斗系统学习 9:构建 TPS 框架 4

1. 技能框架

我的需求是要在 FlowScript 中写技能,然后在角色中引用这个 FlowScript,当需要释放技能的时候就启用这个 FlowScript

1.1 ScriptableAbility v1

ScriptableAbility 是用来存代表技能内容的 FlowScript 的
之后可能还会有其他功能

Assets/MeowFramework/Core/Scriptable/ScriptableAbility/ScriptableAbility.cs

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

using FlowCanvas;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.Scriptable
{
    /// 
    /// 可资产化技能
    /// 
    [CreateAssetMenu(fileName = "New Scriptable Ability",
        menuName = "MeowFramework/Scriptable Ability/Create Scriptable Ability")]
    public class ScriptableAbility : SerializedScriptableObject
    {
        /// 
        /// 技能 ID
        /// 
        [ValidateInput("IDValidate")]
        [Tooltip("技能 ID")]
        public int AbilityID;

        /// 
        /// 俗名
        /// 
        [Tooltip("俗名")]
        public string FriendlyName;

        /// 
        /// 概述
        /// 
        [TextArea]
        [Tooltip("概述")]
        public string Description = "";
        
        /// 
        /// 技能 FlowScript
        /// 
        [Required]
        [Tooltip("技能 FlowScript")]
        public FlowScript AbilityFlowScript;

        /// 
        /// 验证函数:是否为非负数
        /// 
        /// 
        /// 
        private bool IDValidate(int value) => value >= 0;
    }
}

1.2 AbilityEntity v1

为了让技能的 FlowScript 能够执行,需要有一个 FlowScriptController,而 FlowScriptController 又需要挂在一个物体上,因此,一个技能实体需要一个空物体,空物体上面要挂一个 FlowScriptController,这个 FlowScriptController 的 FlowScript 要赋为 ScriptableAbility 中设置好的 FlowScript

Assets/MeowFramework/Core/Entity/AbilityEntity.cs

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

using FlowCanvas;
using Sirenix.OdinInspector;

namespace MeowFramework.Core.Entity
{
    public class AbilityEntity : SerializedMonoBehaviour
    {
        /// 
        /// FlowScript 控制器
        /// 
        private FlowScriptController flowScriptController;
        
        private void OnEnable()
        {
            flowScriptController = GetComponent<FlowScriptController>();
        }

        /// 
        /// 启动技能
        /// 
        public void StartAbility()
        {
            flowScriptController.StartBehaviour();
        }

        /// 
        /// 暂停技能
        /// 
        public void PauseAbility()
        {
            flowScriptController.PauseBehaviour();
        }
        
        /// 
        /// 结束技能
        /// 
        public void StopAbility()
        {
            flowScriptController.StopBehaviour();
        }

        /// 
        /// 重置技能
        /// 
        public void ResetAbility()
        {
            flowScriptController.RestartBehaviour();
        }
    }
}

有一点很怪的是,private Dictionary 在监视器上的设置没办法保存下来。
点开挂有 ActorBase 的 GameObject,在监视器中选择 ActorBase,为暴露出来的 Dictionary 添加一项,然后离开监视器界面,再点开原来的 GameObject,监视器中 ActorBase 的 Dictionary 又变为初始化的空值了
但是 public Dictionary 就不会
所以就,Odin 很神奇

1.3 ActorBase v1

实际释放技能的时候就是生成一个技能实体,然后调用这个技能实体的方法

Assets/MeowFramework/Core/Entity/Actor/ActorBase.cs

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

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

namespace MeowFramework.Core.Actor
{
    public class ActorBase : SerializedMonoBehaviour
    {
        /// 
        /// 血量
        /// 
        [BoxGroup("Attribute")]
        [Tooltip("血量")] 
        public ActorAttribute<float> HP = new ActorAttribute<float>();
        
        /// 
        /// 最大血量
        /// 
        [BoxGroup("Attribute")]
        [Tooltip("最大血量")] 
        public ActorAttribute<float> MaxHP = new ActorAttribute<float>();

        /// 
        /// 可用技能字典
        /// 
        [BoxGroup("GamePlay")]
        [Tooltip("可用技能字典")]
        public Dictionary<int,ScriptableAbility> availableAbilityDictionary = new Dictionary<int,ScriptableAbility>();

        /// 
        /// 出生时附加的 Buff 的字典
        /// 
        [BoxGroup("GamePlay")]
        [Tooltip("出生时附加的 Buff 的字典")]
        public Dictionary<int,ScriptableBuff> bornBuffDictionary = new Dictionary<int,ScriptableBuff>();

        /// 
        /// 运行时的 Buff 的列表
        /// 
        [BoxGroup("GamePlay")]
        [ShowInInspector]
        [Sirenix.OdinInspector.ReadOnly]
        [Tooltip("运行时的 Buff 的列表")]
        private List<int> aliveBuffList = new List<int>();
        
        /// 
        /// 尝试释放技能
        /// 
        /// 技能 ID
        /// 
        public bool TryCastAbility(int availableAbilityIndex)
        {
            // 如果没有这个技能,就返回假
            if (!availableAbilityDictionary.ContainsKey(availableAbilityIndex))
                return false;
            
            // 如果有这个技能,获得技能数据
            var scriptableAbility = availableAbilityDictionary[availableAbilityIndex];
            
            // 生成技能实体
            var abilityEntity = AbilityComponent.SpawnAbilityEntity(scriptableAbility);

            // 执行技能
            abilityEntity.StartAbility();
            
            return true;
        }
    }
}

1.4 AbilityComponent v2

后来我觉得其实没有必要使用 ID 来查找 ScriptableAbility 了
因为我是直接在 ActorBase 中就已经引用了 ScriptableAbility 的
所以接下来,对于 AbilityComponent 组件,要做的就只是生成技能实体的函数而已

Assets/MeowFramework/Core/FrameworkComponent/AbilityComponent.cs

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

using FlowCanvas;
using MeowFramework.Core.Entity;
using MeowFramework.Core.Scriptable;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.FrameworkComponent
{
    /// 
    /// 框架中的技能组件
    /// 
    [InlineEditor]
    public class AbilityComponent : BaseComponent
    {
        /// 
        /// 技能对象池的根节点
        /// 
        private static Transform AbilityPoolRoot;

        private void Start()
        {
            // 创建技能对象池的根节点
            GameObject root = new GameObject();
            root.name = "AbilityPoolRoot";
            root.transform.SetParent(transform);
            AbilityPoolRoot = root.transform;
        }

        /// 
        /// 生成一个技能实体
        /// 
        /// 可资产化技能
        /// 
        public static AbilityEntity SpawnAbilityEntity(ScriptableAbility scriptableAbility)
        {
            // 创建空物体作为 Ability 物体
            GameObject entity = new GameObject();
            // Ability 物体放在统一的 root 下
            entity.transform.SetParent(AbilityPoolRoot);
            // 初始化 FlowScript 控制器
            FlowScriptController flowScriptController = entity.AddComponent<FlowScriptController>();
            flowScriptController.StopBehaviour();
            flowScriptController.behaviour = scriptableAbility.AbilityFlowScript;
            // 为 Ability 物体添加 AbilityEntity,方便控制
            return entity.AddComponent<AbilityEntity>();
        }
    }
}

1.5 AbilityComponent v3

实际运行的时候我发现 AbilityComponent 的 Start 可能慢于其他脚本,AbilityPoolRoot 可能来不及赋值,导致别人在 Start 的时候用到 SpawnAbilityEntity 时 AbilityPoolRoot == null
于是我就想在监视器中配置 AbilityPoolRoot

Assets/MeowFramework/Core/FrameworkComponent/AbilityComponent.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 9:29
// 最后一次修改于: 11/04/2022 21:50
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------

using FlowCanvas;
using MeowFramework.Core.Entity;
using MeowFramework.Core.Scriptable;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.FrameworkComponent
{
    /// 
    /// 框架中的技能组件
    /// 
    [InlineEditor]
    public class AbilityComponent : BaseComponent
    {
        /// 
        /// 技能对象池的根节点
        /// 
        [Required]
        [ShowInInspector]
        [Tooltip("技能对象池的根节点")]
        private Transform abilityPoolRoot;

        /// 
        /// 技能对象池的根节点
        /// 
        public static Transform AbilityPoolRoot => AbilityPoolRoot;
        
        /// 
        /// 生成一个技能实体
        /// 
        /// 可资产化技能
        /// 
        public static AbilityEntity SpawnAbilityEntity(ScriptableAbility scriptableAbility)
        {
            // 创建空物体作为 Ability 物体
            GameObject entity = new GameObject();
            // Ability 物体放在统一的 root 下
            Debug.Log(AbilityPoolRoot);
            entity.transform.SetParent(AbilityPoolRoot);
            // 初始化 FlowScript 控制器
            FlowScriptController flowScriptController = entity.AddComponent<FlowScriptController>();
            flowScriptController.StopBehaviour();
            flowScriptController.behaviour = scriptableAbility.AbilityFlowScript;
            // 为 Ability 物体添加 AbilityEntity,方便控制
            return entity.AddComponent<AbilityEntity>();
        }
    }
}

实际用的时候还是会找到 null

[Unity] 战斗系统学习 9:构建 TPS 框架 4_第1张图片

好吧这是之前我见到的 static 变量不能通过监视器设置的问题

那就只能惰性求值了

[Unity] 战斗系统学习 9:构建 TPS 框架 4_第2张图片

但是写了之后发现原来 transform 是动态的
好吧这很合理

我想写一个静态属性,但是也拿不到

[Unity] 战斗系统学习 9:构建 TPS 框架 4_第3张图片

好吧后面才知道是用 Awake
根本没什么机会用,都忘了hhhh

Assets/MeowFramework/Core/FrameworkComponent/AbilityComponent.cs

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

using System;
using FlowCanvas;
using MeowFramework.Core.Entity;
using MeowFramework.Core.Scriptable;
using NodeCanvas.Tasks.Actions;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.FrameworkComponent
{
    /// 
    /// 框架中的技能组件
    /// 
    [InlineEditor]
    public class AbilityComponent : BaseComponent
    {
        /// 
        /// 技能对象池的根节点
        /// 
        private static Transform AbilityPoolRoot;

        private void Awake()
        {
            // 创建技能对象池的根节点
            GameObject root = new GameObject();
            root.name = "AbilityPoolRoot";
            root.transform.SetParent(transform);
            AbilityPoolRoot = root.transform;
        }

        /// 
        /// 生成一个技能实体
        /// 
        /// 可资产化技能
        /// 
        public static AbilityEntity SpawnAbilityEntity(ScriptableAbility scriptableAbility)
        {
            if(!AbilityPoolRoot)
                Debug.LogError("没有技能对象池的根节点!");
            
            // 创建空物体作为 Ability 物体
            GameObject entity = new GameObject();
            // Ability 物体放在统一的 root 下
            entity.transform.SetParent(AbilityPoolRoot);
            entity.name = scriptableAbility.FriendlyName == "" ? "NewAbilityEntity" : scriptableAbility.FriendlyName + "Entity";
            // 初始化 FlowScript 控制器
            FlowScriptController flowScriptController = entity.AddComponent<FlowScriptController>();
            flowScriptController.StopBehaviour();
            flowScriptController.behaviour = scriptableAbility.AbilityFlowScript;
            // 为 Ability 物体添加 AbilityEntity,方便控制
            return entity.AddComponent<AbilityEntity>();
        }
    }
}

2. Buff 框架

现在我也终于要做射击了
我在想,射击这个东西
是做成一个可以射击的 buff,然后这个 buff 的 flowscript 中写一个绑定 inputcontroller 的事件,连一个 cooldown,再连接到射击函数,比较好
还是单独做一个技能,在主角的 flowscript 中写一个绑定 inputcontroller 的事件,连一个 cooldown,再连接到射击技能,技能里面放装有射击函数的 flowscript,比较好

果然还是应该一个 buff 比较好,毕竟执行 flowscript 是需要生成一个空物体装 flowscriptcontroller 来执行的,如果是单独做一个技能的话,技能执行完就要删除掉生成的空物体,感觉对于射击这种高频事件不友好。虽然也可以用对象池,但是感觉其实也没必要
对于一个一直存在的 buff,就只需要生成一次空物体,加一次 flowscriptcontroller 就好了
相比而言 允许射击 buff 更贴合能力一点,因为 buff 后面要做 buff 之间的检查,打断,消除,什么的……思考

其实我犹豫的就是,我就是感觉,那要是这样的话,那么所有的技能其实都可以放到 buff 里面了
角色能够使用三个可触发的技能,那么就让角色出生的时候带三个 buff,这三个 buff 的 flowscript 中就是一个可触发的技能内容

那这样的话前面做的技能框架要改成 Buff 框架了

2.1 BuffDurationType v1

Buff 设置需要用到的枚举

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

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

namespace MeowFramework.Core.Scriptable
{
    /// 
    /// 可资产化 Buff 持续时间种类
    /// 
    public enum BuffDurationType
    {
        /// 
        /// 瞬间
        /// 
        Instant = 0,
        
        /// 
        /// 持续一帧
        /// 
        OneFrame,
        
        /// 
        /// 持续一段时间
        /// 
        Durable,
        
        /// 
        /// 无限时间
        /// 
        Infinite,
    }
}

2.2 ScriptableBuff v1

ScriptableBuff 保存 Buff 的设置

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

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

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

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

        /// 
        /// 最大堆叠层数
        /// 
        [ShowIf("@LayerStackLimit == BuffLayerStackLimitType.Limited")]
        [BoxGroup("Layer")]
        [Tooltip("最大堆叠层数")]
        public int MaxLayers;

        /// 
        /// 什么时候应该重置 Command
        /// 
        [EnumToggleButtons]
        [ShowIf("@LayerStackLimit == BuffLayerStackLimitType.Limited && MaxLayers == 0")]
        [BoxGroup("Layer")]
        [Tooltip("什么时候应该重置命令")]
        public BuffResetCommandType WhenShouldResetCommand;
        
        /// 
        /// 指令持续时间种类
        /// 
        [EnumToggleButtons]
        [BoxGroup("Time")]
        [Tooltip("指令持续时间种类")]
        public BuffDurationType DurationType;

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

        /// 
        /// 什么时候应该重置 ElapsedTime
        /// 
        [EnumToggleButtons]
        [ShowIf("@DurationType == BuffDurationType.Durable || DurationType == BuffDurationType.Infinite")]
        [BoxGroup("Time")]
        [Tooltip("什么时候应该重置已流逝时间")]
        public BuffResetElapsedTimeType WhenShouldResetElapsedTimeType;
        
        /// 
        /// 是否能够被打断
        /// 
        [ShowIf("@DurationType == BuffDurationType.Durable || DurationType == BuffDurationType.Infinite")]
        [BoxGroup("Time")]
        [Tooltip("是否能够被打断")]
        public bool CanBeInterrupted;
        
        /// 
        /// Buff 元素 Tag 字典
        /// 
        [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},
        };
        
        /// 
        /// Buff FlowScript
        /// 
        [Tooltip("FlowScript")]
        public FlowScript BuffFlowScript;

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

        /// 
        /// 验证函数:是否为非负数
        /// 
        /// 
        /// 
        private bool IDValidate(int value) => value >= 0;
        
        /// 
        /// 验证函数:是否为非负数
        /// 
        /// 
        /// 
        private bool DurationValidate(float value) => value >= 0;
    }
}

2.3 FlowScriptEntity v1

为了让 FlowScript 有一个挂靠的地方,所以要建一套 Entity 来承载

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
{
    /// 
    /// 挂载 FlowScript 的实体
    /// 
    public class FlowScriptEntity : SerializedMonoBehaviour
    {
        /// 
        /// FlowScript 控制器
        /// 
        public FlowScriptController flowScriptController;
        
        private void Awake()
        {
            flowScriptController = GetComponent<FlowScriptController>();
        }
    }
}

2.4 BuffEntity v1

BuffEntity 是可以解析 ScriptableBuff 中的设置的实体

Assets/MeowFramework/Core/Entity/BuffEntity.cs

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

using MeowFramework.Core.Scriptable;
using Sirenix.OdinInspector;
using UnityEngine;

namespace MeowFramework.Core.Entity
{
    /// 
    /// 挂载 FlowScript 的实体
    /// 
    public class BuffEntity : FlowScriptEntity
    {
        /// 
        /// Buff 释放者
        /// 
        [ShowInInspector]
        [Sirenix.OdinInspector.ReadOnly]
        [Tooltip("Buff 释放者")]
        private ActorBase caster;

        /// 
        /// Buff 接受者
        /// 
        [ShowInInspector]
        [Sirenix.OdinInspector.ReadOnly]
        [Tooltip("Buff 接受者")]
        private ActorBase receiver;
        
        /// 
        /// 初始化 Buff
        /// 
        public void BuffInitialize(ActorBase caster, ActorBase receiver, ScriptableBuff scriptableBuff)
        {
            this.caster = caster;
            this.receiver = receiver;
            
        }
        
        /// 
        /// 启动 Buff
        /// 
        public void StartBuff()
        {
            flowScriptController.StartBehaviour();
        }

        /// 
        /// 暂停 Buff
        /// 
        public void PauseBuff()
        {
            flowScriptController.PauseBehaviour();
        }
        
        /// 
        /// 结束 Buff
        /// 
        public void StopBuff()
        {
            flowScriptController.StopBehaviour();
        }

        /// 
        /// 重置 Buff
        /// 
        public void ResetBuff()
        {
            flowScriptController.RestartBehaviour();
        }
    }
}

2.5 BuffComponent v1

Buff 组件的话,由于生成 Buff 的函数被分开了,所以现在唯一有的功能就是记录 Buff 字典,然后提供 Buff 实体的根节点

Assets/MeowFramework/Core/FrameworkComponent/BuffComponent.cs

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

using System.Collections.Generic;
using System.ComponentModel;
using MeowFramework.Core.Scriptable;
using Sirenix.OdinInspector;

namespace MeowFramework.Core.FrameworkComponent
{
    /// 
    /// 框架中的 Buff 组件
    /// 
    [InlineEditor]
    public class BuffComponent : BaseComponent
    {
        /// 
        /// 技能字典
        /// 
        [Sirenix.OdinInspector.ReadOnly]
        [ShowInInspector]
        [Description("Buff 字典")]
        public static Dictionary<int, ScriptableBuff> ScriptableBuffDictionary = new Dictionary<int, ScriptableBuff>();
    }
}

2.6 BuffUtility v1

本来是想把生成 Buff 这个功能放在 Component 里面的,但是我想到,如果要把它做成一个 static 的,那为什么不干脆放到一个通用类里面呢
于是就把生成 Buff 的函数放到了 BuffUtility

Assets/MeowFramework/Core/Utility/BuffUtility.cs

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

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

namespace MeowFramework.Core.Utility
{
    public static class BuffUtility
    {
        /// 
        /// 尝试释放 Buff
        /// 
        /// Buff 释放者
        /// Buff 接受者
        ///  Buff ID
        /// Buff 实体
        public static BuffEntity TryAddBuff(ActorBase caster, ActorBase receiver, int buffIndex)
        {
            // 如果没有这个 Buff,就返回空
            if (!BuffComponent.ScriptableBuffDictionary.ContainsKey(buffIndex))
            {
                Debug.LogError($"Buff 组件的 Buff 字典中不存在键为 {buffIndex} 的条目!");
                return null;
            }

            // 如果有这个 Buff,获得 Buff 数据
            var scriptableBuff = BuffComponent.ScriptableBuffDictionary[buffIndex];

            if(!BuffComponent.BuffPoolRoot)
                Debug.LogError("Buff 组件下面没有对象池的根节点!");
            
            // 创建空物体作为 Buff 物体
            GameObject entity = new GameObject();
            
            // Ability 物体放在统一的 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);
            
            // 执行 Buff
            buffEntity.StartBuff();
            
            return buffEntity;
        }
    }
}

Buff 释放的测试 FlowScript

[Unity] 战斗系统学习 9:构建 TPS 框架 4_第4张图片

用于测试的 Buff

[Unity] 战斗系统学习 9:构建 TPS 框架 4_第5张图片

用于测试的 Buff 的 FlowScript

[Unity] 战斗系统学习 9:构建 TPS 框架 4_第6张图片

运行结果

[Unity] 战斗系统学习 9:构建 TPS 框架 4_第7张图片

看上去这样应该没啥大问题了

你可能感兴趣的:(游戏框架学习记录,2,unity,FlowCanvas,C#,FlowScript,Buff)