在过去十年中,Unity一直是开发游戏的绝佳平台,为开发人员提供大量工具:渲染引擎,物理引擎,动画系统,音频混合器等。但是,在创建关卡或生成游戏内数据时,Unity不足,因为每个游戏都是独一无二的,需要不同种类的工具。值得庆幸的是,Unity为我们的开发人员提供了一个API,可以创建我们自己的编辑器窗口,自定义抽屉和检查器面板。在这一系列的博客文章中,我将向您展示我们如何在Gram Games中为设计师和艺术家在Unity中开发自定义编辑器。我们将首先创建一个编辑器窗口,在其中放置两个面板,然后使其可调整大小。在下一篇文章中,我们将该窗口转换为Unity自己的控制台窗口的克隆。


那么,让我们开始吧!首先,我们将创建一个空的Unity项目,并在Assets下添加一个名为Editor的文件夹。如果您在Unity中为文件夹指定某些名称,它将以特殊方式处理其内容。编辑器就是其中一个名称,此文件夹中的脚本将成为Unity自己编辑器的一部分。那么,让我们构建一个编辑器窗口脚本:进入刚刚创建的Editor文件夹,右键单击,然后选择Create - > C#Script。您也可以选择Editor Test C#Script,但我们会改变所有内容,所以它实际上并不重要。将脚本命名为ResizablePanels,然后在您喜欢的文本编辑器中打开它(在Gram Games中我们更喜欢Xamarin)。

由于这将是一个编辑器窗口,因此该类应该来自EditorWindow而不是MonoBehaviour。 EditorWindow类驻留在UnityEditor命名空间中,因此我们也需要添加它。


using 
  UnityEngine; 
 
 
 
using 
  UnityEditor; 
 
 
 
 
 
 
 
public 
  class 
  ResizablePanels : 
  EditorWindow
 
 

   { 
 
 
 
 
 
 
 

   }



编辑器窗口需要初始化静态方法。 在这个方法中,我们将构建窗口并(可选)给它一个标题。 GetWindow()是一个EditorWindow方法,它创建窗口(如果它不存在),或者查找并关注它(如果存在)。

但是,静态方法本身是不够的,我们还需要添加一个按钮或类似的东西,让我们的用户在Unity中打开窗口。 值得庆幸的是,已经有一个名为MenuItem的属性,它将一个菜单项添加到Unity的菜单栏并运行它应用的方法。 因此,以下代码将创建您可以在Unity中创建的最基本的编辑器窗口。


using 
  UnityEngine; 
 
 
 
using 
  UnityEditor; 
 
 
 
 
 
 
 
public 
  class 
  ResizablePanels : 
  EditorWindow
 
 

   { 
 
 
 
MenuItem( 
  "Window/Resizable Panels")] 
 
 
 
private 
  static 
  void 
  OpenWindow() 
 
 
 

   { 
 
 
 
ResizablePanels 
  window = 
  GetWindow< 
  ResizablePanels>(); 
 
 
 
window. 
  titleContent = 
  new 
  GUIContent( 
  "Resizable Panels"); 
 
 
 

   } 
 
 
 

   }



这是菜单项:

unity在编辑模式下编译 unity 编辑器_unity在编辑模式下编译

这是我们点击它时打开的窗口:

unity在编辑模式下编译 unity 编辑器_unity在编辑模式下编译_02

为了在这个窗口中绘图,我们将使用OnGUI()方法(是的,Unity自己的编辑器系统仍然使用旧的GUI系统,它可能不会长时间改变)。但首先,我们需要两个矩形来定义我们的面板。我还将在他们自己的方法中绘制这些面板,所以当我们处理它时,我们也应该添加这些方法。


using 
  UnityEngine; 
 
 
 
using 
  UnityEditor; 
 
 
 
 
 
 
 
public 
  class 
  ResizablePanels : 
  EditorWindow
 
 

   { 
 
 
 
private 
  Rect 
  upperPanel; 
 
 
 
private 
  Rect 
  lowerPanel; 
 
 
 
 
 
 
 
MenuItem( 
  "Window/Resizable Panels")] 
 
 
 
private 
  static 
  void 
  OpenWindow() 
 
 
 

   { 
 
 
 
ResizablePanels 
  window = 
  GetWindow< 
  ResizablePanels>(); 
 
 
 
window. 
  titleContent = 
  new 
  GUIContent( 
  "Resizable Panels"); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  OnGUI() 
 
 
 

   { 
 
 
 
DrawUpperPanel(); 
 
 
 
DrawLowerPanel(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawUpperPanel() 
 
 
 

   { 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawLowerPanel() 
 
 
 

   { 
 
 
 

   } 
 
 
 

   }



我们的编辑窗口开始形成。我们现在需要做的就是绘制面板并检查它们是否正常工作。GUILayout.BeginArea(Rect rect)将创建一个要绘制的矩形区域,GUILayout.EndArea()标记结束。这些区域将定义我们的面板。我还要在这两个区域添加标签,以便我们可以看到它们的外观。


using 
  UnityEngine; 
 
 
 
using 
  UnityEditor; 
 
 
 
 
 
 
 
public 
  class 
  ResizablePanels : 
  EditorWindow
 
 

   { 
 
 
 
private 
  Rect 
  upperPanel; 
 
 
 
private 
  Rect 
  lowerPanel; 
 
 
 
 
 
 
 
MenuItem( 
  "Window/Resizable Panels")] 
 
 
 
private 
  static 
  void 
  OpenWindow() 
 
 
 

   { 
 
 
 
ResizablePanels 
  window = 
  GetWindow< 
  ResizablePanels>(); 
 
 
 
window. 
  titleContent = 
  new 
  GUIContent( 
  "Resizable Panels"); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  OnGUI() 
 
 
 

   { 
 
 
 
DrawUpperPanel(); 
 
 
 
DrawLowerPanel(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawUpperPanel() 
 
 
 

   { 
 
 
 
upperPanel = 
  new 
  Rect( 
  0, 
  0, 
  position. 
  width, 
  position. 
  height * 
  0.5f); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  upperPanel); 
 
 
 
GUILayout. 
  Label( 
  "Upper Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawLowerPanel() 
 
 
 

   { 
 
 
 
lowerPanel = 
  new 
  Rect( 
  0, 
  position. 
  height * 
  0.5f, 
  position. 
  width, 
  position. 
  height * 
  0.5f); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  lowerPanel); 
 
 
 
GUILayout. 
  Label( 
  "Lower Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 

   }



好吧,他们似乎在工作:

unity在编辑模式下编译 unity 编辑器_自定义_03

然而,这两个面板被设置为覆盖窗口的一半,但是如果我们希望它们可以调整大小,则它们需要具有可变高度。所以,我要添加一个大小比例变量; 这样,当一个面板覆盖一定量的窗口时,另一个面板可以覆盖剩余部分。


using 
  UnityEngine; 
 
 
 
using 
  UnityEditor; 
 
 
 
 
 
 
 
public 
  class 
  ResizablePanels : 
  EditorWindow
 
 

   { 
 
 
 
private 
  Rect 
  upperPanel; 
 
 
 
private 
  Rect 
  lowerPanel; 
 
 
 
 
 
 
 
private 
  float 
  sizeRatio = 
  0.5f; 
 
 
 
 
 
 
 
MenuItem( 
  "Window/Resizable Panels")] 
 
 
 
private 
  static 
  void 
  OpenWindow() 
 
 
 

   { 
 
 
 
ResizablePanels 
  window = 
  GetWindow< 
  ResizablePanels>(); 
 
 
 
window. 
  titleContent = 
  new 
  GUIContent( 
  "Resizable Panels"); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  OnGUI() 
 
 
 

   { 
 
 
 
DrawUpperPanel(); 
 
 
 
DrawLowerPanel(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawUpperPanel() 
 
 
 

   { 
 
 
 
upperPanel = 
  new 
  Rect( 
  0, 
  0, 
  position. 
  width, 
  position. 
  height * 
  sizeRatio); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  upperPanel); 
 
 
 
GUILayout. 
  Label( 
  "Upper Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawLowerPanel() 
 
 
 

   { 
 
 
 
lowerPanel = 
  new 
  Rect( 
  0, ( 
  position. 
  height * 
  sizeRatio), 
  position. 
  width, 
  position. 
  height * ( 
  1 - 
  sizeRatio)); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  lowerPanel); 
 
 
 
GUILayout. 
  Label( 
  "Lower Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 

   }



好的,两个面板都有可变的高度......但是我们仍然无法调整它们的大小!但不要担心,我们离最终产品并不太远。现在我们只需要另一个矩形区域,这样当用户点击那里时我们就可以开始调整大小。我将在两个面板之间添加该区域。这将是10像素高,因为,为什么不呢?我喜欢10(我喜欢1010!甚至更好:))。

我们还需要向用户显示鼠标指针位于调整大小区域中。EditorGUIUtility.AddCursorRect(Rect rect,MouseCursor cursor)就是这样做的,所以我们将在绘图方法中使用它。

我们需要向用户展示另一件事:调整大小区域的开始位置。这看起来像魔术,但我保证,它不是:我们将使用Unity自己的一个图标并将其拉伸并放置,使其看起来像上下面板之间的线。

using 
  UnityEngine; 
 
 
 
using 
  UnityEditor; 
 
 
 
 
 
 
 
public 
  class 
  ResizablePanels : 
  EditorWindow
 
 

   { 
 
 
 
private 
  Rect 
  upperPanel; 
 
 
 
private 
  Rect 
  lowerPanel; 
 
 
 
private 
  Rect 
  resizer; 
 
 
 
 
 
 
 
private 
  float 
  sizeRatio = 
  0.5f; 
 
 
 
private 
  bool 
  isResizing; 
 
 
 
 
 
 
 
private 
  GUIStyle 
  resizerStyle; 
 
 
 
 
 
 
 
MenuItem( 
  "Window/Resizable Panels")] 
 
 
 
private 
  static 
  void 
  OpenWindow() 
 
 
 

   { 
 
 
 
ResizablePanels 
  window = 
  GetWindow< 
  ResizablePanels>(); 
 
 
 
window. 
  titleContent = 
  new 
  GUIContent( 
  "Resizable Panels"); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  OnEnable() 
 
 
 

   { 
 
 
 
resizerStyle = 
  new 
  GUIStyle(); 
 
 
 
resizerStyle. 
  normal. 
  background = 
  EditorGUIUtility. 
  Load( 
  "icons/d_AvatarBlendBackground.png") 
  as 
  Texture2D; 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  OnGUI() 
 
 
 

   { 
 
 
 
DrawUpperPanel(); 
 
 
 
DrawLowerPanel(); 
 
 
 
DrawResizer(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawUpperPanel() 
 
 
 

   { 
 
 
 
upperPanel = 
  new 
  Rect( 
  0, 
  0, 
  position. 
  width, 
  position. 
  height * 
  sizeRatio); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  upperPanel); 
 
 
 
GUILayout. 
  Label( 
  "Upper Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawLowerPanel() 
 
 
 

   { 
 
 
 
lowerPanel = 
  new 
  Rect( 
  0, ( 
  position. 
  height * 
  sizeRatio) + 
  5, 
  position. 
  width, 
  position. 
  height * ( 
  1 - 
  sizeRatio) - 
  5); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  lowerPanel); 
 
 
 
GUILayout. 
  Label( 
  "Lower Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawResizer() 
 
 
 

   { 
 
 
 
resizer = 
  new 
  Rect( 
  0, ( 
  position. 
  height * 
  sizeRatio) - 
  5f, 
  position. 
  width, 
  10f); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  new 
  Rect( 
  resizer. 
  position + ( 
  Vector2. 
  up * 
  5f), 
  new 
  Vector2( 
  position. 
  width, 
  2)), 
  resizerStyle); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 
 
 
 
 
EditorGUIUtility. 
  AddCursorRect( 
  resizer, 
  MouseCursor. 
  ResizeVertical); 
 
 
 

   } 
 
 
 

   }



就快结束了:

unity在编辑模式下编译 unity 编辑器_unity在编辑模式下编译_04

现在,我们将通过添加实际的交互来最终确定它。我们将处理传入的事件,如果事件是鼠标按下事件并且它在调整大小区域,我们将开始调整大小。


using 
  UnityEngine; 
 
 
 
using 
  UnityEditor; 
 
 
 
 
 
 
 
public 
  class 
  ResizablePanels : 
  EditorWindow
 
 

   { 
 
 
 
private 
  Rect 
  upperPanel; 
 
 
 
private 
  Rect 
  lowerPanel; 
 
 
 
private 
  Rect 
  resizer; 
 
 
 
 
 
 
 
private 
  float 
  sizeRatio = 
  0.5f; 
 
 
 
private 
  bool 
  isResizing; 
 
 
 
 
 
 
 
private 
  GUIStyle 
  resizerStyle; 
 
 
 
 
 
 
 
MenuItem( 
  "Window/Resizable Panels")] 
 
 
 
private 
  static 
  void 
  OpenWindow() 
 
 
 

   { 
 
 
 
ResizablePanels 
  window = 
  GetWindow< 
  ResizablePanels>(); 
 
 
 
window. 
  titleContent = 
  new 
  GUIContent( 
  "Resizable Panels"); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  OnEnable() 
 
 
 

   { 
 
 
 
resizerStyle = 
  new 
  GUIStyle(); 
 
 
 
resizerStyle. 
  normal. 
  background = 
  EditorGUIUtility. 
  Load( 
  "icons/d_AvatarBlendBackground.png") 
  as 
  Texture2D; 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  OnGUI() 
 
 
 

   { 
 
 
 
DrawUpperPanel(); 
 
 
 
DrawLowerPanel(); 
 
 
 
DrawResizer(); 
 
 
 
 
 
 
 
ProcessEvents( 
  Event. 
  current); 
 
 
 
 
 
 
 
if ( 
  GUI. 
  changed) 
  Repaint(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawUpperPanel() 
 
 
 

   { 
 
 
 
upperPanel = 
  new 
  Rect( 
  0, 
  0, 
  position. 
  width, 
  position. 
  height * 
  sizeRatio); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  upperPanel); 
 
 
 
GUILayout. 
  Label( 
  "Upper Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawLowerPanel() 
 
 
 

   { 
 
 
 
lowerPanel = 
  new 
  Rect( 
  0, ( 
  position. 
  height * 
  sizeRatio) + 
  5, 
  position. 
  width, 
  position. 
  height * ( 
  1 - 
  sizeRatio) - 
  5); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  lowerPanel); 
 
 
 
GUILayout. 
  Label( 
  "Lower Panel"); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  DrawResizer() 
 
 
 

   { 
 
 
 
resizer = 
  new 
  Rect( 
  0, ( 
  position. 
  height * 
  sizeRatio) - 
  5f, 
  position. 
  width, 
  10f); 
 
 
 
 
 
 
 
GUILayout. 
  BeginArea( 
  new 
  Rect( 
  resizer. 
  position + ( 
  Vector2. 
  up * 
  5f), 
  new 
  Vector2( 
  position. 
  width, 
  2)), 
  resizerStyle); 
 
 
 
GUILayout. 
  EndArea(); 
 
 
 
 
 
 
 
EditorGUIUtility. 
  AddCursorRect( 
  resizer, 
  MouseCursor. 
  ResizeVertical); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  ProcessEvents( 
  Event 
  e) 
 
 
 

   { 
 
 
 
switch ( 
  e. 
  type) 
 
 
 

   { 
 
 
 
case 
  EventType. 
  MouseDown: 
 
 
 
if ( 
  e. 
  button == 
  0 && 
  resizer. 
  Contains( 
  e. 
  mousePosition)) 
 
 
 

   { 
 
 
 
isResizing = 
  true; 
 
 
 

   } 
 
 
 
break; 
 
 
 
 
 
 
 
case 
  EventType. 
  MouseUp: 
 
 
 
isResizing = 
  false; 
 
 
 
break; 
 
 
 

   } 
 
 
 
 
 
 
 
Resize( 
  e); 
 
 
 

   } 
 
 
 
 
 
 
 
private 
  void 
  Resize( 
  Event 
  e) 
 
 
 

   { 
 
 
 
if ( 
  isResizing) 
 
 
 

   { 
 
 
 
sizeRatio = 
  e. 
  mousePosition. 
  y / 
  position. 
  height; 
 
 
 
Repaint(); 
 
 
 

   } 
 
 
 

   } 
 
 
 

   }



这是最终版本:

unity在编辑模式下编译 unity 编辑器_自定义_05