用Unity做個遊戲(五) – 編輯器擴充套件

Inspoy Cheng發表於2019-03-02

本文首發自inspoy的雜七雜八 | 菜雞inspoy的學習記錄

前言

專案這個東西果然還是做起來才會發現坑,儘量早填上好了

View Prefab

上一篇的vwTest這個UI預設體的根節點vwTest是一個Panel控制元件,內容是個背景框,這個想了下不太妥,應該改一下,包含具體內容的控制元件不應該在根節點中,現在把根節點改成透明panel,尺寸為整個View的尺寸。背景框相關的放到根節點下邊。

用Unity做個遊戲(五) – 編輯器擴充套件
0501

用Unity做個遊戲(五) – 編輯器擴充套件
0502

新增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上右鍵就可以看到相應的選單項了

用Unity做個遊戲(五) – 編輯器擴充套件
0503

不過如果我手滑右鍵了其他非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);
        }
    }
}複製程式碼

效果如圖:

用Unity做個遊戲(五) – 編輯器擴充套件
0504

完整程式碼

上面貼出的程式碼片段由於篇幅限制只保留了關鍵部分,完整的程式碼可在我的github上找到

相關文章