Unity 遊戲框架搭建 2019 (二十五) 類的第一個作用 與 Obselete 屬性
- 2020 年 4 月 10 日
- 筆記
在上一篇我們整理到了第七個示例,我們今天再接著往下整理。我們來看第八個示例:
#if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; using System; using System.IO; namespace QFramework { public class PreviousFunctions : MonoBehaviour { public static string GenerateUnityPackageName() { return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh"); } public static void CopyText(string text) { GUIUtility.systemCopyBuffer = text; } public static void OpenInFolder(string folderPath) { Application.OpenURL("file:///" + folderPath); } #if UNITY_EDITOR public static void CallMenuItem(string menuPath) { EditorApplication.ExecuteMenuItem(menuPath); } public static void ExportPackage(string assetPathName,string fileName) { AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse); } #endif #if UNITY_EDITOR [MenuItem("QFramework/8.總結之前的方法/1.獲取文件名")] private static void MenuClicked() { Debug.Log(GenerateUnityPackageName()); } [MenuItem("QFramework/8.總結之前的方法/2.複製文本到剪切板")] private static void MenuClicked2() { CopyText("要複製的關鍵字"); } [MenuItem("QFramework/8.總結之前的方法/3.生成文件名到剪切板")] private static void MenuClicked3() { CopyText(GenerateUnityPackageName()); } [MenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage")] private static void MenuClicked4() { ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage"); } [MenuItem("QFramework/8.總結之前的方法/5.打開所在文件夾")] private static void MenuClicked5() { OpenInFolder(Application.dataPath); } [MenuItem("QFramework/8.總結之前的方法/6.MenuItem 復用")] private static void MenuClicked6() { CallMenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage"); OpenInFolder(Path.Combine(Application.dataPath, "../")); } [MenuItem("QFramework/8.總結之前的方法/7.自定義快捷鍵")] private static void MenuClicked7() { Debug.Log("%e 意思是快捷鍵 cmd/ctrl + e"); } #endif } }
其實程式碼量還是比較多的。
而在上一篇中,我們就知道了,這個示例有類命名的問題。我們運氣比較好,剛好可以試著解決一下。
關於類,我們在寫第一個示例的時候就去接觸了,不過筆者並沒有講它,是因為作為一個程式碼設計的工具,類是非常重要的一個概念,它比方法複雜得多,不過今天我們不用全部了解,只需要了解對本示例有用的部分就好了。
我們都知道,在 C# 中方法都是需要在類中實現的。所以類的第一個作用就是方法的集合。
而我們的問題是,對於 OpenInFinder 、ExportPackage 這些方法所在的類的名字比較奇怪。
之所以能意識到問題的存在,是因為筆者知道一個庫不可能僅僅這幾個方法的。如果是僅僅這幾個方法,我們還是可以叫 PreviousFunctions 。因為方法數量比較小,所以用人腦就可以記住了。就算忘記了再去看一遍也很容易記住的。但是到目前為止我們收集了 13 個示例,那麼至少有 13 個方法,在未來隨著時間增長,我們要收集的方法會越來越多。所以給方法進行合理地分類,並把它們放在合適的地方是必須要做的。
不過我們對於對方法分類還是新手,因為到目前為止,筆者沒有在此專欄中提過方法分類這件事,
我們先來看下這些方法是幹嘛的,以及用在哪裡的?
- GenerateUnityPackageName:自動生成文件名,是屬於導出功能的一部分,屬於訂製方法。
- CopyText:複製文本,比較通用。
- OpenInFolder:打開所在文件夾,在 UnityEditor 里比較通用。
- CallMenuItem:復用菜單,在 UnityEditor 里比較通用。
- ExportPackage:導出 Package,在 UnityEditor 比較通用。
很自然地,根據用處可以分為三類,一個是訂製方法,GenerateUnityPackageName,它只能用在導出功能里。在其他的情況下很少適用。
第二種則是 UnityEditor 通用,比如 OpenInFolder 和 CallMenuItem。
第三種則是可能全平台通用的,比如 CopyText。
基於以上我們就按照這種方式去分類。如何分呢?
答案就是使用類,給類起一個類型名字就好。
在之前我們提過,類的第一個作用是方法的集合,它可以放若干個方法。而我們方法已經分好類型了,現在就差給類起一個合適的名字。我們先叫做 Exporter (導出器) 、EditorUtil (編輯器工具)和 CommonUtil (通用工具)。
程式碼如下:
CommonUtil 類
public class CommonUtil { public static void CopyText(string text) { GUIUtility.systemCopyBuffer = text; } }
Exporter 類
public class Exporter { public static string GenerateUnityPackageName() { return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh"); } }
EditorUtil 類
public class EditorUtil { #if UNITY_EDITOR public static void CallMenuItem(string menuPath) { EditorApplication.ExecuteMenuItem(menuPath); } public static void OpenInFolder(string folderPath) { Application.OpenURL("file:///" + folderPath); } public static void ExportPackage(string assetPathName,string fileName) { AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse); } #endif }
這樣就算給方法分好類了,這三個類放在了 PreviousFunctions 類定義位置的上方。
如下程式碼所示:
#if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; using System; using System.IO; namespace QFramework { public class CommonUtil { ... } public class Exporter { ... } public class EditorUtil { ... } public class PreviousFunctions : MonoBehaviour { ... } }
那麼,PreviousFunctions 里以前實現的方法怎麼辦?要進行刪除嘛?
已經刪了的童鞋可能知道,直接刪除會造成編譯問題。因為在第七個示例里,已經用了 PreviousFunctions 里的方法。所以保險起見,不能馬上進行刪除,而是做一步方法的中轉。
例如 PreviousFunction.CopyText 實現如下所示:
public static void CopyText(string text) { CommonUtil.CopyText(text); }
這樣就可以了,ok 了,我們把其他的部分也照著這樣做,程式碼如下。
public static string GenerateUnityPackageName() { return Exporter.GenerateUnityPackageName(); } public static void CopyText(string text) { CommonUtil.CopyText(text); } public static void OpenInFolder(string folderPath) { EditorUtil.OpenInFolder((folderPath)); } #if UNITY_EDITOR public static void CallMenuItem(string menuPath) { EditorUtil.CallMenuItem(menuPath); } public static void ExportPackage(string assetPathName,string fileName) { EditorUtil.ExportPackage(assetPathName, fileName); } #endif
這樣,可以保證功能不失效,也就是遵循了我們的約定和規則之一。
但是這樣還不夠,因為我們逐個整理完示例之後,回過頭來可能會忘記。在這裡筆者介紹一個 C# 的標籤屬性 [System.Obselete(「方法以過時」)] ,只要在方法上加上這個標籤,編譯器就會在使用這個方法的地方報出警告,而警告的內容則是 Obselete 括弧中的 「方法以過時」。
我們先給這五個方法加上,然後觀察下 Unity 的控制台的警告。
程式碼如下:
PreviousFunctions.cs
[Obsolete("方法以過時,請使用 Exporter.GenerateUnityPackageName();")] public static string GenerateUnityPackageName() { return Exporter.GenerateUnityPackageName(); } [Obsolete("方法以過時,請使用 CommonUtil.CopyText(text);")] public static void CopyText(string text) { CommonUtil.CopyText(text); } [Obsolete("方法以過時,請使用 EditorUtil.OpenInFolder(folderPath);")] public static void OpenInFolder(string folderPath) { EditorUtil.OpenInFolder(folderPath); } #if UNITY_EDITOR [Obsolete("方法以過時,請使用 EditorUtil.CallMenuItem(menuPath);")] public static void CallMenuItem(string menuPath) { EditorUtil.CallMenuItem(menuPath); } [Obsolete("方法以過時,請使用 EditorUtil.ExportPackage(assetPathName, fileName);"] public static void ExportPackage(string assetPathName,string fileName) { EditorUtil.ExportPackage(assetPathName, fileName); } #endif
編譯之後的結果如下:
資訊給得非常詳細,這樣我們之後就不會忘記了,只要在方法上有 Obsolete 的方法,在進行整理的時候如果它沒有被引用的時候就可以刪掉了。
現在這幾個方法被第七個示例引用了,所以還不能刪除,而是這一輪示例整理過後,回過頭再整理。
今天新的內容夠多了,我們直接列出完整的 PreviousFuctions.cs 程式碼。
如下:
#if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; using System; using System.IO; namespace QFramework { public class CommonUtil { public static void CopyText(string text) { GUIUtility.systemCopyBuffer = text; } } public class Exporter { public static string GenerateUnityPackageName() { return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh"); } } public class EditorUtil { #if UNITY_EDITOR public static void CallMenuItem(string menuPath) { EditorApplication.ExecuteMenuItem(menuPath); } public static void OpenInFolder(string folderPath) { Application.OpenURL("file:///" + folderPath); } public static void ExportPackage(string assetPathName,string fileName) { AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse); } #endif } public class PreviousFunctions : MonoBehaviour { [Obsolete("方法以過時,請使用 Exporter.GenerateUnityPackageName();")] public static string GenerateUnityPackageName() { return Exporter.GenerateUnityPackageName(); } [Obsolete("方法以過時,請使用 CommonUtil.CopyText(text);")] public static void CopyText(string text) { CommonUtil.CopyText(text); } [Obsolete("方法以過時,請使用 EditorUtil.OpenInFolder(folderPath);")] public static void OpenInFolder(string folderPath) { EditorUtil.OpenInFolder(folderPath); } #if UNITY_EDITOR [Obsolete("方法以過時,請使用 EditorUtil.CallMenuItem(menuPath);")] public static void CallMenuItem(string menuPath) { EditorUtil.CallMenuItem(menuPath); } [Obsolete("方法以過時,請使用 EditorUtil.ExportPackage(assetPathName, fileName);")] public static void ExportPackage(string assetPathName,string fileName) { EditorUtil.ExportPackage(assetPathName, fileName); } #endif #if UNITY_EDITOR [MenuItem("QFramework/8.總結之前的方法/1.獲取文件名")] private static void MenuClicked() { Debug.Log(Exporter.GenerateUnityPackageName()); } [MenuItem("QFramework/8.總結之前的方法/2.複製文本到剪切板")] private static void MenuClicked2() { CommonUtil.CopyText("要複製的關鍵字"); } [MenuItem("QFramework/8.總結之前的方法/3.生成文件名到剪切板")] private static void MenuClicked3() { CommonUtil.CopyText(GenerateUnityPackageName()); } [MenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage")] private static void MenuClicked4() { EditorUtil.ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage"); } [MenuItem("QFramework/8.總結之前的方法/5.打開所在文件夾")] private static void MenuClicked5() { EditorUtil.OpenInFolder(Application.dataPath); } [MenuItem("QFramework/8.總結之前的方法/6.MenuItem 復用")] private static void MenuClicked6() { EditorUtil.CallMenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage"); EditorUtil.OpenInFolder(Path.Combine(Application.dataPath, "../")); } #endif } }
大家發現 PreviousFunctions 這個類里的所有的 MenuItem 方法里的實現,都改成了新的方法。
而筆者刪除了以下方法,原因是知識點和第七個示例重複了,有了第七個示例就不需要這個方法了。
[MenuItem("QFramework/8.總結之前的方法/7.自定義快捷鍵")] private static void MenuClicked7() { Debug.Log("%e 意思是快捷鍵 cmd/ctrl + e"); }
小結
- 要做的事情:
- (完成) 備份:導出文件,並取一個合理的名字。
- 遺留問題:
- (完成一部分) 第八個示例與之前的示例程式碼重複,功能重複。
- (完成) 方法所在類的命名有問題。
- 菜單欄顯示順序問題。
- 約定和規則:
- 每個示例在 QFramework 目錄下創建一個文件夾,文件夾的格式是: 數字.示例的功能
- 每個示例寫一個腳本,腳本中包含可復用的靜態方法和 MenuItem 方法。
- 每寫一個示例進行一次導出,導出的文件名後邊加上日期和時間,這個功能已經在導出功能里內置了。
- 每次有 API 變更的時候做一次備份,備份的名字採用 QFramework_vX.Y.Z 格式。
- 每次進行整理的時候要確保是在功能有效的情況下進行刪除和變更。
- 示例分類:
- 知識學習&收集
- API 收集
- C# 語法實踐
- 庫本身的功能
- 規則實現
- 使用流程提供及優化
- 效率提升(編碼體驗、邏輯復用)
- 項目實用工具收集
- 知識學習&收集
今天的內容就寫到這裡,下一篇再見,拜拜~
轉載請註明地址:涼鞋的筆記:liangxiegame.com
更多內容
-
QFramework 地址:https://github.com/liangxiegame/QFramework
-
QQ 交流群:623597263
-
Unity 進階小班:
- 主要訓練內容:
- 框架搭建訓練(第一年)
- 跟著案例學 Shader(第一年)
- 副業的孵化(第二年、第三年)
- 權益、授課形式等具體詳情請查看《小班產品手冊》:https://liangxiegame.com/master/intro
- 主要訓練內容:
-
關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。