2019. 7. 28. 15:59ㆍ유니티/(Old)에디터 확장
Unity エディター拡張入門
Web版無償公開中!Unityエディター拡張の入門書!
anchan828.github.io
에디터 확장을 시작하기에 앞서 알아야 되는 것이 있습니다. 이 장에서는 모든 것을 설명할 순 없지만 알아두면 나중에 EditorGUI, EditorGUILayout으로 할 수 있는 응용의 폭을 넓힐 수 있습니다. 샘플 코드는 간략화하여 EditorGUILayout의 용도에 집중하도록 하였습니다.
6.1 EditorGUI
런타임 때 실행하는 GUI 클래스와 역할은 비슷하지만 Editor 용의 기능이 추가되어있는 클래스입니다. 차례차례 배치되는 EditorGUILayout 클래스도 제공됩니다.
먼저 EditorWindow의 EditorGUILayout으로 문자를 표시해봅니다.
using UnityEngine;
using UnityEditor;
public class NewBehaviourScript : EditorWindow
{
[MenuItem("Window/Example")]
static void Open ()
{
GetWindow<NewBehaviourScript> ();
}
void OnGUI ()
{
EditorGUILayout.LabelField ("Example Label");
}
}
|
6.2 ChangeCheck
BeginChangeCheck와 EndChangeCheck에 포함된 GUI에서 무엇간의 변경이 있을 경우 EndChangeCheck가 true를 반환합니다.
using UnityEngine;
using UnityEditor;
public class NewBehaviourScript : EditorWindow
{
[MenuItem("Window/Example")]
static void Open ()
{
GetWindow<NewBehaviourScript> ();
}
bool toggleValue;
void OnGUI ()
{
EditorGUI.BeginChangeCheck ();
//toggle을 마우스로클릭해서 값을 변경.
toggleValue = EditorGUILayout.ToggleLeft ("Toggle", toggleValue);
//toggleValue의 값이 변경될 떄마다 true를 반환.
if (EditorGUI.EndChangeCheck ()) {
if (toggleValue) {
Debug.Log ("toggleValue가 true가 된 순간 불러집니다.");
}
}
}
}
|
실제로는 GUI.changed
ChangeCheck는 GUI.changed를 내부에서 처리하여 전달합니다. GUI.change로 ChangeCheck를 직접 구현해보면 다음과 같이 구현할 수 있습니다.
bool toggleValue;
Stack<bool> stack = new Stack<bool> ();
void OnGUI ()
{
//BeginChangeCheck 의 역할
{
//먼저 값을 push
stack.Push (GUI.changed);
GUI.changed = false;
}
toggleValue = EditorGUILayout.ToggleLeft ("Toggle", toggleValue);
//EndChangeCheck 의 역할
{
bool changed = GUI.changed;
//어느 쪽이든 true라면 변경된 것이라고 판별
GUI.changed |= stack.Pop ();
}
if (changed) {
Debug.Log ("toggleValue가 true가 되면 호출됩니다.");
}
}
|
6.3 DisabledGroup
using UnityEngine;
using UnityEditor;
public class NewBehaviourScript : EditorWindow
{
[MenuItem("Window/Example")]
static void Open ()
{
GetWindow<NewBehaviourScript> ();
}
void OnGUI ()
{
Display ();
EditorGUILayout.Space ();
EditorGUI.BeginDisabledGroup (true);
Display ();
EditorGUI.EndDisabledGroup ();
}
void Display ()
{
EditorGUILayout.ToggleLeft ("Toggle", false);
EditorGUILayout.IntSlider (0, 10, 0);
GUILayout.Button ("Button");
}
}
|
실제로는 GUI.enabled
DisabledGroup의 내부는 GUI.enabled로 처리합니다. GUI.enabled로 DisabledGroup를 직접 구현하면 다음과 같습니다.
void OnGUI ()
{
Display ();
EditorGUILayout.Space ();
GUI.enabled = false;
Display ();
GUI.enabled = true;
}
void Display ()
{
EditorGUILayout.ToggleLeft ("Toggle", false);
EditorGUILayout.IntSlider (0, 10, 0);
GUILayout.Button ("Button");
}
|
6.4 FadeGroup
GUI의 그룹을 페이드 인, 페이드 아웃을 할 경우에 사용합니다. 주로 특정 트리거에 의해 동작하는 방식으로 처리하지만 이번에는 버튼을 눌러서 페이드해서 GUI가 표시되도록 해봅니다.
페이드 중 GUI를 조작할 수 없습니다. 페이드의 속도는 어느정도 조절해서 유저를 기다리지 않도록 해봅니다.
using UnityEngine;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine.Events;
public class NewBehaviourScript : EditorWindow
{
[MenuItem("Window/Example")]
static void Open ()
{
GetWindow<NewBehaviourScript> ();
}
//최초 값이 0이면 페이드를 하지 않는 것으로 판단하여 0.0001f과 같이 0에 근접한 값을 설정.
AnimFloat animFloat = new AnimFloat (0.0001f);
Texture tex;
void OnGUI ()
{
bool on = animFloat.value == 1;
if (GUILayout.Button (on ? "Close" : "Open", GUILayout.Width (64))) {
animFloat.target = on ? 0.0001f : 1;
animFloat.speed = 0.05f;
//값이 변하면 EditorWindow를 다시 그림.
var env = new UnityEvent ();
env.AddListener (() => Repaint ());
animFloat.valueChanged = env;
}
EditorGUILayout.BeginHorizontal ();
EditorGUILayout.BeginFadeGroup (animFloat.value);
Display ();
EditorGUILayout.EndFadeGroup ();
Display ();
EditorGUILayout.EndHorizontal ();
}
void Display ()
{
EditorGUILayout.BeginVertical ();
EditorGUILayout.ToggleLeft ("Toggle", false);
var options = new []{GUILayout.Width (128), GUILayout.Height (128)};
tex = EditorGUILayout.ObjectField (
tex, typeof(Texture), false, options) as Texture;
GUILayout.Button ("Button");
EditorGUILayout.EndVertical ();
}
}
|
6.5 EditorGUI.ObjectField
객체의 참조를 다루는 필드입니다. 인수에 참조할 객체의 형을 지정할 수 있습니다. 텍스처 형(Texture2D 혹은 Sprite)는 특수한 썸네일 형식의 필드가 됩니다.
void OnGUI ()
{
EditorGUILayout.ObjectField (null, typeof(Object), false);
EditorGUILayout.ObjectField (null, typeof(Material), false);
EditorGUILayout.ObjectField (null, typeof(AudioClip), false);
var options = new []{GUILayout.Width (64), GUILayout.Height (64)};
EditorGUILayout.ObjectField (null, typeof(Texture), false, options);
EditorGUILayout.ObjectField (null, typeof(Sprite), false, options);
}
|
allowSceneObjects 매개변수
유니티 커스텀 에디터(6) - 오브젝트 필드와 매개변수"allowSceneObjects"
이번 목표 : 오브젝트 필드를 만들자!유니티의 핵심 개념인 오브젝트를 편집하거나 참고하려 할 때 내가 ...
blog.naver.com
위 사이트의 내용을 빌려서 테스트 해본 결과 true이면 씬에서 끌어 쓸 수 있고, false이면 씬에서는 끌어 쓸 수 없고, Project에서 끌어와야 하는 것을 확인해보았습니다.
6.6 EditorGUI.MultiFloatField
복수의 float 값을 편집할 필드를 하나의 행에 표시하기 위한 용도로 사용됩니다.
인스펙터 창에 Vector3의 값을 편집하는 것처럼 표시됩니다.
float[] numbers = new float[] {
0,
1,
2
};
GUIContent[] contents = new GUIContent[] {
new GUIContent ("X"),
new GUIContent ("Y"),
new GUIContent ("Z")
};
void OnGUI ()
{
EditorGUI.MultiFloatField (
new Rect (30, 30, 200, EditorGUIUtility.singleLineHeight),
new GUIContent ("Label"),
contents,
numbers);
}
|
6.7 EditorGUI.indentLevel
들여쓰기의 레벨을 관리합니다. 다음 코드와 같이 부분적으로 들여 쓰기를 증감하는 것으로 인스펙터와 계층 뷰에서 보는 것처럼 계단구조를 구성할 수 있습니다.
void OnGUI ()
{
EditorGUILayout.LabelField ("Parent");
EditorGUI.indentLevel++;
EditorGUILayout.LabelField ("Child");
EditorGUILayout.LabelField ("Child");
EditorGUI.indentLevel--;
EditorGUILayout.LabelField ("Parent");
EditorGUI.indentLevel++;
EditorGUILayout.LabelField ("Child");
}
|
이것은 EditorGUI와 EditorGUILayout 양쪽에 효과를 줄 수 있습니다.
6.8 EditorGUILayout.Knob
각도와 정해진 범위 내에서 값을 설정하기 위한 루프를 작성합니다. 마우스로 드래그를 한다던지 표시된 라벨을 클릭하는 것으로 값을 직접 입력할 수 있습니다.
float angle = 0;
void OnGUI ()
{
angle = EditorGUILayout.Knob (Vector2.one * 64,
angle, 0, 360, "도", Color.gray, Color.red, true);
}
|
6.9 Scope
EditorGUILayout.BeginHorizontal/EndHorizontal 것과 같이 Begin/End로 시작하는 GUI 그룹의 보조 기능입니다. HorizontalScope, VerticalScope, ScrollViewScope와 같은 종류가 제공됩니다. Scope 자체는 IDisposable 객체로 처리되어 using을 사용할 수 있습니다.
using (new EditorGUILayout.HorizontalScope ()) {
GUILayout.Button ("Button1");
GUILayout.Button ("Button2");
}
|
Scope의 제작 - BackgroundColorScope
HorizontalScope와 같이 Scope는 GUI.Scope 클래스를 계승하여 작성되어 있습니다.
public class HorizontalScope : GUI.Scope
{
public HorizontalScope()
{
EditorGUILayout.BeginHorizontal();
}
protected override void CloseScope()
{
EditorGUILayout.EndHorizontal();
}
//생략
}
|
CloseScope 함수는 Dispose 시 호출되는 함수입니다. Scope 클래스 내부에서 Begin, CloseScope 함수 내에 End를 호출하게 합니다.
동일하게 GUI.Scpoe를 계승한 클래스로써 Scope를 작성하는 것도 가능합니다. 이번에는 시험 삼아 그림 6.10와 같이 Scope 내에서만 GUI의 배경을 변경하는 BackgroundColorScope를 작성해보겠습니다.
using UnityEngine;
public class BackgroundColorScope : GUI.Scope
{
private readonly Color color;
public BackgroundColorScope(Color color)
{
this.color = GUI.backgroundColor;
GUI.backgroundColor = color;
}
protected override void CloseScope()
{
GUI.backgroundColor = color;
}
}
|
이처럼 GUI.backgroundColor에 Color 정보를 전달하기 전에 변수를 하나 선언해서 보전한 다음 CloseScope로 원래 색상으로 되돌립니다.
using (new BackgroundColorScope (Color.green)) {
// 녹색 버튼
GUILayout.Button ("Button");
using (new BackgroundColorScope (Color.yellow)) {
// 노란색 버튼
GUILayout.Button ("Button");
}
}
|
6.10 보기에는 버튼이지만 기능은 토글(탭 버튼)
Unity 에디터의 GUI에는 보기에는 버튼인데 동작은 토글처럼 하는 버튼들이 존재합니다.
이를 만드는 방법을 소개하고자 합니다.
스타일은 버튼인데 기능은 토글(단일)
작성하는 방법은 단일로써 Toggle에 버튼 스타일을 적용하면 됩니다.
bool on;
void OnGUI ()
{
//GUIStyle는 문자열로 지정할 수도 있습니다.
on = GUILayout.Toggle (on, on ? "on" : "off", "button");
}
|
스타일은 버튼인데 기능은 토글(멀티)
복수의 선택지 중에서 하나를 선택할 때 그림 6.1과 같이 토클 형식을 작성할 수 있습니다.
bool one, two, three;
void OnGUI ()
{
using (new EditorGUILayout.HorizontalScope ()) {
one = GUILayout.Toggle (one, "1", EditorStyles.miniButtonLeft);
two = GUILayout.Toggle (two, "2", EditorStyles.miniButtonMid);
three = GUILayout.Toggle (three, "3", EditorStyles.miniButtonRight);
}
}
|
분명 복수의 토글을 배치하게 되면 위와 같은 코드처럼 될 수도 있습니다. 하지만 이런 형식의 코드는 추천하지 않습니다. 이 정도의 bool 변수가 토글을 작성하기 위하 증가되면 관리 측면에서 불편합니다. 이 경우 GUILayout.Toolbar를 작성하여 간단히 해결하는 것이 가능합니다.
int selected;
void OnGUI ()
{
selected = GUILayout.Toolbar (selected, new string[]{ "1", "2", "3" });
}
|
선택된 버튼의 인덱스를 int형 변수로 관리하고 표시할 토글(문자열)은 string 배열로 관리합니다. 추가적으로 GUIStyle을 변경하는 것으로 여러 가지 표현이 가능합니다.
EditorStyles.toolbarButton을 사용하는 것으로 툴 바와 PlayerSetting의 플랫폼 별 설정과 같은 토글 형식을 표현할 수 잇습니다.
int selected;
void OnGUI ()
{
selected = GUILayout.Toolbar (selected,
new string[]{ "1", "2", "3" }, EditorStyles.toolbarButton);
}
|
1열로 표시하려면 GUILayout.SelectionGrid에 스타일을 PreferencesKeysElement (Unity 내부에서 처리하는 GUIStyle)로 설정하는 것으로 Preferences 윈도우에 표현되어있는 선택 메뉴처럼 만들 수 있습니다.
int selected;
void OnGUI ()
{
selected = GUILayout.SelectionGrid (selected,
new string[]{ "1", "2", "3" },1, "PreferencesKeysElement");
}
|
'유니티 > (Old)에디터 확장' 카테고리의 다른 글
제8장 MenuItem (0) | 2019.08.13 |
---|---|
제7장 EditorWindow (0) | 2019.08.11 |
제 5장 SerializedObject에 대해서 (0) | 2019.07.28 |
제4장 ScriptableObject (0) | 2019.07.28 |
제3장 데이터 보존 (0) | 2019.07.28 |