前述 总结的一些Unity的常用工具集
UIS 这是我根据网上的一些框架自己总结写出的小框架,感觉比较好用。
UIManager 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 using Newtonsoft.Json;using System;using System.Collections;using System.Collections.Generic;using System.IO;using QFramework;using UnityEditor;using UnityEngine;using UnityEngine.Events;namespace UI { public class UIManager { private static UIManager _instance; public static UIManager Instance { get { if (_instance == null ) _instance = new UIManager(); return _instance; } } public UIManager () { UIPanelInfoSaveInJson(); } private Transform canvasTransform; public Transform CanvasTransform { get { if (canvasTransform == null ) canvasTransform = GameObject.Find("Canvas" ).transform; return canvasTransform; } } private List<UIPanel> panelList; private Dictionary<EUIPanelType, BasePanel> panelDict; private Stack<BasePanel> panelStack; UnityAction finishEvent; #region 数据相关 #region 关于Panel的Json数据的代码 readonly string panelPrefabPath = Application.dataPath + @"/Resources/Prefabs/UIPanelPrefab" ; readonly string panelJsonPath = Application.streamingAssetsPath + @"/Json/GameSetting/UIJson.json" ; public List<UIPanel> ReadPanelJsonFile () { if (!File.Exists(panelJsonPath)) File.WriteAllText(panelJsonPath, "[]" ); List<UIPanel> list = JsonConvert.DeserializeObject<List<UIPanel>>(File.ReadAllText(panelJsonPath)); return list; } public void WritePanelJsonFile () { string json = JsonConvert.SerializeObject(panelList); File.WriteAllText(panelJsonPath, json); } public void UIPanelInfoSaveInJson () { panelList = ReadPanelJsonFile(); DirectoryInfo folder = new DirectoryInfo(panelPrefabPath); foreach (FileInfo file in folder.GetFiles("*.prefab" )) { EUIPanelType type = (EUIPanelType)Enum.Parse(typeof (EUIPanelType), file.Name.Replace(".prefab" , "" )); string path = @"Prefabs/UIPanelPrefab/" + file.Name.Replace(".prefab" , "" ); bool uiPanelExistInList = false ; UIPanel uIPanel = panelList.SearchPanelForType(type); if (uIPanel != null ) { uIPanel.UIPanelPath = path; uiPanelExistInList = true ; } if (uiPanelExistInList == false ) { UIPanel panel = new UIPanel(type, path); panelList.Add(panel); } } WritePanelJsonFile(); #if UNITY_EDITOR AssetDatabase.Refresh(); #endif } #endregion #endregion #region 面板相关设置 public BasePanel GetPanel (EUIPanelType type ) { if (panelDict == null ) panelDict = new Dictionary<EUIPanelType, BasePanel>(); BasePanel Panel1 = panelDict.TryGetValue(type); if (Panel1 == null ) { string path = panelList.SearchPanelForType(type).UIPanelPath; if (path == null ) throw new Exception("找不到该UIPanelType的Prefab" ); if (Resources.Load(path) == null ) throw new Exception("找不到该Path的Prefab" ); GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject; instPanel.transform.SetParent(CanvasTransform, false ); panelDict.Add(type, instPanel.GetComponent<BasePanel>()); return instPanel.GetComponent<BasePanel>(); } return Panel1; } public void PushPanel (EUIPanelType type ) { if (panelStack == null ) panelStack = new Stack<BasePanel>(); BasePanel topPanel = null ; BasePanel currPanel = null ; if (panelStack.Count > 0 ) topPanel = panelStack.Peek(); currPanel = GetPanel(type); panelStack.Push(currPanel); finishEvent = currPanel.OnEnter; if (topPanel != null ) topPanel.OnPause(finishEvent); else currPanel.OnEnter(); } public void PopPanel () { if (panelStack == null ) panelStack = new Stack<BasePanel>(); BasePanel topPanel = null ; BasePanel currPanel = null ; if (panelStack.Count == 0 ) return ; topPanel = panelStack.Pop(); finishEvent = null ; if (panelStack.Count != 0 ) { currPanel = panelStack.Peek(); finishEvent = currPanel.OnResume; } topPanel.OnExit(finishEvent); } public void ClearPanel () { if (panelStack == null ) return ; if (panelStack.Count != 0 ) panelStack.Clear(); if (panelDict.Count != 0 ) panelDict.Clear(); } #endregion } }
UIPanelEnum 1 2 3 4 5 public enum EUIPanelType{ StartPanel }
UIPanel 1 2 3 4 5 6 7 8 9 10 11 public class UIPanel { public EUIPanelType UIPanelType; public string UIPanelPath; public UIPanel (EUIPanelType Type, string Path ) { UIPanelType = Type; UIPanelPath = Path; } }
BasePanel 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 using UnityEngine;using UnityEngine.Events;using UnityEngine.EventSystems;using UnityEngine.UI;namespace UI { public class BasePanel : MonoBehaviour { public GameObject firstSelectedOgj = null ; protected CanvasGroup canvasGroup; protected Button CloseButton = null ; protected virtual void Awake () { canvasGroup = GetComponent<CanvasGroup>(); CloseButton = FindCloseButton("CloseButton" ); if (CloseButton != null ) { CloseButton.onClick.AddListener(Close); } if (canvasGroup == null ) canvasGroup = transform.gameObject.AddComponent<CanvasGroup>(); canvasGroup.alpha = 0 ; canvasGroup.blocksRaycasts = false ; } public virtual void OnEnter () { EventSystem.current.firstSelectedGameObject = firstSelectedOgj; EventSystem.current.SetSelectedGameObject(null ); EventSystem.current.SetSelectedGameObject(firstSelectedOgj); canvasGroup.alpha = 1 ; canvasGroup.blocksRaycasts = true ; } public virtual void OnResume () { EventSystem.current.firstSelectedGameObject = firstSelectedOgj; EventSystem.current.SetSelectedGameObject(null ); EventSystem.current.SetSelectedGameObject(firstSelectedOgj); canvasGroup.alpha = 1 ; canvasGroup.blocksRaycasts = true ; } public virtual void OnPause (UnityAction finishEvent = null ) { canvasGroup.alpha = 0 ; canvasGroup.blocksRaycasts = false ; if (finishEvent != null ) { finishEvent(); } } public virtual void OnExit (UnityAction finishEvent = null ) { canvasGroup.alpha = 0 ; canvasGroup.blocksRaycasts = false ; if (finishEvent != null ) { finishEvent(); } } private Button FindCloseButton (string childName ) { Button closeButton = null ; foreach (var item in GetComponentsInChildren <Button >()) { if (item.name == childName) closeButton = item.GetComponent<Button>(); } return closeButton; } public virtual void Close () { UIManager.Instance.PopPanel(); } } }
DictionaryExtension 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 using System.Collections.Generic;public static class DictionaryExtension { public static TValue TryGetValue <TKey , TValue >(this Dictionary<TKey, TValue> dict, TKey key ) { TValue value ; dict.TryGetValue(key, out value ); return value ; } }
ListExtension 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 using System.Collections.Generic;public static class ListExtension { public static UIPanel SearchPanelForType (this List<UIPanel> list, EUIPanelType type ) { if (list == null )return null ; foreach (var item in list) { if (item.UIPanelType == type) return item; } return null ; } }
Start 1 2 3 4 5 6 7 8 9 10 11 using UnityEngine;using UI;public class UIEnter : MonoBehaviour { public void Start () { UIManager.Instance.ClearPanel(); UIManager.Instance.PushPanel(EUIPanelType.StartPanel); } }
StartPanel 1 2 3 4 5 6 7 8 9 10 namespace UI { public class StartPanel : BasePanel { public void OnStartGameButton () { } } }
SceneManager 接下来登场的是,我自己实际用的超精简SceneManger,属于是想用什么内容就加什么内容了哈哈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 using System;using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.SceneManagement;namespace Manager { public class MySceneManager : SingletonMono <MySceneManager > { public float loadingValue { get ; private set ; } public GameObject LoadingPanel; private Action onStartAction; private bool _isActionOut = false ; public int GetSceneNumber { get { return SceneManager.GetActiveScene().buildIndex; } } private List<GameObject> objectsDontDestory; public List<GameObject> Push (GameObject theobject ) { if (objectsDontDestory == null ) { objectsDontDestory = new List<GameObject>(); } objectsDontDestory.Add(theobject); return objectsDontDestory; } public void MyLoadSceneAsync (int sceneIndex ) { if (_isActionOut) { onStartAction = null ; _isActionOut = false ; } if (objectsDontDestory != null ) { for (int i = 0 ; i < objectsDontDestory.Count; i++) { DontDestroyOnLoad(objectsDontDestory[i]); } } DontDestroyOnLoad(this .gameObject); StartCoroutine(LoadAsync(sceneIndex)); StartCoroutine(WaitForNewScene(sceneIndex)); } IEnumerator LoadAsync (int sceneIndex ) { PushLoadPanel(); AsyncOperation operation = SceneManager.LoadSceneAsync(sceneIndex); while (!operation.isDone) { loadingValue = operation.progress; yield return null ; } } IEnumerator WaitForNewScene (int sceneIndex ) { while (SceneManager.GetActiveScene().buildIndex != sceneIndex) { yield return null ; } onStartAction?.Invoke(); _isActionOut = true ; } public void RemoveDontGameObject (string name ) { for (int i = 0 ; i < objectsDontDestory.Count; i++) { if (objectsDontDestory[i].name == name) { objectsDontDestory[i].transform.SetParent(null ); objectsDontDestory.Remove(objectsDontDestory[i]); } } } public void AddActionAfterScene (Action action ) { if (_isActionOut) { onStartAction = null ; _isActionOut = false ; } onStartAction += action; } public void Clear () { foreach (var bGameObject in objectsDontDestory) { bGameObject.transform.SetParent(null ); } objectsDontDestory.Clear(); onStartAction = null ; } public void PushLoadPanel () { LoadingPanel.SetActive(true ); } } }
这一点代码实现了基本的场景切换的部分功能。
MusicManager 这里是一个比较简单的全局音乐管理的实现代码
Music 1 2 3 4 5 6 7 [System.Serializable ] public class Music { public string name; public AudioClip clip; [Range(0f, 1f) ] public float volume = 1f ; }
MusicManager 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 public class MusicManager : MonoSingleton <MusicManager >{ public List<Music> musicSounds, sfxSounds; [SerializeField ] private AudioSource musicSource, sfxSource; public float musicVolume => musicSource.volume; public float sfxVolume => sfxSource.volume; public void PlayMusic (string name ) { Music s = musicSounds.Find(x => x.name == name); if (s == null ) { Debug.Log("没有找到音乐" ); } else { musicSource.clip = s.clip; musicSource.Play(); } } public void PlaySFX (string name ) { Music s = sfxSounds.Find(x => x.name == name); if (s == null ) { Debug.Log("没有找到音效" ); } else { sfxSource.PlayOneShot(s.clip); } } public void PauseMusic () { musicSource.Pause(); } public void UnPauseMusic () { musicSource.UnPause(); } public void StopSFX () { sfxSource.Stop(); } public void ToggleMusic () { musicSource.mute = !musicSource.mute; } public void ToggleSFX () { sfxSource.mute = !sfxSource.mute; } public void MusicVolume (int volume ) { float V = volume / 10f ; musicSource.volume = V; } public void SFXVolume (int volume ) { float V = volume / 10f ; sfxSource.volume = V; } }
BuffManager 写了一个比较好用的BuffManager
Buff 先写一个通用的Buff接口
1 2 3 4 5 6 7 8 public interface IBuff { public void OnBuffAdd () ; public void OnBuffUpdate () ; public void OnBuffRemove () ; }
BuffManager 然后就是主要的BuffManager代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public class BuffsManager : SingletonMono <BuffsManager >{ private List<IBuff> _buffs; #region 私有方法 private IBuff Creat (Enums.Buff buff ) { return buff switch { _ => throw new ArgumentOutOfRangeException(nameof (buff), buff, null ) }; } private void AddBuff (IBuff buff ) { _buffs.Add(buff); buff.OnBuffAdd(); } private void RemoveBuff (IBuff buff ) { if (_buffs.Contains(buff)) { _buffs.Remove(buff); buff.OnBuffRemove(); } } private void Update () { foreach (var buff in _buffs) { buff.OnBuffUpdate(); } } #endregion public void AddBuff (Enums.Buff buff ) { AddBuff(Creat(buff)); } public void RemoveBuff (Enums.Buff buff ) { RemoveBuff(Creat(buff)); } public bool Contains (Enums.Buff buff ) { return _buffs.Contains(Creat(buff)); } }
TimeManager 这里是我主要用到的计时器的用法,一般配合上面的buffmanager一起用。
Timer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class Timer { private float time; private float timer; private Action callback; private bool isRepeat; public float Time => timer; public Timer (float time, bool isRepeat, Action callback ) { this .time = time; this .timer = time; this .callback = callback; this .isRepeat = isRepeat; } public void OnUpdate (float deltaTime ) { timer -= deltaTime; if (timer <= 0 ) { if (isRepeat) { callback?.Invoke(); timer = time + timer; } else { callback?.Invoke(); TimeManager.Instance.ReleaseTimer(this ); } } } public void Close (bool isInvoke = false ) { if (isInvoke) { callback?.Invoke(); } TimeManager.Instance.ReleaseTimer(this ); } public void Reset () { timer = time; } }
TimeManager 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class TimeManager : SingletonMono <TimeManager >{ private List<Timer> timerList = new List<Timer>(); public Timer AddTimer (float time, Action callback ) { Timer timer = new Timer(time, false , callback); timerList.Add(timer); return timer; } public Timer AddRepeatTimer (float time, Action callback ) { Timer timer = new Timer(time, true , callback); timerList.Add(timer); return timer; } public void ReleaseTimer (Timer timer ) { timerList.Remove(timer); } private void Update () { for (int i = 0 ; i < timerList.Count; i++) { timerList[i].OnUpdate(Time.deltaTime); } } public void ClearAllTimer () { foreach (var timer in timerList) { timer?.Close(); } timerList.Clear(); } }