一、EditorWindow类属性及函数

首先提供官方参考文档:API-Reference-EditorWindow

概述: EditorWindow类继承自ScriptableObject类;我们可以通过继承这个类并重写来创建一个自定义的编辑器窗口,它可以随意停靠或放置在编辑器内任意位置,就像unity界面原生窗口一样;

static 属性



static 方法

  • CreateWindow():unity新提供的创建窗口函数;
  • GetWindow() / GetWindowWithRect():获取窗口,可以将窗口停靠在其它类型的窗口上;如下,该函数会获取第一次创建的窗口,如果没有就创建一个;它会自动显示窗口,无需调用open()函数;
EditorWindow.GetWindow<FirstEditorWindow>();

public 属性

  • position (Rect):窗口位置
  • maxSize/minSize (Vector2):最大最小尺寸

public 方法

  • Show() / Close():

消息回调

  • OnGUI():

Inherited:

static 属性



static 方法



public 属性



public 方法



消息回调

  • Awake():
  • OnEnable() / OnDisable():当窗口被创建时调用,可以在OnEnable()设置窗口的一些属性;

二、相关的简单GUI类

GUIContent:一种GUI元素,构造函数共包含三个参数,有多种构造函数类型;这是一个非常重要的类,几乎所有的控件都会用到它作为显示文字的参数;

GUIContent(string text,Texture image,string tooltip);

三、应用

1.创建自定义EditorWindow的三步骤

  • 创建一个继承自EditorWindow的脚本;
  • 使用代码来触发这个窗口的显示;
  • 在OnGUI回调函数中绘制GUI;
class MyWindow : EditorWindow {
    [MenuItem ("Window/My Window")]

    public static void  ShowWindow () {
        EditorWindow.GetWindow(typeof(MyWindow));
    }
    
    void OnGUI () {
        // The actual window code goes here
    }
}

2.窗口的停靠

有时候,我们希望窗口能够和其它已有窗口绑定在一起,就需要在GetWindow()中传入参数;

窗口停靠时一般就两种方式,停靠在场景视图中,停靠在属性面板中,下面分别给出示例:

//停靠在监视窗口
FirstEditorWindow window = EditorWindow.GetWindow<FirstEditorWindow>(typeof(UnityEditor.InspectorWindow));
//停靠在场景窗口
FirstEditorWindow window = EditorWindow.GetWindow<FirstEditorWindow>(typeof(UnityEditor.SceneView));

3.EditorWindow&ScriptableObject

如果需要保存一些配置文件,可以将EditorWindow和ScriptableObject配合使用;

首先定义一个ScriptableObject的配置类,然后在打开窗口时加载和保存数据即可;

public class GameSettingsData : ScriptableObject
{
    public bool isFPSOpen = true;
}

private void Awake()
    {
        gameSettings = AssetDatabase.LoadAssetAtPath<GameSettingsData>(dataRelativePth);
        //判断有没有配置表数据,如果没有,则创建;有,则加载
        //if (!File.Exists(Application.dataPath+dataRelativePth))
        if (!gameSettings)
        {
            gameSettings = ScriptableObject.CreateInstance<GameSettingsData>();
            AssetDatabase.CreateAsset(gameSettings,dataRelativePth);
        }
        Init();
        
    }

    private void Init() {
        isFPSOpen = gameSettings.isFPSOpen;
    }

4.注意GUI控件的排列布局以及锚点设置

通过获取当前窗口的Rect属性来设置手动设置控件的位置,当然:控件的Rect是相对于当前Window的;

Rect windowRect = this.position;

5.小案例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text.RegularExpressions;
using System.IO;

public class TextureSpitWindow : EditorWindow
{
    // 设置窗口参数
    public Texture2D sourceTexture;
    public Texture2D maskTexture;
    public string sourcePath;
    public string sourceFolerPath; // 分割结果的存储路径
    public string retPath = ""; // 分割结果的存储路径
    // public List<Texture2D> allTextureList = new List<Texture2D>(); // 放置所有生成的texture
    Dictionary<byte, Texture2D> allTextureList = new Dictionary<byte, Texture2D>();

    [MenuItem ("Tools/Split Texture")]
    public static void  ShowWindow () {
        EditorWindow thisWindow = EditorWindow.GetWindow(typeof(TextureSpitWindow));
        thisWindow.titleContent = new GUIContent("切割图片");
        thisWindow.position = new Rect(Screen.width/2, Screen.height/2, 600, 800);
    }

    void OnGUI()
    {
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("选择切割图片");
        sourceTexture = EditorGUILayout.ObjectField(sourceTexture, typeof(Texture2D), true) as Texture2D;
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("选择遮罩图片");
        maskTexture = EditorGUILayout.ObjectField(maskTexture, typeof(Texture2D), true) as Texture2D;
        EditorGUILayout.EndHorizontal();

        sourcePath = AssetDatabase.GetAssetPath(sourceTexture);

        if(sourceTexture != null){
            string pattern = "/" + sourceTexture.name + "\\.\\w+";
            Debug.Log(sourcePath);
            Debug.Log(pattern);
            Regex rgx = new Regex(pattern);
            sourceFolerPath = rgx.Replace(sourcePath, "");
            
            string sourceTexName = sourceTexture.name;
            retPath = sourceFolerPath + "/" +sourceTexName;
        }

        EditorGUILayout.BeginHorizontal();

        EditorGUILayout.LabelField("存储路径");
        EditorGUILayout.TextField(retPath);
        if (GUILayout.Button("选择存储路径"))
        {
            retPath = EditorUtility.OpenFolderPanel("选择存储路径", retPath, "");
        }
        
        EditorGUILayout.EndHorizontal();

        if (GUILayout.Button("生成"))
        {
            Split();
        }
    }

    void Split(){
        SplitTexture();
        SaveSplitTexture();
    }

    void SplitTexture(){
        int width = maskTexture.width;
        int height = maskTexture.height;

        for(int i = 0; i < width; i++){
            for(int j = 0; j < height; j++){
                Color pixelCol = maskTexture.GetPixel(i, j);
                Color32 maskCol = pixelCol;
                if(allTextureList.ContainsKey(maskCol.a) == false){
                    Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
                    allTextureList.Add(maskCol.a, tex);
                    tex.SetPixel(i, j, pixelCol);
                }
            }
        }
        foreach(KeyValuePair<byte, Texture2D> tex in allTextureList){
            tex.Value.Apply();
        }
    }

    void SaveSplitTexture(){
        if(AssetDatabase.IsValidFolder(retPath) == false){
            AssetDatabase.CreateFolder(sourceFolerPath, sourceTexture.name);
        }

        if(AssetDatabase.IsValidFolder(retPath) == false){
            EditorUtility.DisplayDialog("文件路径错误", "错误的文件夹:" + retPath, "确定", null);
            return;
        }

        for(int i = 10; i < sourceTexture.width; i++){
            for(int j = 10; j < sourceTexture.height; j++){
                sourceTexture.SetPixel(i, j, new Color(1, 0, 0, 1));
            }
        }
        sourceTexture.Apply();
        // int splitTexCount = 0;
        // foreach(KeyValuePair<byte, Texture2D> tex in allTextureList){
        //     splitTexCount++;
        //     AssetDatabase.CreateAsset(tex.Value, retPath + "/" + splitTexCount + ".png");
        // }

        AssetDatabase.SaveAssets();
    }
}