一、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();
}
}