一开始我想的是这样做框架组件嘛,跟 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
{
///
/// 初始化组件
///
[Required]
[ShowInInspector]
[Description("初始化组件")]
public static InitializationComponent InitializationComponent;
///
/// 技能组件
///
[Required]
[ShowInInspector]
[Description("技能组件")]
public static AbilityComponent AbilityComponent;
}
}
监视器中是这样
我本来以为这样的话就可以直接拖进去了,没想打它把组件拖进去之后,脚本一更新,拖进去的组件又消失了
就是说,我试验出来 static 的变量的值不会被监视器的赋值覆盖,神奇
那最终还是不得不用 GetComponent
这要求这个脚本的执行顺序在所有脚本之前了
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
{
///
/// 初始化组件
///
[ShowInInspector]
[Sirenix.OdinInspector.ReadOnly]
[Description("初始化组件")]
public static InitializationComponent Initialization;
///
/// 技能组件
///
[ShowInInspector]
[Sirenix.OdinInspector.ReadOnly]
[Description("技能组件")]
public static AbilityComponent Ability;
///
/// Buff 组件
///
[ShowInInspector]
[Sirenix.OdinInspector.ReadOnly]
[Description("Buff 组件")]
public static BuffComponent Buff;
private void Start()
{
try
{
Initialization = transform.Find("InitializationComponent").GetComponent();
Ability = transform.Find("AbilityComponent").GetComponent();
Buff = transform.Find("BuffComponent").GetComponent();
}
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
{
///
/// 框架中的技能组件
///
[InlineEditor]
public class AbilityComponent : BaseComponent
{
///
/// 技能字典
///
[Sirenix.OdinInspector.ReadOnly]
[ShowInInspector]
[Description("技能字典")]
public static Dictionary ScriptableAbilityDictonary = new Dictionary();
}
}
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
{
///
/// Ability ID
///
[OnValueChanged("Register")]
[ValidateInput("IDValidate")]
[Tooltip("Ability ID")]
public int AbilityID = -1;
///
/// 旧 ID 用于取消字典中的旧 ID 键值对
///
private int oldAbiliyID = -1;
///
/// 注册技能 ID
///
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;
}
///
/// 验证函数:是否为非负数,是否这个 ID 被占据
///
///
///
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
{
///
/// 可资产化技能
///
[CreateAssetMenu(fileName = "New Scriptable Ability",
menuName = "MeowFramework/Scriptable Ability/Create Scriptable Ability")]
public class ScriptableAbility : SerializedScriptableObject
{
///
/// 技能 ID
///
[ValidateInput("IDValidate")]
[Tooltip("技能 ID")]
public int AbilityID;
///
/// 初始时注册技能 ID
///
private void OnEnable()
{
// 根据新的 ID 添加键值对
FrameworkComponent.AbilityComponent.ScriptableAbilityDictonary[AbilityID] = this;
}
///
/// 验证函数:是否为非负数
///
/// 新值
///
private bool IDValidate(int value) => value >= 0;
}
}
经过测试,这样写不但可以在运行时更新静态字典,也可以让游戏运行时更新的字典的内容,在退出游戏时仍然保存,虽然我不知道时保存在哪里了,但是总之就是在监视器里面还能看到
并且如果在编辑器中删去一个 ScriptableAbility 的实例的话,AbilityComponent 中的字典虽然理所当然地不会记录到这个删除,但是它在进入游戏之后还是会把那些不存在的 ScriptableAbility 删去
这么说,倒像是,static 变量在运行游戏的时候会初始化一次,无视监视器的赋值(当然它能够显示出来都是因为 Odin 的强制序列化,所以出现什么奇怪的行为都也不奇怪了),但在游戏运行时的分配的内存却能保存下来,虽然下一次进入游戏的时候也会抛弃上一次保存下来的内存
这么说,其实“在游戏运行时的分配的内存却能保存下来”这个判断也不准确,因为这只是 Odin 展示给我看的,我总感觉游戏结束之后,给游戏分配的所有内存都应该释放掉,所以监视器上不应该显示字典在游戏运行时的值才对……
总之对于 Unity 不支持的东西就不纠结太多了,能用就行x
2.3 ScriptableAbility v2接下来就要用到这个技能字典了
但是当我想通过静态变量获取的时候发现我获取不到
假设我加上这么一段
////// 框架组件 /// 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
{
///
/// 可资产化技能
///
[CreateAssetMenu(fileName = "New Scriptable Ability",
menuName = "MeowFramework/Scriptable Ability/Create Scriptable Ability")]
public class ScriptableAbility : SerializedScriptableObject
{
///
/// 技能 ID
///
[ValidateInput("IDValidate")]
[Tooltip("技能 ID")]
public int AbilityID;
///
/// 初始时注册技能 ID
///
private void OnEnable()
{
// 根据新的 ID 添加键值对
AbilityComponent.ScriptableAbilityDictionary[AbilityID] = this;
}
///
/// 验证函数:是否为非负数
///
///
///
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
{
///
/// 初始化组件
///
[Required]
[Tooltip("初始化组件")]
public InitializationComponent Initialization;
///
/// 技能组件
///
[Required]
[Tooltip("技能组件")]
public AbilityComponent Ability;
///
/// Buff 组件
///
[Required]
[Tooltip("Buff 组件")]
public BuffComponent Buff;
}
}
运行一次游戏之后变成这样
看上去还不错


![[Unity] 战斗系统学习 8:构建 TPS 框架 3:mono 组件 [Unity] 战斗系统学习 8:构建 TPS 框架 3:mono 组件](http://www.mshxw.com/aiimages/31/900974.png)
