本文首發自inspoy的雜七雜八 | 菜雞inspoy的學習記錄
前言
專案這個東西果然還是做起來才會發現坑,儘量早填上好了
View Prefab
上一篇的vwTest這個UI預設體的根節點vwTest是一個Panel控制元件,內容是個背景框,這個想了下不太妥,應該改一下,包含具體內容的控制元件不應該在根節點中,現在把根節點改成透明panel,尺寸為整個View的尺寸。背景框相關的放到根節點下邊。
新增UI
為了更方便地新增UI,我給SFSceneManager
加了幾個靜態方法,通過指定預設體、父節點的transform、層級順序(越大越靠前),可以簡化新增UI的步驟
static public GameObject addView(GameObject prefab, Transform trans = null, int sibIdx = -1)
{
if (prefab == null)
{
SFUtils.logWarning("prefab為空");
return null;
}
Transform parent = trans;
if (parent == null)
{
parent = SFSceneManager.uiRoot.transform;
}
var GO = GameObject.Instantiate(prefab, parent) as GameObject;
if (zOrder >= 0)
{
GO.SetSiblingIndex(sibIdx);
}
return GO;
}
static public GameObject addView(string viewName, Transform trans = null, int sibIdx = -1)
{
var prefab = Resources.Load(viewName) as GameObject;
if (prefab == null)
{
SFUtils.logWarning(string.Format("找不到view:{0}", viewName));
return null;
}
return SFSceneManager.addView(prefab, trans, sibIdx);
}複製程式碼
只提供第一個引數的話預設會加在整個UI介面的最前面,當然也可以指定加在某個自定義節點下面,也可以指定層級順序
UI程式碼生成
設想的工作流程是這樣:UI設計人員修改或建立UI Prefab,在Project檢視裡右鍵點選Prefab,會有一個匯出生成程式碼的選單項,點選它,就可以一鍵生成程式碼並且自動把View指令碼掛載到Prefab上。
為了實現這種效果,就必須擴充套件Unity的編輯器。
Unity提供了非常豐富的編輯器擴充套件介面,如新增選單項,自定義Inspector皮膚,甚至自定義Scene檢視中的輔助UI。
我們這裡只使用新增選單項的功能:
在Assets中建立Editor資料夾,在裡面建立一個C#指令碼,檔名隨意,然後寫一個類,類名也隨意:
public class SFUIExporterMenu
{
[MenuItem("Assets/SF/Export UI")]
private static void exportUI()
{
generateUICode(Selection.activeGameObject);
}
}複製程式碼
Selection.activeGameObject
表示當前在Project檢視中選中的Prefab,如果選中的不是Prefab這個就是null。MenuItem
特性表示這個方法用於擴充套件選單項,引數"Assets/SF/Export UI"
表示這個自定義選單項的位置,在Assets選單中新增的話,在Asset上右鍵就可以看到相應的選單項了
不過如果我手滑右鍵了其他非Prefab,顯然這時是不應該允許匯出的,因為這不是UI,所以還要加一個驗證,選中非法的Asset時將選單項置灰。
[MenuItem("Assets/SF/Export UI", true)]
private static bool exportUIValidation()
{
var GO = Selection.activeGameObject;
return GO != null && GO.name.Substring(0, 2) == "vw";
}複製程式碼
特性的第二個引數true代表這個方法是用來驗證合法性的,返回true為合法,false非法。
然後就是根據Prefab來生成程式碼並儲存了
string viewName = prefab.name.Substring(2);
string viewFilepath = string.Format("Assets/Scripts/UI/SF%sView.cs", viewName);
var viewFile = new FileInfo(viewFilepath);
var sw = viewFile.CreateText();
sw.Write(viewContent);
sw.Close();
// 生成viewContent的邏輯比較複雜,不在文章中貼出了複製程式碼
自動掛載指令碼
當然最後要把生成的View指令碼掛載在Prefab上
string componentName = "SF" + viewName + "View";
AssetDatabase.Refresh();
var component = prefab.GetComponent(componentName);
if (component == null)
{
prefab.AddComponent(getTypeByName(componentName));
}複製程式碼
下面是根據名稱獲取型別的方法,因為Component.AddComponent(string)已經被官方在5.0版本中廢棄了,我們必須通過其他的方式曲線救國,下面的方法參考了ぼちつく的部落格,這個方法的執行效率必然很低,尤其是專案規模大起來之後,不過至少給編輯器用的擴充套件不會在遊戲執行時的階段執行,而且也不會太頻繁,所以效能稍微差一點也是可以接受的
private static Type getTypeByName(string className)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type type in assembly.GetTypes())
{
if (type.Name == className)
{
return type;
}
}
}
return null;
}複製程式碼
其他
研究編輯器擴充套件的時候發現了一個好玩兒的東西,繼承UnityEditor.AssetModificationProcessor
並實現OnWillCreateAsset()
方法可以在建立Assets時收到通知,可以利用這個方法來給之後建立的指令碼加上頭部檔案資訊的註釋。程式碼如下:
public class SFScriptHeaderGenerator : UnityEditor.AssetModificationProcessor
{
static private string header =
"/**
" +
" * Created on ##DateTime## by ##UserName##
" +
" * All rights reserved.
" +
" */
";
public static void OnWillCreateAsset(string path)
{
path = path.Replace(".meta", "");
if (path.EndsWith(".cs"))
{
string fullText = header;
fullText = fullText.Replace("##DateTime##", System.DateTime.Now.ToString("yyyy/MM/dd"));
fullText = fullText.Replace("##UserName##", System.Environment.UserName);
fullText += File.ReadAllText(path);
File.WriteAllText(path, fullText);
}
}
}複製程式碼
效果如圖:
完整程式碼
上面貼出的程式碼片段由於篇幅限制只保留了關鍵部分,完整的程式碼可在我的github上找到