1. 框架组件

1.1 FrameworkComponent v1

一开始我想的是这样做框架组件嘛,跟 GF 学的

但是后来我才知道 static 变量是默认在监视器上不显示的,怪不得 GF 不在

Assets/MeowFramework/Core/FrameworkComponent/FrameworkAdmin.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 9:49
// 最后一次修改于: 11/04/2022 10:14
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System.ComponentModel;
using Sirenix.OdinInspector;namespace MeowFramework.Core.FrameworkComponent
{public class FrameworkAdmin : SerializedMonoBehaviour{/// <summary>/// 初始化组件/// </summary>[Required][ShowInInspector][Description("初始化组件")]public static InitializationComponent InitializationComponent;/// <summary>/// 技能组件/// </summary>[Required][ShowInInspector][Description("技能组件")]public static AbilityComponent AbilityComponent;}
}

监视器中是这样

我本来以为这样的话就可以直接拖进去了,没想打它把组件拖进去之后,脚本一更新,拖进去的组件又消失了
就是说,我试验出来 static 的变量的值不会被监视器的赋值覆盖,神奇
那最终还是不得不用 GetComponent
这要求这个脚本的执行顺序在所有脚本之前了

1.2 FrameworkComponent v2

Assets/MeowFramework/Core/FrameworkComponent/FrameworkComponent.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 9:49
// 最后一次修改于: 11/04/2022 11:12
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using System.ComponentModel;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.FrameworkComponent
{public class FrameworkComponent : SerializedMonoBehaviour{/// <summary>/// 初始化组件/// </summary>[ShowInInspector][Sirenix.OdinInspector.ReadOnly][Description("初始化组件")]public static InitializationComponent Initialization;/// <summary>/// 技能组件/// </summary>[ShowInInspector][Sirenix.OdinInspector.ReadOnly][Description("技能组件")]public static AbilityComponent Ability;/// <summary>/// Buff 组件/// </summary>[ShowInInspector][Sirenix.OdinInspector.ReadOnly][Description("Buff 组件")]public static BuffComponent Buff;private void Start(){try{Initialization = transform.Find("InitializationComponent").GetComponent<InitializationComponent>();Ability = transform.Find("AbilityComponent").GetComponent<AbilityComponent>();Buff = transform.Find("BuffComponent").GetComponent<BuffComponent>();}catch (Exception e){Debug.LogError("缺少框架组件!");throw;}}}
}

2. 技能组件

2.1 AbilityComponent v1

目前做静态 mono 的目的就是方便地获得引用……
我想实现一个功能就是,创建 ScriptableObject 的时候会自动把自己写到一个字典里面,然后这个字典提供一个根据 id 查找对应的 ScriptbableObject 的功能
于是我就想把这个字典放到框架组件里面,虽然直接放到 ScriptableObject 的脚本里面最方便,丹斯数据放在框架组件里面看上去比较合理

初步实现为

Assets/MeowFramework/Core/FrameworkComponent/AbilityComponent.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 9:29
// 最后一次修改于: 11/04/2022 10:31
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System.Collections.Generic;
using System.ComponentModel;
using MeowFramework.Core.Scriptable;
using Sirenix.OdinInspector;namespace MeowFramework.Core.FrameworkComponent
{/// <summary>/// 框架中的技能组件/// </summary>[InlineEditor]public class AbilityComponent : BaseComponent{/// <summary>/// 技能字典/// </summary>[Sirenix.OdinInspector.ReadOnly][ShowInInspector][Description("技能字典")]public static Dictionary<int, ScriptableAbility> ScriptableAbilityDictonary = new Dictionary<int, ScriptableAbility>();}
}

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

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 05/04/2022 15:25
// 最后一次修改于: 11/04/2022 14:21
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
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{/// <summary>/// Ability ID/// </summary>[OnValueChanged("Register")][ValidateInput("IDValidate")][Tooltip("Ability ID")]public int AbilityID = -1;/// <summary>/// 旧 ID 用于取消字典中的旧 ID 键值对/// </summary>private int oldAbiliyID = -1;/// <summary>/// 注册技能 ID/// </summary>private void Register(){if (AbilityID >= 0){// 如果包含旧的键,那就去掉这个旧的键值对if (FrameworkComponent.AbilityComponent.ScriptableAbilityDictonary.ContainsKey(oldAbiliyID))FrameworkComponent.AbilityComponent.ScriptableAbilityDictonary.Remove(oldAbiliyID);// 根据新的 ID 添加键值对FrameworkComponent.AbilityComponent.ScriptableAbilityDictonary[AbilityID] = this;}// 更新旧值oldAbiliyID = AbilityID;}/// <summary>/// 验证函数:是否为非负数,是否这个 ID 被占据/// </summary>/// <param name="value"></param>/// <returns></returns>private bool IDValidate(int value){if(value >= 0)if (FrameworkComponent.AbilityComponent.ScriptableAbilityDictonary[value] == this)return true;return false;}}
}

虽然这样写,运行游戏前,可以在编辑器界面看到 AbilityComponent 的字典里面有键值对

但是运行游戏之前还是看不到 FrameworkComponent 中的 AbilityComponent 的 inline 界面中的字典有键值对

运行游戏后,两个地方都看不到键值对了


退出游戏之后,AbilityComponent 的字典也变空了,图略

2.2 ScriptableAbility v1

参考运行时获取组件赋给静态变量的做法
ScriptableAbility 看来也是不得不在运行时赋值了
可惜了,我本来希望一切可以在监视器中安排妥当的

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

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 05/04/2022 15:25
// 最后一次修改于: 11/04/2022 15:09
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.Scriptable
{/// <summary>/// 可资产化技能/// </summary>[CreateAssetMenu(fileName = "New Scriptable Ability",menuName = "MeowFramework/Scriptable Ability/Create Scriptable Ability")]public class ScriptableAbility : SerializedScriptableObject{/// <summary>/// 技能 ID/// </summary>[ValidateInput("IDValidate")][Tooltip("技能 ID")]public int AbilityID;/// <summary>/// 初始时注册技能 ID/// </summary>private void OnEnable(){// 根据新的 ID 添加键值对FrameworkComponent.AbilityComponent.ScriptableAbilityDictonary[AbilityID] = this;}/// <summary>/// 验证函数:是否为非负数/// </summary>/// <param name="value">新值</param>/// <returns></returns>private bool IDValidate(int value) => value >= 0;}
}

经过测试,这样写不但可以在运行时更新静态字典,也可以让游戏运行时更新的字典的内容,在退出游戏时仍然保存,虽然我不知道时保存在哪里了,但是总之就是在监视器里面还能看到
并且如果在编辑器中删去一个 ScriptableAbility 的实例的话,AbilityComponent 中的字典虽然理所当然地不会记录到这个删除,但是它在进入游戏之后还是会把那些不存在的 ScriptableAbility 删去

这么说,倒像是,static 变量在运行游戏的时候会初始化一次,无视监视器的赋值(当然它能够显示出来都是因为 Odin 的强制序列化,所以出现什么奇怪的行为都也不奇怪了),但在游戏运行时的分配的内存却能保存下来,虽然下一次进入游戏的时候也会抛弃上一次保存下来的内存

这么说,其实“在游戏运行时的分配的内存却能保存下来”这个判断也不准确,因为这只是 Odin 展示给我看的,我总感觉游戏结束之后,给游戏分配的所有内存都应该释放掉,所以监视器上不应该显示字典在游戏运行时的值才对……

总之对于 Unity 不支持的东西就不纠结太多了,能用就行x

2.3 ScriptableAbility v2

接下来就要用到这个技能字典了
但是当我想通过静态变量获取的时候发现我获取不到

假设我加上这么一段

     /// <summary>/// 框架组件/// </summary>public static FrameworkComponent Framework;

那么他更是找不到 Ability 了

总结来说就是

有两个类 classA classB
classA 中有一个静态成员 instanceB
classB 中有一个静态成员 instanceC
classA.instanceB 可以
classA.instanceB.instanceC 不可以

这是什么道理

问了别人,别人说 C# 访问静态成员的方法是通过 类型名.静态成员 而不是 对象.静态成员
好的捏

就是非 static 是给实例用的,叫动态方法
static 是给类用的,叫静态方法
C# 是不支持动静态混用的

嗯……所以就直接用 AbilityComponent 吧,不强求在前面加一个 Framework 了

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

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 05/04/2022 15:25
// 最后一次修改于: 11/04/2022 16:43
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using MeowFramework.Core.FrameworkComponent;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.Scriptable
{/// <summary>/// 可资产化技能/// </summary>[CreateAssetMenu(fileName = "New Scriptable Ability",menuName = "MeowFramework/Scriptable Ability/Create Scriptable Ability")]public class ScriptableAbility : SerializedScriptableObject{/// <summary>/// 技能 ID/// </summary>[ValidateInput("IDValidate")][Tooltip("技能 ID")]public int AbilityID;/// <summary>/// 初始时注册技能 ID/// </summary>private void OnEnable(){// 根据新的 ID 添加键值对AbilityComponent.ScriptableAbilityDictionary[AbilityID] = this;}/// <summary>/// 验证函数:是否为非负数/// </summary>/// <param name="value"></param>/// <returns></returns>private bool IDValidate(int value) => value >= 0;}
}

2.4 FrameworkComponent v3

那既然我都直接用类名了,那我就不需要在 FrameworkComponent 里面对组件使用 static 了
这样也可以避免掉 static 变量在监视器中的奇怪问题了

Assets/MeowFramework/Core/FrameworkComponent/FrameworkComponent.cs

// ----------------------------------------------
// 作者: 廉价喵
// 创建于: 11/04/2022 9:49
// 最后一次修改于: 11/04/2022 16:55
// 版权所有: CheapMeowStudio
// 描述:
// ----------------------------------------------using System;
using System.ComponentModel;
using Sirenix.OdinInspector;
using UnityEngine;namespace MeowFramework.Core.FrameworkComponent
{public class FrameworkComponent : SerializedMonoBehaviour{/// <summary>/// 初始化组件/// </summary>[Required][Tooltip("初始化组件")]public InitializationComponent Initialization;/// <summary>/// 技能组件/// </summary>[Required][Tooltip("技能组件")]public AbilityComponent Ability;/// <summary>/// Buff 组件/// </summary>[Required][Tooltip("Buff 组件")]public BuffComponent Buff;}
}

运行一次游戏之后变成这样

看上去还不错

[Unity] 战斗系统学习 8:构建 TPS 框架 3:mono 组件相关推荐

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

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

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

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

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

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

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

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

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

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

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

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

  7. [Unity] 战斗系统学习 10:ActorAttribute

    1. ActorAttribute v1 一开始我是想做一个可以使用泛型 ScriptableObject 的角色属性 1.1 ScriptableGenericVariable v1 泛型 Scri ...

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

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

  9. [Unity] 战斗系统学习 2:FlowCanvas 中的 SubGraph

    这篇文章试错出来就是,不改源码实现不了一个 FlowScriptControler 并行执行多个 FlowScript 1. 错误用法 :直接使用 Initialize StartGraph Test ...

最新文章

  1. MATLAB【五】———— matlab 调用C++生成exe文件,高斯核函数
  2. Anaconda 环境下 R 包 ggraph_1.0.2 安装小记
  3. html lt table 设置数据,vue_+_element_ui_动态添加table数据
  4. matplotlib----初探------4折线图
  5. 04 ORA系列:ORA-00984 列在此处不允许 SQL parse error location
  6. 虚拟服务器备案流程,国内虚拟主机备案流程
  7. php数字转中文数字排序,php实现中文转数字
  8. 【报告分享】2020全球网络趋势报告.pdf(附下载链接)
  9. 《大话设计模式》第29章-OOTV杯超级模式大赛—模式总结(五)
  10. CodeBlocks配色方案设置(简单易懂)
  11. 用Python画一颗心、小人发射爱心
  12. codeforces——961A Tetris
  13. rust腐蚀怎么建立单机服务器_腐蚀rust搭建Rust服务器及联机教程
  14. 将数组分成两部分,使得这两部分的和的差最小
  15. 实现百度语音识别功能
  16. 输入一个整数n,按要求生成一个n*n的蛇形矩阵
  17. 集群通信TIPC协议
  18. 前端应届生如何做一个职业规划
  19. 约瑟夫环c语言单链表的解题思路,太透彻了:约瑟夫环的三种解法
  20. 战双帕弥什登入显示服务器错误,战双帕弥什渠道账号登录失败/安装失败/提示新版本/卡顿闪退FAQ大全[多图]...

热门文章

  1. 数据采集组件:Flume基础用法和Kafka集成
  2. 阿里云服务器被挖矿怎么解决
  3. 案例:java进制互转
  4. 网络应用框架Netty快速入门
  5. 我就是互联网的老不死
  6. python操作haproxy配置文件实例
  7. 盒子模型与DOCTYPE
  8. pfring(pf_ring)编译安装
  9. ZZULIOJ 1117: 查找数组元素
  10. 计算机文化基础第三版龙天才课后答案,龙天才