这篇文章试错出来就是,不改源码实现不了一个 FlowScriptControler 并行执行多个 FlowScript

1. 错误用法 :直接使用 Initialize StartGraph

TestFlow

TestFlow 1

测试脚本

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 28/03/2022 17:43
// 最后一次修改于: 05/04/2022 9:14
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System.Collections;
using FlowCanvas;
using NodeCanvas.Framework;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core
{public class ActorBase : SerializedMonoBehaviour{/// <summary>/// 黑板/// </summary>[BoxGroup("Component")][Tooltip("黑板")]public IBlackboard Blackboard;/// <summary>/// 血量/// </summary>[BoxGroup("Attribute")][Tooltip("血量")] public ActorAttribute<float> HP = new ActorAttribute<float>();/// <summary>/// 最大血量/// </summary>[BoxGroup("Attribute")][Tooltip("最大血量")] public ActorAttribute<float> MaxHP = new ActorAttribute<float>();public FlowScript testFlow;public void Start(){StartCoroutine(ExecuteFlowScript(testFlow));}public IEnumerator ExecuteFlowScript(FlowScript flowScript){yield return new WaitForSeconds(1);if(Blackboard == null)yield break;flowScript.Initialize(this,Blackboard,true);flowScript.StartGraph(this,Blackboard,Graph.UpdateMode.Manual);flowScript.Stop();yield return null;}}
}

测试 GameObject

运行结果

首先这证明了,我如果使用同一个 agent 和 黑板 的话,两个 FlowScript 是可以共存的
但是这也说明 FlowScript 的启动并不是那么简单

2. 错误用法:实例上动态执行 Sub FlowCanvas

2.1 寻找 Sub FlowCanvas 的接口

我本来就是直接看输入点运算符之后出现的下拉菜单,能用什么函数就用什么函数
现在看来是不行了
那就只好看他的 FlowScriptController 看看别人的是怎么使用 FlowScript 素材的

Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/GraphOwner.cs

一开始看到泛型的 StartBehaviour

泛型的 StartBehaviour 把输入的继承 Graph 的实例转为父类 Graph 类型的 graph 变量
接下来就会跳转到一个 StartBehaviour,它直接对 graph 进行操作

可以看到除了我摸索着使用的 StartGraph 之外还要经过一个 GetInstance

GetInstance 这里经过一系列判断之后就是用 Graph.Clone
只是他需要把这个得到的 instance 放入它的字典里面

他这个字典的作用就是在 GraphOwner 销毁的时候同时销毁他身上的所有 Graph
这样的话我如果要自己Graph.Clone然后 StartGraph,我就要自己管理它们的销毁

那还是用 GraphOwner 的吧

但是 GraphOwner 的思想就是一个时间内只有一个 Behaviour,从它 StartBehaviour 的时候需要 SwithBehaviourSwithBehaviour 的时候需要先 StopBehaviour 这个流程就能看出来
本来我还想,那既然如此的话,我就需要新建一个跟 GraphOwner 类似但是在 StartBehaviour SwithBehaviour 这些方面不一样的 MultiGraphOwner
但是之后想到了 SubFlow 之前是以为它是需要提前分配好资产,所以我还没想到。现在我明确了这个需求,看过了 FlowScriptController 之后,就感觉这个 SubFlow 就是作者给 MultiGraphOwner 的需求安排的了

Assets/ParadoxNotion/FlowCanvas/Modules/FlowGraphs/Nodes/Nested/FlowNestedFlow.cs

Assets/ParadoxNotion/FlowCanvas/Modules/FlowGraphs/Nodes/Nested/FlowNestedBase.cs

他这个嵌套 Node 的关于 Node 的部分可以不看,就看它从 Start 入口进来干了什么
他是用了一个 this.TryStartSubGraph(targetAgent.value, (result) => { endResult = result; OnStop(f); });

Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/IGraphAssignableExtensions.cs

这就很舒服了
作者注释,创建实例,映射,启动,都做好了

Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/IGraphAssignableExtensions.cs

看它这个 CheckInstance 他是要用到实现了 IGraphAssignable 的对象

Assets/ParadoxNotion/FlowCanvas/Modules/FlowGraphs/FlowNodeNested.cs

Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Interfaces.cs

路径为
FlowNestedBase<T> : FlowNodeNested<T>
FlowNodeNested<T> : FlowNode, IGraphAssignable<T>

虽然我是现在才知道 interface 里面可以使用属性
以前我还以为变量和属性之前界限很不明显
现在我悟了,属性访问变量,但是需要函数的实现
需要函数的实现,就可以用接口,因为接口就是用来定义函数的
但是接口不能定义一个实例
这样,如果我要定义一个类有什么变量和方法,然后不想继承的时候,本来一般的想法是多继承嘛,但是 C# 不允许多继承,只允许多接口。我之前以为这样很不方便啊,因为接口定义不了变量,只能定义方法。现在我悟了,这并不是说你无法实现与多继承相类似的效果,只是你需要用接口中的继承属性来取代继承变量的思路

我还学到了一个东西
FlowNodeNested<T> : FlowNode, IGraphAssignable<T> 中本来是要实现 subGraph currentInstance 属性的嘛
但是它写成 public abstract T subGraph { get; set; }
配合 Graph IGraphAssignable.subGraph { get { return subGraph; } set { subGraph = (T)value; } }
这就又把 subGraph 的实现往后推了
也不是说学到吧,就是打破了我的”必须要在直接继承接口的那个类里面实现接口“的观念
严格来说他也是立即实现了,虽然实现了,但是是用抽象类实现的hhhh相当于用抽象类做接力了

他这个意思就是一个 IGraphAssignable 包含一个 subGraph currentInstance

Assets/ParadoxNotion/FlowCanvas/Modules/FlowGraphs/Nodes/Nested/FlowNestedBase.cs

subGraph 在 SubFlow 节点这里就是一个 FlowScript

回到 Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/IGraphAssignableExtensions.cs 的 CheckInstance

subGraphcurrentInstance 是否相等
相等则返回 currentInstance
不相等则看 instances 字典是否为空
为空则新建字典
不为空则在字典里面找跟输入的 subGraph 对应的实例
有则拿到实例,没有则通过 Graph.Clone 创建一个,并且加入自己的 instances 字典
如果拿到了 currentInstance
就开始写入值,绑定值函数,然后开始子图
如果子图结束时仍然在工作,那么读取所有值,取消绑定值函数
同时如果TryStartSubGraphcallback 不为空就激活

嗯……

2.2 继承 Sub FlowCanvas 需要的接口

第一次尝试是这样

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 28/03/2022 17:43
// 最后一次修改于: 05/04/2022 16:10
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System.Collections;
using System.Collections.Generic;
using FlowCanvas;
using NodeCanvas.Framework;
using NodeCanvas.Framework.Internal;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core
{public class ActorBase : SerializedMonoBehaviour, IGraphAssignable<FlowScript>{/// <summary>/// 黑板/// </summary>[BoxGroup("Component")][Tooltip("黑板")]public IBlackboard Blackboard;/// <summary>/// 血量/// </summary>[BoxGroup("Attribute")][Tooltip("血量")] public ActorAttribute<float> HP = new ActorAttribute<float>();/// <summary>/// 最大血量/// </summary>[BoxGroup("Attribute")][Tooltip("最大血量")] public ActorAttribute<float> MaxHP = new ActorAttribute<float>();/// <summary>/// 实现 IGraphElement 的属性 名称/// </summary>public string name { get; }/// <summary>/// 实现 IGraphElement 的属性 UID/// </summary>public string UID { get; }/// <summary>/// 实现 IGraphElement 的属性 主图/// </summary>public Graph graph { get; }/// <summary>/// 实现 IGraphElement 的属性 状态/// </summary>public Status status { get; }/// <summary>/// 实现 IGraphAssignable<FlowScript> 接口的属性 子 FlowScript/// </summary>public FlowScript subGraph{ get; set; }/// <summary>/// 实现 IGraphAssignable<FlowScript> 接口的属性 当前子 FlowScript/// </summary>public FlowScript currentInstance{ get; set; }/// <summary>/// 实现 IGraphAssignable 接口的属性 instance 字典/// </summary>public Dictionary<Graph, Graph> instances { get; set; }/// <summary>/// 实现 IGraphAssignable 接口的属性 子 FlowScript 的 BBP/// </summary>public BBParameter subGraphParameter { get; }/// <summary>/// 实现 IGraphAssignable 接口的属性 子 FlowScript 的变量表/// </summary>public List<BBMappingParameter> variablesMap { get; set; }/// <summary>/// 实现 IGraphAssignable 接口的属性 子 FlowScript/// </summary>Graph IGraphAssignable.subGraph { get => subGraph;set => subGraph = (FlowScript)value;}/// <summary>/// 实现 IGraphAssignable 接口的属性 子 FlowScript 当前 instance/// </summary>Graph IGraphAssignable.currentInstance { get => currentInstance;set => currentInstance = (FlowScript)value;}/// <summary>/// 用于测试的子 FlowScript/// </summary>public FlowScript testFlow;/// <summary>/// FlowScript 控制器/// </summary>public FlowScriptController flowScriptController;public void Start(){StartCoroutine(ExecuteFlowScript(testFlow));}/// <summary>/// 用于测试添加子 FlowScript/// </summary>/// <param name="flowScript"></param>/// <returns></returns>public IEnumerator ExecuteFlowScript(FlowScript flowScript){yield return new WaitForSeconds(1);subGraph = testFlow;this.TryStartSubGraph(this);yield return null;}}
}

接口很多,很容易忽略哪些属性没继承,唉

2.3 尝试执行 Sub FlowCanvas 需要的接口

第一版执行的结果为

有个地方为空

测试为 assignable.currentInstance 为空

我还没在

FlowNestedBase<T> : FlowNodeNested<T>
FlowNodeNested<T> : FlowNode, IGraphAssignable<T>

这之中找到怎么初始化 currentInstance

我就想到这个属性是不是应该一直不为 null 的

随便用了一个属性测试了一下

这个值对象的属性初始就不为 null

这个类型对象呃属性初始为 null

我悟了
值对象的属性初始不为 null
引用对象的属性初始为 null

但是我在哪里都没看到初始化 currentInstance
继续看的话……我错了

我是在赋值语句之前打印的
对于任何一个 assignable,那刚进来肯定是没有 currentInstance

正确的测试代码

测试结果

果然啊,是 assignable.graph.blackboard.parent
我这个 ActorBase 都没有黑板

graph 初始化的路径是在

FlowNestedBase<T> : FlowNodeNested<T>
FlowNodeNested<T> : FlowNode, IGraphAssignable<T>
FlowNode : Node, ISerializationCallbackReceiver

Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Node.cs

唉……麻了
不想做了,都初始化到最底层了

这样的话,这就说明这个东西就是用在 FlowScript 的节点里面的
嗯改那不就是自己还做了一套出来
所以说我的思路是错的,我不应该想着在一个什么都没有,只继承一个接口的实例上动态执行 Sub FlowCanvas

3. 正确用法 :在 FlowScript 中使用 Sub Flow

在 FlowScript 中使用 Sub Flow,虽然能成,但是有一个问题是他会暂时停用主 FlowScript
而我的期望是主 FlowScript 和 Sub FlowScript 是并行的
既然如此,那么想要做并行 FlowScript 的话,不改源码是不可能了
替代的用法就是提前配置一个装好 FlowScriptController 和 BlackBoard 的 Perfab,然后再需要的时候创建这个 Perfab
唉……难受

[Unity] 战斗系统学习 2:FlowCanvas 中的 SubGraph相关推荐

  1. [Unity] 战斗系统学习 4:FlowCanvas 中的 LatentActionNode

    [Unity] 战斗系统学习 2:FlowCanvas 中的 SubGraph 1. 并行执行 FlowScript 可能的魔改方向 其实我原本是想魔改 FlowCanvas 使其支持并行 FlowS ...

  2. [Unity] 战斗系统学习 3:FlowCanvas 中的 Input System

    1. 常规 Input System 使用 Assets/MeowFramework/MeowACT/InputSystem/MeowACTInputController.cs // -------- ...

  3. [Unity] 战斗系统学习 5:构建 TPS 框架 1

    [Unity] ACT 战斗系统学习 4:重构前的第三人称控制器 以前看猴与花果山的文章,感觉大开眼界,但是没做过所以没更多体会 https://zhuanlan.zhihu.com/p/416805 ...

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

    1. Port 与 BBParameter 我一开始就是公开组件接口,那个时候是因为我还只会用 AddValueInput,不会用 BBParameter 但是后来我发现 BBParameter 很简 ...

  5. Unity笔记一,Unity编辑器学习【记录中】

    这里写自定义目录标题 一,Unity编辑器的学习 1.1 API 1.1.1 Application 应用程序 1.1.2 AudioSource 音频源 1.1.3 Camera 摄像机 1.1.3 ...

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

    1. Time 一开始我是希望有一个 ScriptableObject 可以用来计时的 对于一些需要持续计时的事情可以用 1.1 ScriptableTimer Assets/MeowFramewor ...

  7. [Unity] 战斗系统学习 8:构建 TPS 框架 3:mono 组件

    1. 框架组件 1.1 FrameworkComponent v1 一开始我想的是这样做框架组件嘛,跟 GF 学的 但是后来我才知道 static 变量是默认在监视器上不显示的,怪不得 GF 不在 A ...

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

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

  9. [Unity] 战斗系统学习 13:Switchable 2

    1. Switchable v2 改了这两个 TPSCharacterAnimationController.Mode TPSCharacterLocomotionController.Mode 之后 ...

最新文章

  1. 用OpenCV玩《铁拳》!!!
  2. 左线性文法和右线性文法_线性代数期末考试复习资料
  3. 如何移植.NET Framework项目至.NET Core?
  4. 网管型工业交换机的三大指标介绍
  5. rem布局 html,移动端h5之rem布局/px2rem
  6. 安卓与HTML简单的交互使用
  7. mysql config.path_mysql之 mysql_config_editor/login-path 登录密码保护
  8. 通达OA 2013版和2013增强版两个版本开发的一些差异
  9. pycharm windows 重置_pycharm重置设置,恢复默认设置
  10. windows 8.1安装VS2005出现安装失败:未能安装.NET framework 3.5解决方案
  11. matlab 距平,[转载]基于Matlab软件进行EOF分解、回归趋势分析,并
  12. ueditor编辑器二次开发与优化
  13. JavaScript 获取元素方法
  14. Redis基本概念知识
  15. Android--Telephony
  16. Redis的三种启动方式
  17. 对待前任你有遗憾么?
  18. hangfire mysql_Hangfire 后台日志 The underlying provider failed on Open 错误
  19. 浙江大学计算机学院的软件工程和软件学院的软件工程哪个好,软件工程专业最强十校,浙大第二、清华第五,这所师范类院校很意外...
  20. Server2008如何卸载MySQL_Sql Server 2008完全卸载方法(其他版本类似)

热门文章

  1. Java描述设计模式(23):访问者模式
  2. SpringBoot2.0 基础案例(12):基于转账案例,演示事务管理操作
  3. Django REST framework API开发
  4. 创建定制的ASP.NET AJAX非可视化客户端组件
  5. 洛谷 P3211 [HNOI2011]XOR和路径(推dp+高斯消元)
  6. 小议:怎样解决创建Web Application失败问题?
  7. openstack内存占用清理
  8. 第一行代码阅读笔记---基本知识
  9. vmware workstation 关于三种网络连接方式的理解
  10. Linux关于Sendmail配置错误的问题