Unity 遊戲框架搭建 2019 (二十三、二十四) 備份與版本號&危險的操作

先列出上一篇的總結:

  1. 要做的事情:
    • 備份:導出文件,並取一個合理的名字。
  2. 遺留問題:
    • 第八個示例與之前的示例代碼重複,功能重複。
  3. 約定和規則:
    • 每個示例在 QFramework 目錄下創建一個文件夾,文件夾的格式是: 數字.示例的功能
    • 每個示例寫一個腳本,腳本中包含可復用的靜態方法和 MenuItem 方法。
    • 每寫一個示例進行一次導出,導出的文件名後邊加上日期和時間,這個功能已經在導出功能里內置了。
  4. 示例分類:
    1. 知識學習&收集
      • API 收集
      • C# 語法實踐
    2. 庫本身的功能
      • 規則實現
      • 使用流程提供及優化
      • 效率提升(編碼體驗、邏輯復用)
      • 項目實用工具收集

我們先解決第一個問題,備份問題。

文件命名

導出文件很容易,但是文件的名字就比較有講究了。現在我們的庫呢第一次進行比較大的整理,未來說不定有很多次這樣的整理。所以文件命名應該能夠體現庫的某一個階段。

我們目前的命名規是 QFramework_日期_時,這種命名能夠體現庫的某個時間點,從而我們能夠在多個文件之間找到最後一次更新的庫。但是這樣還不夠。如果現在想找到第一篇文章的庫,那要去找到第一篇文章寫的時間。找到這個庫的難度會隨着時間越來越困難。不過這種命名已經完成了它的使命,最起碼從第一個示例到現在沒出現太大的問題。

但是有新的要求了。因為示例的代碼會被刪除,這算是代碼的比較大的變更了,而且看專欄的童鞋所在的階段也不同,有的童鞋剛剛看第一篇而有的童鞋已經完結了。所以要考慮庫的各個階段。

如何表示庫的某個階段呢?

有一種比較好的方式,就是按照文章的標題命名,比如這篇文章之前的庫名字為 QFramework_19_開始整理,或者按照最新的示例名字,比如 QFramwork_13 GameObject 顯示、隱藏簡化。但是這樣的名字過了很久回過頭來找文件還是會要凌亂好一會,所以並不合適。

比較合適的是用版本號,我們生活中使用的軟件都有版本號,比如 Unity 5.6.5 或者 2017.2 等等。對於開發者來說版本號已經是比較熟悉的東西了。

使用版本號命名的文件格式為: QFramework_vX.Y.Z
X 是主版本號,用於不向前兼容的更新。
Y 是中間版本,用於可向前兼容的功能性更新。
Z 是小版本號,用於功能完善和 bug 修復的更新。

一般都是從 v0.1.1 這個版本開始發佈的,但是這個版本呢叫做 mvp 版本,也就是最小可驗證版本。我們的庫還沒有到這個階段,而且版本號這個東西剛開始用,是用於方便自己記憶的,也是為了做一個備份而已,還不用發佈給別人用。所以我們的備份版本為 v0.0.0 。

還有一點要注意的是,v0.x.y 這個階段的版本可以不考慮向前兼容。但是如果已經 v0.1.1 了,就要發佈出去了,也有用戶在使用了,那就要儘可能要做到向前兼容。

向前兼容的意思是,用戶升級版本不必更改 API 的使用。

開始備份

在上一小節得到了結論。

現在,我們要開始着手導出。使用導出工具導出文件,並手動把文件名字命名為 QFramework_v0.0.0。

這樣備份就算完成了。

可以把它放到網盤或者硬盤裡。這樣就可以安心整理代碼了。

小結

版本號算是約定和規則的內容。

危險的操作

今天開始,進行逐個示例的整理。

第一個示例

先看第一個。

#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"));  		}  	}  }  

因為在第八個示例里給提取成方法了,所以這個示例可以直接刪除了。

刪除之後的文件結構如下圖所示。
006tNc79gy1fzfr4kvi6sj30mm0c0q4w.jpg

第二個示例

代碼如下

#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 = "要複製的關鍵字";  		}  	}  }  

這個也在第八個示例中提取成方法了,所以這部分也可以直接刪了,
刪除之後的文件結構如下圖所示:
006tNc79gy1fzfr4oojhfj30ma0b475x.jpg

第三個示例

代碼如下:

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");  		}  	}  }  

這個示例是是原來示例一和示例二的結合,同樣在第八個示例中提取成方法了,果斷刪。

第四個示例

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  	}  }  

同理,果斷刪。

第五個示例

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  	}  }  

同理,果斷刪。

第六個示例

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  	}  }  

同理果斷刪

第七個示例

#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  	}  }  

第七個示例是快捷鍵功能,不過我們沒有在第八個示例中提取成方法,因為快捷鍵不可以復用。
而這個是我們目前導出功能的核心代碼,所以比較重要,這個就不能刪除了。

通過觀察可知,MenuClicked 方法中的對 MenuItem "QFramework/6.MenuItem 復用" 的復用,已經失效了,因為第六個示例被我們刪掉了。

不過沒關係,我們在第八個示例中有提取成方法。而使用方法完成導出功能的代碼如下:

		[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");  		}  

不過在寫第八個示例的時候還是在用 MenuItem 進行方法的調用,雖然那時候已經學習了調用 public 方法,但是由於 public 方法的運用沒有那麼純熟,想不到是很正常的。但是現在不一樣了,我們用 public 方法進行非常多的方法設計練習了,所以直接着手整理就好了。

整理後的第七個示例代碼如下:

using System.IO;    #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()  		{  			var generatePackageName = PreviousFunctions.GenerateUnityPackageName();    			PreviousFunctions.ExportPackage("Assets/QFramework",generatePackageName + ".unitypackage");    			PreviousFunctions.OpenInFolder(Path.Combine(Application.dataPath, "../"));  		}  #endif  	}  }  

這些方法都是自己實現的,調用起來比較親切了吧?

等待編譯之後,再按下快捷鍵 ctrl/cmd + e,就自動導出成功了,感受到滿滿的成就感。

不過命名方式還是 QFramework_日期_時,不過沒關係,這不算真正的導出,只是測試而已,我們還沒有整理結束。整理這個階段雖然在文章中要寫很久,但是實際過程中可能幾分鐘就整理完了。但是整理這個過程寫文章很久的原因是,因為在整理的候筆者的內心戲份非常多,也就是思考經過會非常多。而筆者呢都要把它們展示出來,這樣大家理解了這些,就不難自己再造個 QFramework 了甚至更好,而本系列專欄的亮點就是這個。

到此呢,我們成功了。

不過以上代碼呢,還存在一些問題:

  1. 方法所在的類名比較奇怪,比如 GenerateUnityPackageName 和 ExportPackage 所在的類都是 PreviousFunctions,PreviousFunctions 意思是之前的方法。是為了配合示例的名字而起的。

  2. 菜單欄的顯示順序問題,目前菜單欄的顯示順序有點混亂,如下。

006tNc79gy1fzfr4v9zutj30du05b77y.jpg
這個問題存在了好久了,不過沒辦法,因為一到七個示例已經寫好了,當時沒辦法更改,在整理階段是改掉這個問題的比較好的時機。

因為在本篇文章的開頭,有說過我們一個一個示例進行整理,所以這兩個問題,我們先記錄下來,等每個示例都整理了一遍之後,再看看如何解決。

除了以上存在的這兩個問題,我們還做了一個比較危險的操作,就是先刪除了第六個示例,等到第七個示例的時候發現功能失效了,還好在第八個示例中我們有相同的功能實現,否則就要去靠記憶力去恢復功能了,或者靠我們 v0.0.0 版本的備份進行恢復。這樣會耗費我們額外的精力和時間,是很不值當的。

基於這個經驗,我們在整理代碼的時候,要優先確保功能是有效的,然後再進行一些變更或者刪除的操作。

小結

把以上兩個問題記錄下來,我們的總結又可以更新了,更新後如下。

  1. 要做的事情:
    • (完成) 備份:導出文件,並取一個合理的名字。
  2. 遺留問題:
    • (完成一部分) 第八個示例與之前的示例代碼重複,功能重複。
    • 方法所在類的命名有問題。
    • 菜單欄顯示順序問題。
  3. 約定和規則:
    • 每個示例在 QFramework 目錄下創建一個文件夾,文件夾的格式是: 數字.示例的功能
    • 每個示例寫一個腳本,腳本中包含可復用的靜態方法和 MenuItem 方法。
    • 每寫一個示例進行一次導出,導出的文件名後邊加上日期和時間,這個功能已經在導出功能里內置了。
    • 每次有 API 變更的時候做一次備份,備份的名字採用 QFramework_vX.Y.Z 格式。
    • 每次進行整理的時候要確保是在功能有效的情況下進行刪除和變更。
  4. 示例分類:
    1. 知識學習&收集
      • API 收集
      • C# 語法實踐
    2. 庫本身的功能
      • 規則實現
      • 使用流程提供及優化
      • 效率提升(編碼體驗、邏輯復用)
      • 項目實用工具收集

除了更新了兩個問題以外,又在約定和規則中增加了關於備份的規則,描述得很清楚了,這裡不多說了。

今天的內容就這些,拜拜~

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

更多內容