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