Przepis na Indyka – Tworzenie edytorów cz. 1

Unity samo w sobie jest bardzo rozbudowanym silnikiem i edytorem do tworzenia gier. Jednak by wyciągnąć z niego 100% możliwości należy samemu zacząć go rozbudowywać.

Tworzenie edytorów cz. 1

Tutorial Unity

1. Uruchamianie componentów w edytorze

Najprostszym sposobem stworzenia skryptu do wykorzystania w edytorze jest dodanie do componentu tuż przed nazwa klasy atrybutu
[code language=”csharp”]
[ExecuteInEditMode]
[/code]
Przykładowe wykorzystanie. Stwórzmy teraz skrypt który będzie ustawiał obiekty z listy w linii zaczynając od swojej pozycji.  Będzie wykonywał to co Update.

[code language=”csharp”]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ObjectsInLine : MonoBehaviour
{
public float distanceBetween = 2;
public List objects = new List ();

void Start ()
{

}

void Update ()
{
for (int i = 0; i < objects.Count; i++) {
objects [i].position = transform.position + transform.forward * i * distanceBetween;
}
}
}

[/code]

W skrypcie mamy dwie zmienne listę obiektów oraz dystans pomiędzy nimi. W metodzie Update Skrypt ustawia co klatkę wszystkie obiekty z listy w linii.

Dodajmy teraz kilka obiektów do sceny i rozłóżmy je w dowolny sposób na scenie:

Unity-1-ObjectsInScene

 

Następnie podepnijmy obiekty do listy skryptu ObjectsInLine.

Unity-2-AddObjects

W tym momencie mamy już wszystko ustawione aby skrypt mógł wykonać swoje zadanie. Jednak aby obiekty zostały ustawione w linii musimy uruchomić grę przyciskiem Play.

Unity-3-objectsInLinePlay

Obiekty ustawiły się w linii.

Chcielibyśmy jednak osiągnąć ten sam efekt bez uruchomienia gry. Dodajmy w tym celu atrybut ExecuteInEditMode do skryptu.

[code language=”csharp”]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[ExecuteInEditMode]
public class ObjectsInLine : MonoBehaviour
{
public float distanceBetween = 2;
public List objects = new List ();

void Start ()
{

}

void Update ()
{
for (int i = 0; i < objects.Count; i++) {
objects [i].position = transform.position + transform.forward * i * distanceBetween;
}
}
}
[/code]

Po dodaniu atrybutu i powrocie z edytora kodu do unity obiekty od razu ustawiają się w linii. Także próba poruszenia obiektem z listy nie powiedzie się. Jeżeli dodamy nowe obiekty do listy one również ustawią się w linii.

Unity-4-objectsInLineNoPlay

ExecuteInEditMode umożliwia tworzenie prostych skryptów uruchamianych w edytorze które pozwalają zobaczyć efekty pracy bez uruchamiania samej gry.

2. Tworzenie własnego inspektora do componentu

Przejdziemy teraz do tworzenia własnych inspektorów skryptów. W unity  w celu stworzenia własnego inspektora należy stworzyć wpierw własny component, w tym tutorialu wykorzystamy nasz skrypt ObjectsInLine.

[code language=”csharp”]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ObjectsInLine : MonoBehaviour
{
public float distanceBetween = 2;
public List objects = new List ();

void Start ()
{

}
void Update ()
{
for (int i = 0; i < objects.Count; i++) {
objects [i].position = transform.position + transform.forward * i * distanceBetween;
}
}
}
[/code]

Stwórzmy teraz nasz skrypt inspektora. Skrypt ten należy stworzyć w katalogu Editor w naszych assetach.

Unity-5-editorFolder

[code language=”csharp”]
using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(ObjectsInLine))]
public class ObjectsInLineEditor : Editor
{

public override void OnInspectorGUI ()
{
ObjectsInLine myTarget = (ObjectsInLine)target;

EditorGUILayout.LabelField („Custom editor”);

}
}
[/code]

Kilka ważnych uwag dotyczących tworzenia skryptów edytora. Po pierwsze muszą posiadać dodany namespace UnityEditor oraz dziedziczyć po klasie Editor. Sam skrypt inspektora będziemy tworzyć w metodzie OnInspectorGUI. Metoda ta działa podobnie do starego systemu gui Unity. Możemy w niej ręcznie dodawać wszystkie pola ze skryptu jak i tworzyć własne pola.
Jednak przy skomplikowanych komponentach odtworzenie całości bazowego inspektora skryptu potrafi zająć sporo czasu dlatego warto korzystać z metody DrawDefaultInspector. Na tą chwilę jeżeli spojrzymy do inspektora naszego obiektu ze skryptem ObjectsInLine wygląda on następująco:
Unity-6-simpleCustomEditor

Jeżeli natomiast w metodzie OnInspectorGUI dodamy wywołanie DrawDefaultInspector:
[code language=”csharp”]
using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(ObjectsInLine))]
public class ObjectsInLineEditor : Editor
{

public override void OnInspectorGUI ()
{
ObjectsInLine myTarget = (ObjectsInLine)target;

EditorGUILayout.LabelField („Custom editor”);

DrawDefaultInspector ();

}
}
[/code]

Unity-7-drawDefault

Zobaczymy nasz label „Custom Editor” oraz wszystkie pola komponentu. Dodamy teraz do naszego inspektora możliwość wywoływania ustawienia obiektów w linii za pomocą przycisku zamiast ustawiać je w każdym Update.
Wpierw zmieńmy skrypt ObjectsInLine dodając publiczną metodę SetObjectsInLine:

[code language=”csharp”]
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[ExecuteInEditMode]
public class ObjectsInLine : MonoBehaviour
{
public float distanceBetween = 2;
public List objects = new List ();

void Start ()
{

}

void Update ()
{

}

public void SetObjectsInLine ()
{
for (int i = 0; i < objects.Count; i++) {
objects [i].position = transform.position + transform.forward * i * distanceBetween;
}
}
}
[/code]

Następnie w skrypcie inspektora dodamy wywołanie tej metody na przycisk. W tym celu skorzystamy z pola target naszego skryptu, przypiszemy je do zmiennej lokalnej

[code language=”csharp”]
ObjectsInLine myTarget = (ObjectsInLine)target;
[/code]

Pole to pozwala komunikować się naszemu inspektorowi z componentem na obiekcie w hierarchii.
Dodamy teraz do inspektora przycisk który wywoła metodę SetObjectsInLine

[code language=”csharp”]
using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(ObjectsInLine))]
public class ObjectsInLineEditor : Editor
{

public override void OnInspectorGUI ()
{
ObjectsInLine myTarget = (ObjectsInLine)target;

EditorGUILayout.LabelField („Custom editor”);

DrawDefaultInspector ();

if (GUILayout.Button („Set Objects in line”)) {
myTarget.SetObjectsInLine ();
}
}
}
[/code]

W naszym inspektorze pojawił się przycisk do ustawiania obiektów w linii.

Unity-8-buttonSetObjects

Poprzestawiajmy teraz nasze obiekty w scenie aby nie były ułożone w linii.

Unity-9-objectsNotInLine

Po przyciśnięciu przycisku w edytorze obiekty ponownie ustawiają się w linii.

Unity-10-objectsBackInLine

3. Podsumowanie

Zarazem ExecuteInEditMode jak i własne skrypty inspektora pozwalają rozszerzać Edytor unity o dodatkowe możliwości.

W drugiej części tutoriala dotyczącego tworzenia edytorów zajmiemy się tworzeniem okien edytora oraz powiemy wstępnie o ScriptableObject i ich wykorzystaniu.

4. Linki

http://docs.unity3d.com/Manual/editor-CustomEditors.html

https://unity3d.com/learn/tutorials/modules/intermediate/editor/building-custom-inspector

https://unity3d.com/learn/tutorials/modules/intermediate/editor/adding-buttons-to-inspector