[Unity] 战斗系统学习 13:Switchable 2
1. Switchable v2
改了這兩個
TPSCharacterAnimationController.Mode
TPSCharacterLocomotionController.Mode
之后我就覺得,有很多是重復的,是可以改的
比如
public float ModeTransitionTime = 1f;private List<ISwitchable> switchableObjectList = new List<ISwitchable>();private Coroutine switchValueCoroutine;private void ClearSwitchableList()private IEnumerator ModeTransition(TPSCharacterBehaviourMode mode)SwitchObject 也有很多重復的,我就做成了泛型 SwitchableGeneric<T>
SmoothDamp 沒有泛型,所以只好繼承泛型確定類型 SwitchableFloat SwitchableVector3
為了方便,承擔平滑插值邏輯的函數做成接口,并放到 SwitchableGeneric<T> 中,在 SwitchableFloat SwitchableVector3 中延遲實現
原來直接在 mono 里面做的協程,現在我把 Mode 單獨做成一個 Switcher 類,那么他就需要獲取到 mono 組件
原來直接在 mono 里面把 ISwitchable 加入一個列表,現在我把這個列表放到 Switcher 類中,于是 ISwitchable 需要有一個時機加入 Switcher 類的列表中
本來我是想在構造函數中做這些事的,但是首先我不能設置一個有參的構造函數,因為我必須要有一個無參的構造函數,才能在變量初始化的同時構造變量(如果有參,這個參數不能是編譯期提供的,所以我只能在 Awake 中調用有參構造函數),這樣我才能在監視器中配置類
所以 Switcher 有一個 RegisterSwitchable 函數來把 ISwitchable 加入一個列表,有 Owner 屬性配置 mono 主人,Switcher 的 Mode 的 setter 會觸發平滑協程,平滑協程里面對 ISwitchable 列表調用平滑函數
1.1 ISwitchable
Assets/MeowFramework/Core/Switchable/ISwitchable.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 9:00 // 最后一次修改于: 22/04/2022 19:33 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System;namespace MeowFramework.Core.Switchable {/// <summary>/// 切換變量的接口/// </summary>public interface ISwitchable{/// <summary>/// 使變量在不同預設值之間切換/// </summary>/// <param name="mode">預設模式</param>public void SwitchValue(Enum mode);} }1.2 ISwitcher
Assets/MeowFramework/Core/Switchable/ISwitcher.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 19:08 // 最后一次修改于: 22/04/2022 20:38 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System.Collections.Generic;namespace MeowFramework.Core.Switchable {/// <summary>/// 切換器的借口/// </summary>public interface ISwitcher{/// <summary>/// 注冊可切換變量/// </summary>/// <param name="switchable">可切換變量</param>public void RegisterSwitchable(ISwitchable switchable);/// <summary>/// 注冊可切換變量/// </summary>/// <param name="switchableList">可切換變量列表</param>public void RegisterSwitchable(List<ISwitchable> switchableList);} }1.3 SwitchableGeneric
要推遲接口的實現,所以使用抽象類
Assets/MeowFramework/Core/Switchable/SwitchableGeneric.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 18:55 // 最后一次修改于: 22/04/2022 21:33 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System; using System.Collections.Generic; using Sirenix.OdinInspector; using UnityEngine;namespace MeowFramework.Core.Switchable {public abstract class SwitchableGeneric<T> : ISwitchable{/// <summary>/// 當前值/// </summary>[ShowInInspector][Tooltip("當前值")]protected T value;/// <summary>/// 當前值/// </summary>public T Value{get => value;set{AfterValueChangeAction?.Invoke(this.value, value);this.value = value;}}/// <summary>/// 值改變后觸發的委托/// </summary>[HideInInspector]public Action<T, T> AfterValueChangeAction;/// <summary>/// 預設值字典/// </summary>[Tooltip("預設值字典")]public Dictionary<Enum, T> TargetValueDict = new Dictionary<Enum, T>();// 緩存/// <summary>/// 平滑速度/// </summary>protected T smoothVelocity;/// <summary>/// 平滑時間/// </summary>[Tooltip("平滑時間")]public float SmoothTime = 0.2f;// 析構函數~SwitchableGeneric(){AfterValueChangeAction = null;}// 接口// 延遲實現接口/// <summary>/// 使變量在不同預設值之間切換/// </summary>/// <param name="mode">預設模式</param>public abstract void SwitchValue(Enum mode);} }1.4 SwitchableFloat
Assets/MeowFramework/Core/Switchable/SwitchableFloat.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 9:01 // 最后一次修改于: 22/04/2022 21:33 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System; using UnityEngine;namespace MeowFramework.Core.Switchable {/// <summary>/// 可切換浮點/// </summary>public class SwitchableFloat : SwitchableGeneric<float>{// 實現接口/// <summary>/// 使變量在不同預設值之間切換/// </summary>/// <param name="mode">預設模式</param>public override void SwitchValue(Enum mode){// SmoothDamp if (TargetValueDict.ContainsKey(mode)){float target = TargetValueDict[mode];Value = Mathf.SmoothDamp(Value, target, ref smoothVelocity, SmoothTime);}}} }1.5 SwitcherEnum
Assets/MeowFramework/Core/Switchable/SwitcherEnum.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 18:45 // 最后一次修改于: 22/04/2022 20:38 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Sirenix.OdinInspector; using UnityEngine;namespace MeowFramework.Core.Switchable {public class SwitcherEnum<T> : ISwitcher where T: Enum{/// <summary>/// 主人/// </summary>private SerializedMonoBehaviour owner;/// <summary>/// 主人/// </summary>public SerializedMonoBehaviour Owner{set => owner = value;}/// <summary>/// 行動模式/// </summary>[ShowInInspector][Tooltip("行動模式")]private T mode;/// <summary>/// 行動模式/// </summary>public T Mode{get => mode;set{if (owner != null){if (switchValueCoroutine != null)owner.StopCoroutine(switchValueCoroutine);switchValueCoroutine = owner.StartCoroutine(ModeTransition(value));mode = value;}}}/// <summary>/// 切換模式的過渡時間/// </summary>[Tooltip("切換模式的過渡時間")]public float ModeTransitionTime = 1f;// 緩存/// <summary>/// 可切換變量列表/// </summary>private List<ISwitchable> switchableObjectList = new List<ISwitchable>();/// <summary>/// 切換變量的協程/// </summary>private Coroutine switchValueCoroutine;/// <summary>/// 模式過渡:使變量在不同預設值之間切換/// </summary>/// <param name="mode">預設模式</param>/// <returns></returns>private IEnumerator ModeTransition(T mode){float time = ModeTransitionTime;while(time > 0){time -= Time.deltaTime;foreach (ISwitchable switchable in switchableObjectList){switchable.SwitchValue(mode);}}yield return null;}/// <summary>/// 注冊可切換變量/// </summary>/// <param name="switchable">可切換變量</param>public void RegisterSwitchable(ISwitchable switchable){if(switchable != null)switchableObjectList.Add(switchable);}/// <summary>/// 注冊可切換變量/// </summary>/// <param name="switchableList">可切換變量列表</param>public void RegisterSwitchable(List<ISwitchable> switchableList){if (switchableList != null)switchableObjectList.AddRange(switchableList);}} }效果大概是這樣
跟以前看上去一樣hhh
之后應該是 Controller 改動后的代碼
但是我測試的時候又發現了問題,所以先解決 Switchable 的 Bug……
2. Bug:構造期間不為 null 游戲開始后變成 null
測試的時候發現 SwitcherMode.switchableObjectList == null 導致 InitSwitchableList() 中 switchableObjectList.AddRange(switchableList); 出錯
解決方法記錄:
[Unity][Odin Inspector] SerializedMonoBehaviour 中的 private List 會被初始化為 null
3. Switchable v3
3.1 SwitcherEnum v3.1
既然 SerializedMonoBehaviour 中的 private List 會被初始化為 null
那我就只能在其它函數里面檢查 null,如果為 null 就代為初始化
Assets/MeowFramework/Core/Switchable/SwitcherEnum.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 18:45 // 最后一次修改于: 26/04/2022 9:30 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Sirenix.OdinInspector; using UnityEngine;namespace MeowFramework.Core.Switchable {public class SwitcherEnum<T> : ISwitcher where T: Enum{/// <summary>/// 主人/// </summary>private SerializedMonoBehaviour owner;/// <summary>/// 主人/// </summary>public SerializedMonoBehaviour Owner{set => owner = value;}/// <summary>/// 行動模式/// </summary>[ShowInInspector][Tooltip("行動模式")]private T mode;/// <summary>/// 行動模式/// </summary>public T Mode{get => mode;set{if (owner != null){if (switchValueCoroutine != null)owner.StopCoroutine(switchValueCoroutine);switchValueCoroutine = owner.StartCoroutine(ModeTransition(value));mode = value;}}}/// <summary>/// 切換模式的過渡時間/// </summary>[Tooltip("切換模式的過渡時間")]public float ModeTransitionTime = 1f;// 緩存/// <summary>/// 可切換變量列表/// </summary>private List<ISwitchable> switchableList = new List<ISwitchable>();/// <summary>/// 切換變量的協程/// </summary>private Coroutine switchValueCoroutine;/// <summary>/// 模式過渡:使變量在不同預設值之間切換/// </summary>/// <param name="mode">預設模式</param>/// <returns></returns>private IEnumerator ModeTransition(T mode){float time = ModeTransitionTime;while(time > 0){time -= Time.deltaTime;foreach (ISwitchable switchable in switchableList){switchable.SwitchValue(mode);}}yield return null;}/// <summary>/// 注冊可切換變量/// </summary>/// <param name="switchable">可切換變量</param>public void RegisterSwitchable(ISwitchable switchable){if (switchable == null)return;if (switchableList == null)switchableList = new List<ISwitchable> {switchable};elseswitchableList.Add(switchable);}/// <summary>/// 注冊可切換變量/// </summary>/// <param name="switchableList">可切換變量列表</param>public void RegisterSwitchable(List<ISwitchable> switchableList){if (switchableList == null)return;if (this.switchableList == null)this.switchableList = switchableList;elsethis.switchableList.AddRange(switchableList);}} }測試過這樣是沒有問題的
但是如果真的要這么寫的話,那還不如直接寫成一個屬性
3.2 ISwitcher v3.2
Assets/MeowFramework/Core/Switchable/ISwitcher.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 19:08 // 最后一次修改于: 26/04/2022 9:37 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System.Collections.Generic;namespace MeowFramework.Core.Switchable {/// <summary>/// 切換器的借口/// </summary>public interface ISwitcher{/// <summary>/// 可切換變量列表/// </summary>public List<ISwitchable> SwitchableList{get;}} }3.3 SwitcherEnum v3.2
Assets/MeowFramework/Core/Switchable/SwitcherEnum.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 22/04/2022 18:45 // 最后一次修改于: 26/04/2022 9:42 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Sirenix.OdinInspector; using UnityEngine;namespace MeowFramework.Core.Switchable {public class SwitcherEnum<T> : ISwitcher where T: Enum{/// <summary>/// 主人/// </summary>private SerializedMonoBehaviour owner;/// <summary>/// 主人/// </summary>public SerializedMonoBehaviour Owner{set => owner = value;}/// <summary>/// 行動模式/// </summary>[ShowInInspector][Tooltip("行動模式")]private T mode;/// <summary>/// 行動模式/// </summary>public T Mode{get => mode;set{if (owner != null){if (switchValueCoroutine != null)owner.StopCoroutine(switchValueCoroutine);switchValueCoroutine = owner.StartCoroutine(ModeTransition(value));mode = value;}}}/// <summary>/// 切換模式的過渡時間/// </summary>[Tooltip("切換模式的過渡時間")]public float ModeTransitionTime = 1f;/// <summary>/// 可切換變量列表/// </summary>private List<ISwitchable> switchableList;/// <summary>/// 可切換變量列表/// </summary>public List<ISwitchable> SwitchableList{get{if(switchableList == null)switchableList = new List<ISwitchable>();return switchableList;}}// 緩存/// <summary>/// 切換變量的協程/// </summary>private Coroutine switchValueCoroutine;/// <summary>/// 模式過渡:使變量在不同預設值之間切換/// </summary>/// <param name="mode">預設模式</param>/// <returns></returns>private IEnumerator ModeTransition(T mode){float time = ModeTransitionTime;while(time > 0){time -= Time.deltaTime;foreach (ISwitchable switchable in switchableList){switchable.SwitchValue(mode);}}yield return null;}} }這樣,接下來就可以放 Controller 了
3.4 TPSCharacterUIController.Mode
Assets/MeowFramework/TPSCharacter/Scripts/Controller/TPSCharacterUIController.Mode.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 12/04/2022 15:53 // 最后一次修改于: 26/04/2022 9:42 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System.Collections.Generic; using MeowFramework.Core.Switchable; using Sirenix.OdinInspector; using UnityEngine;namespace MeowFramework.TPSCharacter {/// <summary>/// 第三人稱 UI 控制器/// </summary>public partial class TPSCharacterUIController{/// <summary>/// 行動模式/// </summary>[BoxGroup("Mode")][Tooltip("行動模式")]public SwitcherEnum<TPSCharacterBehaviourMode> SwitcherMode = new SwitcherEnum<TPSCharacterBehaviourMode>();/// <summary>/// 瞄準 UI 的透明度/// </summary>[BoxGroup("Mode")][Tooltip("瞄準 UI 的透明度")]public SwitchableFloat AimUIAlpha = new SwitchableFloat();/// <summary>/// 初始化可切換變量列表/// </summary>private void InitSwitchableList(){// Switcher 注冊SwitcherMode.Owner = this;// Switchable 注冊SwitcherMode.SwitchableList.AddRange(new List<ISwitchable>{AimUIAlpha,});// Switchable 數值綁定AimUIAlpha.AfterValueChangeAction += (oldValue, newValue) => { AimUI.GetComponent<CanvasGroup>().alpha = newValue; };}} }3.5 TPSCharacterLocomotionController.Mode
Assets/MeowFramework/TPSCharacter/Scripts/Controller/TPSCharacterLocomotionController.Mode.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 12/04/2022 15:48 // 最后一次修改于: 26/04/2022 9:42 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System.Collections.Generic; using Cinemachine; using MeowFramework.Core.Switchable; using Sirenix.OdinInspector; using UnityEngine;namespace MeowFramework.TPSCharacter {/// <summary>/// 第三人稱運動控制器/// </summary>public partial class TPSCharacterLocomotionController{/// <summary>/// 行動模式/// </summary>[BoxGroup("Mode")][Tooltip("行動模式")]public SwitcherEnum<TPSCharacterBehaviourMode> SwitcherMode = new SwitcherEnum<TPSCharacterBehaviourMode>();/// <summary>/// 行走速度/// </summary>[BoxGroup("Mode")][Tooltip("行走速度")]public SwitchableFloat WalkSpeed = new SwitchableFloat();/// <summary>/// 攝像機 FOV/// </summary>[BoxGroup("Mode")][Tooltip("攝像機 FOV")]public SwitchableFloat CameraFOV = new SwitchableFloat();/// <summary>/// 攝像機側向位置/// </summary>[BoxGroup("Mode")][Tooltip("攝像機側向位置")]public SwitchableFloat CameraSide = new SwitchableFloat();/// <summary>/// 初始化可切換變量列表/// </summary>private void InitSwitchableList(){// 攝像機第三人稱跟隨組件var camera3rdPersonFollow =PlayerFollowCamera.GetCinemachineComponent<Cinemachine3rdPersonFollow>();// Switcher 注冊SwitcherMode.Owner = this;// Switchable 注冊SwitcherMode.SwitchableList.AddRange(new List<ISwitchable>{WalkSpeed,CameraFOV,CameraSide });// Switchable 數值綁定WalkSpeed.AfterValueChangeAction += (oldValue, newValue) => { walkSpeed = newValue; };CameraFOV.AfterValueChangeAction += (oldValue, newValue) => { PlayerFollowCamera.m_Lens.FieldOfView = newValue; };CameraSide.AfterValueChangeAction += (oldValue, newValue) => { camera3rdPersonFollow.CameraSide = newValue; };}} }3.6 TPSCharacterAnimationController.Mode
Assets/MeowFramework/TPSCharacter/Scripts/Controller/TPSCharacterAnimationController.Mode.cs
// ---------------------------------------------- // 作者: 廉價喵 // 創建于: 12/04/2022 15:55 // 最后一次修改于: 26/04/2022 9:42 // 版權所有: CheapMeowStudio // 描述: // ----------------------------------------------using System.Collections; using System.Collections.Generic; using MeowFramework.Core.Switchable; using Sirenix.OdinInspector; using UnityEngine;namespace MeowFramework.TPSCharacter {/// <summary>/// 第三人稱動畫狀態機控制器/// </summary>public partial class TPSCharacterAnimationController{/// <summary>/// 行動模式/// </summary>[BoxGroup("Mode")][Tooltip("行動模式")]public SwitcherEnum<TPSCharacterBehaviourMode> SwitcherMode = new SwitcherEnum<TPSCharacterBehaviourMode>();/// <summary>/// 動畫狀態機第 0 層的權重/// </summary>[BoxGroup("Mode")][Tooltip("動畫狀態機第 0 層的權重")]public SwitchableFloat AnimLayer0Weight = new SwitchableFloat();/// <summary>/// 動畫狀態機第 1 層的權重/// </summary>[BoxGroup("Mode")][Tooltip("動畫狀態機第 1 層的權重")]public SwitchableFloat AnimLayer1Weight = new SwitchableFloat();/// <summary>/// 動畫狀態機第 2 層的權重/// </summary>[BoxGroup("Mode")][Tooltip("動畫狀態機第 2 層的權重")]public SwitchableFloat AnimLayer2Weight = new SwitchableFloat();/// <summary>/// 步槍待機姿態所用到的骨骼綁定的權重/// </summary>[BoxGroup("Mode")][Tooltip("步槍待機姿態所用到的骨骼綁定的權重")]public SwitchableFloat RifleIdleRigWeight = new SwitchableFloat();/// <summary>/// 步槍瞄準姿態所用到的骨骼綁定的權重/// </summary>[BoxGroup("Mode")][Tooltip("步槍瞄準姿態所用到的骨骼綁定的權重")]public SwitchableFloat RifleAimingRigWeight = new SwitchableFloat();/// <summary>/// 初始化可切換變量列表/// </summary>private void InitSwitchableList(){// Switcher 注冊SwitcherMode.Owner = this;// Switchable 注冊SwitcherMode.SwitchableList.AddRange(new List<ISwitchable>{AnimLayer0Weight,AnimLayer1Weight,AnimLayer2Weight,RifleIdleRigWeight,RifleAimingRigWeight});// Switchable 數值綁定AnimLayer0Weight.AfterValueChangeAction += (oldValue, newValue) => { Anim.SetLayerWeight(0, newValue); };AnimLayer1Weight.AfterValueChangeAction += (oldValue, newValue) => { Anim.SetLayerWeight(1, newValue); };AnimLayer2Weight.AfterValueChangeAction += (oldValue, newValue) => { Anim.SetLayerWeight(2, newValue); };RifleIdleRigWeight.AfterValueChangeAction += (oldValue, newValue) => { rifleIdleRig.weight = newValue; };RifleAimingRigWeight.AfterValueChangeAction += (oldValue, newValue) => { rifleAimingRig.weight = newValue; };}} }總結
以上是生活随笔為你收集整理的[Unity] 战斗系统学习 13:Switchable 2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vs2013 获取cpu温度
- 下一篇: HTML 中 id、name、class