­

Unity 遊戲框架搭建 2019 (九~十二) 第一章小結&第二章簡介&第八個示例

  • 2020 年 3 月 27 日
  • 筆記

第一章小結

為了強化教程的重點,會在合適的時候進行總結與快速複習。
006tNc79gy1fzdd6su2bvj312j0qfgsk.jpg

第二章 簡介

在第一章我們做了知識庫的準備,從而讓我們更高效地收集示例。

在第二章,我們就用準備好的導出工具試着收集幾個示例,這些示例中有的是我們後續庫的基礎工具,也有的是在項目中非常實用的小工具,還有一些示例是實踐了在框架搭建方向上非常重要的 C# 語法知識。

第二章大綱如下。

006tNc79gy1fzdh9eedxwj30gr0dhwg2.jpg

第八個示例(一)

在之前,我們完成了一個導出的功能。但是在完成這個功能的過程中,我們也遇到了一些問題。我們回憶一下,在《MenuItem 復用》的這篇文章中,我們想對如下代碼進行復用。

using System;  #if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;    namespace QFramework  {  	public class ExportUnityPackage : MonoBehaviour  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/4.導出 UnityPackage")]  		private static void MenuClicked()  		{  			var assetPathName = "Assets/QFramework";  			var fileName = "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh") + ".unitypackage";  			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);  		}  #endif  	}  }  

這個方法被聲明為 private 權限,所以是不可以被訪問的。不過還好,MenuItem 可以復用,問題就勉強解決了。但是每次復用的時候要手打或複製一遍字符串未免也太麻煩了,而且也容易出錯。那麼還有其他的方式么?

這就是今天要解決的問題。當別的示例想調用以上的方法的時候,由於是 private 類型,所以只能通過 MenuItem 的方式進行調用,而 MenuItem 這種方式比較麻煩。

解決方案大家很容易就想到,把 private 改成 public 就行了。這樣從達成代碼復用這個目的的這個角度來說,問題是算是解決了,但是以筆者的經驗來講,這樣還會有一些問題,就到這樣就好。我們好好享受這個勝利的果實。

到這裡如果有不知道 private 和 public 關鍵字的作用是什麼的童鞋,那麼筆者就簡單提一句,使用 private 定義的方法只能在類的內部或者內部類中被調用,則不可以被子類和外部類調用,而使用 public 定義的方法,如果所在類也是 public 類型的,那麼在任意地方可以被調用。

我們要怎麼用這個 public 關鍵字呢?是在寫示例的時候,僅僅把 private 改成 public 就行了嘛?有沒有更好用的方法?

如果僅僅是把 private 改成 public 不是最好的方法,因為通過 MenuItem 修飾的方法,不能傳參數,也沒有返回值。不能傳參或不能返回值的話,一個方法的使用就會受限。

所以筆者給出的方案是,再創建一個靜態的 public 方法,而這個方法被 MenuItem 調用。這樣的好處是,我們在創建一個方法的時候,可以好好地利用參數和返回值進行設計。

說了這麼多,終於得到了一個明確的方案。我們來通過今天的第八個示例快速試一下。

第八個示例

第八個示例是什麼呢,就是在第八個示例中,把所有的示例都提取成方法,並再次完成導出的功能。

首先第一個示例代碼如下:

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;  using System;    namespace QFramework  {  	public static class LogFileName  	{  		#if UNITY_EDITOR  		[MenuItem("QFramework/1.生成 unitypackage 名字")]  		#endif  		private static void GenerateUnityPackageName()  		{  			Debug.Log("QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh"));  		}  	}  }  

這個示例的核心是 DateTime.Now.ToString() 這個代碼。之所以是核心,是因為沒用過它的人,第一次用會感覺很陌生,而且 Unity 和 C# 的 API 有那麼多,怎麼可能一個一個全部記住呢?所以就寫了這樣的一個示例,以便日後,要用的時候迅速翻閱這個代碼就可以知道怎麼用。隨着時間,這個 API 用的次數會越來越多,慢慢自己就記住了。但是就算記住了,也有可能會忘的那一天,所以還有得讓它在我們的庫中存在。

OK,我們直接看提取後的代碼。

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;  using System;    namespace QFramework  {  	public class PreviousFunctions : MonoBehaviour  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/1.獲取文件名")]  #endif  		private static void MenuClicked()  		{  			Debug.Log(GenerateUnityPackageName());  		}    		public static string GenerateUnityPackageName()  		{  			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");  		}  	}  }  

首先注意,MenuItem,由於第八個示例是有很多的東西,所以就又加了一級菜單。

點擊以上菜單,執行結果正確。

第八個示例(二)

在上一篇我們抽取了第一個示例的方法,我們在這篇在接着往下抽取。

提取第二個示例

先看第二個示例的代碼。

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;    namespace QFramework  {  	public static class CopyText2Clipboard  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/2.複製文本到剪切板")]  #endif  		private static void CopyText()  		{  			GUIUtility.systemCopyBuffer = "要複製的關鍵字";  		}  	}  }  

核心 API 是 GUIUtility.systemCopyBuffer,而後邊的內容,應該是使用的時候自己填的。所以要創建一個 string 類型的參數,用來接收要複製的內容。抽取後的方法如下。

#if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/2.複製文本到剪切板")]  #endif  		private static void MenuClicked2()  		{  			CopyText("要複製的關鍵字");  		}    		public static void CopyText(string text)  		{  			GUIUtility.systemCopyBuffer = text;  		}  

提取第三示例

我們接着看第三個示例

using System;  #if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;    namespace QFramework  {  	public class GenerateUnityPackageName2ClipBoard  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/3.生成文件名到剪切板")]  #endif  		private static void MenuClicked()  		{  			GUIUtility.systemCopyBuffer = "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");  		}  	}  }  

第三個示例和第一個和第二個示例重複了所以沒有抽取的必要。不過,我們還是要實現與第三個 MenuItem 同等的功能的。

代碼如下:

#if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/3.生成文件名到剪切板")]  #endif  		private static void MenuClicked3()  		{  			CopyText(GenerateUnityPackageName());  		}  

提取第四示例

第四個示例代碼如下:

using System;  #if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;    namespace QFramework  {  	public class ExportUnityPackage : MonoBehaviour  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/4.導出 UnityPackage")]  		private static void MenuClicked()  		{  			var assetPathName = "Assets/QFramework";  			var fileName = "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh") + ".unitypackage";  			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);  		}  #endif  	}  }  

核心是 AssetDatabase.ExportPackage 這個 API。一般情況下 ExportPackageOptions 都是用 Recurse。所以只聲明兩個參數就好了。一個是 assetPathNam,一個是 fileName。抽取後的方法如下。

#if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage")]  		private static void MenuClicked4()  		{  			ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage");  		}  #endif    		public static void ExportPackage(string assetPathName,string fileName)  		{  			#if UNITY_EDITOR  			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);  			#endif  		}  

提取第五個示例

首先看代碼:

using System;  #if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;    namespace QFramework  {  	public class OpenInFolder  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/5.打開所在文件夾")]  		private static void MenuClicked()  		{  			Application.OpenURL("file:///" +  Application.dataPath);  		}  #endif  	}  }  

核心的 API 就是 OpenURL,在打開文件夾的時候,一般路徑的前綴是固定的。提取成如下:

#if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/5.打開所在文件夾")]  		private static void MenuClicked5()  		{  			OpenInFolder(Application.dataPath);  		}  #endif  		public static void OpenInFolder(string folderPath)  		{  			Application.OpenURL("file:///" +  folderPath);    		}  

提取第六個示例

先看代碼

using System.IO;  #if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;    namespace QFramework  {  	public class ReuseMenuItem : MonoBehaviour  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/6.MenuItem 復用")]  		private static void MenuClicked()  		{  			EditorApplication.ExecuteMenuItem("QFramework/4.導出 UnityPackage");  			Application.OpenURL("file:///" + Path.Combine(Application.dataPath, "../"));  		}  #endif  	}  }  

核心 API 是 EditorApplication.ExecuteMenuItem。
提取方法後的代碼如下。

#if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/6.MenuItem 復用")]  		private static void MenuClicked6()  		{  			CallMenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage");  			OpenInFolder(Path.Combine(Application.dataPath, "../"));  		}    		public static void CallMenuItem(string menuPath)  		{  			EditorApplication.ExecuteMenuItem(menuPath);  		}  #endif  

提取第七個示例

先看代碼:

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;    namespace QFramework  {  	public class CustomShortCut : MonoBehaviour  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/7.自定義快捷鍵 %e")]  		private static void MenuClicked()  		{  			EditorApplication.ExecuteMenuItem("QFramework/6.MenuItem 復用");  		}  #endif  	}  }  

這個呢是自定義快捷鍵,所以目前沒有辦法復用,只能記在代碼里了。在這裡我們直接輸出一句話就好。
代碼如下:

#if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/7.自定義快捷鍵")]  		private static void MenuClicked7()  		{  			Debug.Log("%e 意思是快捷鍵 cmd/ctrl + e");  		}  #endif  

到此呢,第八個示例的代碼算寫完了。
如下:

#if UNITY_EDITOR  using UnityEditor;  #endif    using UnityEngine;  using System;  using System.IO;    namespace QFramework  {  	public class PreviousFunctions : MonoBehaviour  	{  #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/1.獲取文件名")]  #endif  		private static void MenuClicked()  		{  			Debug.Log(GenerateUnityPackageName());  		}    		public static string GenerateUnityPackageName()  		{  			return "QFramework_" + DateTime.Now.ToString("yyyyMMdd_hh");  		}    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/2.複製文本到剪切板")]  #endif  		private static void MenuClicked2()  		{  			CopyText("要複製的關鍵字");  		}    		public static void CopyText(string text)  		{  			GUIUtility.systemCopyBuffer = text;  		}    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/3.生成文件名到剪切板")]  #endif  		private static void MenuClicked3()  		{  			CopyText(GenerateUnityPackageName());  		}    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage")]  		private static void MenuClicked4()  		{  			ExportPackage("Assets/QFramework",GenerateUnityPackageName() + ".unitypackage");  		}  #endif    		public static void ExportPackage(string assetPathName,string fileName)  		{  			#if UNITY_EDITOR  			AssetDatabase.ExportPackage(assetPathName, fileName, ExportPackageOptions.Recurse);  			#endif  		}    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/5.打開所在文件夾")]  		private static void MenuClicked5()  		{  			OpenInFolder(Application.dataPath);  		}  #endif  		public static void OpenInFolder(string folderPath)  		{  			Application.OpenURL("file:///" +  folderPath);  		}    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/6.MenuItem 復用")]  		private static void MenuClicked6()  		{  			CallMenuItem("QFramework/8.總結之前的方法/4.導出 UnityPackage");  			OpenInFolder(Path.Combine(Application.dataPath, "../"));  		}    		public static void CallMenuItem(string menuPath)  		{  			EditorApplication.ExecuteMenuItem(menuPath);  		}  #endif    #if UNITY_EDITOR  		[MenuItem("QFramework/8.總結之前的方法/7.自定義快捷鍵")]  		private static void MenuClicked7()  		{  			Debug.Log("%e 意思是快捷鍵 cmd/ctrl + e");  		}  #endif    	}   }  

代碼有點辣眼睛,因為宏定義太多了,並且 MenuItem 方法和 public 方法交叉使用,所以我們整理一下,整理後的代碼如下。

#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 CallMenuItem(string menuPath)  		{  			EditorApplication.ExecuteMenuItem(menuPath);  		}    		public static void OpenInFolder(string folderPath)  		{  			Application.OpenURL("file:///" +  folderPath);  		}    #if UNITY_EDITOR  		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  	}   }  

逐個執行菜單,運行結果全部正確。

到此呢,我們可以進行一次導出了。

ok,今天的內容就這些。

轉載請註明地址:涼鞋的筆記:liangxiegame.com

更多內容