Klasy(czne) Unity3d to seria w której omawiam podstawowe klasy dostępne w Unity3d. Omawiam do czego dana klasa służy i jakie fajne funkcję posiada.
Dzisiejszy odcinek: Klasa GUI.
Klasę GUI możemy rozwinąć jako Graphic User Interface, czyli po naszemu: Graficzny Interfejs Użytkownika. Większość z nas, skojarzy to z paskiem życia postaci, menu budowy jednostek, czy menu w grze. Skojarzenia będą całkiem dobre, ale nie w Unity.
Unity do tego celu wykorzystywało klasę GUI, ale do swojej 4 edycji. Wraz z częścią czwartą pojawił się Canvas, oraz klasa UI. Unity zaleca wykorzystanie właśnie tych narzędzi przy tworzeniu czy to menu, czy to HUDa, czy innych elementów graficznych, które możemy podpiąć pod interfejs graficzny.
No dobra, to co w takim razie z GUI? Zostało wyłączone z obiegu i nie powinniśmy go używać? W takim przypadku tego wpisu by nie było.
Do czego mi klasa GUI?
Zgodnie z dokumentacją Unity, klasa GUI ma dokładnie 3 przeznaczenia:
- Tworzenie narzędzi do debugowania wewnątrz gry,
- Tworzenie niestandardowych inspektorów dla komponentów typu: skrypt,
- Tworzenie nowych edytorów i narzędzi do zwiększenia możliwości Unity3d – pluginów.
O co tutaj chodzi? Skrypty w Unity obsługują pewną szczególną funkcję: OnGUI. Taka funkcja pozwala stworzyć graficzny interfejs dla skryptu w locie. W klasycznej sytuacji, musielibyśmy postawić canvasa, dodać mu elementy takie jak przyciski i opisy, potem napisać skrypty, które obsłużyłyby przyciski i dopiero coś z tym zrobić. Dzięki klasie GUI, możemy to wszystko zamknąć w jednym skrypcie. Zyskujemy dzięki temu dwie rzeczy:
- Jeśli tworzyliśmy skrypt dodający jakąś funkcjonalność, gdy go prześlemy innemu programiście, to dostanie on skrypt wraz z menu, obsługującym jego funkcjonalności. Nie trzeba dodatkowo przesyłać sceny.
- Możemy w prosty sposób, wewnątrz skryptu napisać sobie narzędzia do debugowania. Wypisać różne parametry i obserwować ich zmiany.
W ten sposób możemy sobie też tworzyć szkice naszych docelowych menu. Można je napisać szybko i już sprawdzać ich funkcjonowanie.
Podkreślę jeszcze raz. Tak wykonane menu, nie powinno trafić do końcowego gracza.
Jak wykorzystać klasę GUI?
W zasadzie całe wykorzystanie klasy GUI sprowadza się do tworzenia elementów interfejsu wewnątrz funkcji OnGUI. Najbardziej podstawowy skrypt, będzie wyglądał tak:
using UnityEngine; using System.Collections; public class GUITest : MonoBehaviour { void OnGUI () { // Tutaj Kod } }
Oczywiście, taki kod nic nie robi.
Nie będę omawiał po kolei każdej funkcji dostępnej w klasie GUI. Od tego w zasadzie jest dokumentacja. Natomiast zaprezentuję wam kilka podstawowych rzeczy, oraz streszczę, co jeszcze możecie dzięki tej klasie zrobić.
Podstawowe zastosowania
Wg. mnie dwie najpowszechniejsze metody wykorzystania GUI, będą sprowadzały się do tworzenia prostych menu przyciskowych – do tworzenia pozorowanego menu, prostego panelu testowego czy przycisków wyzwalających akcję. Oraz do wyświetlania danych w ten czy inny sposób w celu debugowani. Dlatego, te dwie metody omówię.
Zaprezentowany kod, będzie pochodził z dokumentacji. Omówienie będzie moje.
Przyciski
using UnityEngine; using System.Collections; public class GUITest : MonoBehaviour { public Texture2D icon; void OnGUI () { // Przycisk z ikona if (GUI.Button (new Rect (10,10, 100, 50), icon)) { print ("Ikona zostala kliknieta"); } // Klasyczny przycisk z tekstem if (GUI.Button (new Rect (10,70, 100, 20), "Tresc Przycisku")) { print ("Przycisk zostal klikniety"); } } }
Zaczynamy od przycisków. Są tutaj dwa warianty. Przycisk tekstowy, oraz przycisk z ikoną zamiast treści. Wykorzystujemy tutaj funkcję Button. Przyjmuje ona dwa parametry: Pierwszy to obiekt typu Rect, a drugi to odpowiednio string z treścią przycisku, lub obiekt typu Texture2D reprezentujący ikonę.
Obiekt typu Rect ma 4 parametry konstruktora. Pozycję na ekranie, oraz wysokość i szerokość. Wygląda to tak: new Rect(x, y, szerokość, wysokość). Pozycja x i y odnosi się do lewego górnego rogu przycisku, a punktem (0, 0) jest lewy górny róg ekranu.
[stextbox id=”info” defcaption=”true”]Przy ustalaniu pozycji elementów przydatne mogą być zmienne: Screen.height oraz Screen.width, które zawierają odpowiednio wysokość i szerokość ekranu.[/stextbox]
Drugą zastanawiającą rzeczą może być: Dlaczego przyciski są wewnątrz ifa? Musimy pamiętać, że w tym przypadku Button jest funkcją, która zwraca true lub false. True pojawia się, gdy przycisk został kliknięty. Dzięki temu, wewnątrz ifa możemy rozpisać akcję, która ma się wykonać gdy ktoś kliknie dany przycisk.
Ciekawostką mogą być tutaj jeszcze dwie inne funkcję:
Toolbar, która wyświetla nam przyciski jako listę jeden obok drugiego, jak w typowym pasku narzędzi:
Oraz grid, który wyświetla nam siatkę przycisków.
using UnityEngine; using System.Collections; public class ExampleClass : MonoBehaviour { // Zmienne Toolbara public int toolbarInt = 0; public string[] toolbarStrings = new string[] {"Toolbar1", "Toolbar2", "Toolbar3"}; // Zmienne Grida private int selectionGridInt = 0; private string[] selectionStrings = {"Grid 1", "Grid 2", "Grid 3", "Grid 4"}; void OnGUI() { // Tworzymy Toolbar toolbarInt = GUI.Toolbar(new Rect(25, 25, 250, 30), toolbarInt, toolbarStrings); // Tworzymy Grid selectionGridInt = GUI.SelectionGrid (new Rect (25, 25, 300, 60), selectionGridInt, selectionStrings, 2); } }
Część kodu jest nam znana. Zmiany są dwie. Pojawia się zmienna typu int toolbarInt oraz selectionGridInt. Są to zmienne mówiące, który przycisk jest wciśnięty (będzie oznaczony jako wciśnięty). Druga zmiana, to fakt, że treść przycisku zastąpiła tablica z treściami.
W przypadku Grida, mamy dodatkowy parametr na samym końcu. Mówi on, ile kolumn ma się wyświetlić.
Ważna rzecz: Obie funkcję zwracają nam inta. Int mówi o tym, który przycisk został wciśnięty. Więc tutaj o tym jakie akcję będą wykonane nie decyduje if, którym obejmujemy grida czy toolbara, a jakiś switch umieszczony później.
Wypisanie tekstu
Tutaj sprawa jest w sumie jeszcze prostsza, niż w przypadku przycisku. Oto kod:
using UnityEngine; using System.Collections; public class GUITest : MonoBehaviour { public Texture2D icon; public int zm; void OnGUI () { // Etykieta z tekstem GUI.Label (new Rect (0,0,100,50), "Tutaj jakas tresc dla etykiety"); // Etykieta z obrazkiem GUI.Label (new Rect (0,0,100,50), icon); // Etykieta wypisujaca wartosc zmiennej GUI.Label (new Rect (0,0,100,50), "Zmienna zm = " + zm); } }
Do wyświetlenia treści służy funkcja Label (etykieta). Nie ma tutaj nic, co mogłoby nas zaskoczyć. Znów klasa Rect decyduje o położeniu etykiety, a jako drugi parametr podajemy treść etykiety (również możemy podać teksturę).
Jeśli chcemy wypisać zawartość jakiejś zmiennej, obowiązują nas te same zasady łączenia stringów, co normalnie.
Możemy sobie też wyrysować dowolną teksturę:
using UnityEngine; using System.Collections; public class ExampleClass : MonoBehaviour { public Texture aTexture; void OnGUI() { GUI.DrawTexture(new Rect(10, 10, 60, 60), aTexture); } }
Ponownie sprawa jest prosta, pozycja i sama tekstura.
Inne przydatne funkcje
Ogólnie klasa GUI dysponuje funkcjami pozwalającymi tworzyć różne formularze i nie tylko. Po za przyciskami klasycznymi, mamy funkcję Toggle, która wyświetla przycisk mający stan włączony lub wyłączony. Mamy klasy TextField, TextArea i PasswordField, które tworzą nam opcję generowania formularza takiego jak w internecie.
Mamy też HorizontalSlider i VerticalSlider, czyli kontroli tworzące suwaki do zmiany wartości w założonym przedziale.
Całość możemy ładnie opakować wykorzystując klasy Window i Box, tworzące odpowiednio okienko i prostokąt do zbierania treści.
Dostosowanie wyglądu
Ogólnie nasze wytwory będą całkiem ładne i estetyczne. Ale to ciągle domyślny wygląd Unity. Możemy sobie takie kontrolki dostosować po swojemu. Służy do tego klasa GUISkin. Możemy sobie obiekt tej klasy utworzyć w edytorze klikając w panelu Hierarchy prawym przyciskiem i wybierając: Create -> GUISkin. Samo ustawienie kontrolek możemy dostosować w oknie inspektor, po wybraniu utworzonego obiektu w panelu hierarchy.
Możemy sobie modyfikować tutaj różne śmieszne parametry dla kontrolek w różnych sytuacjach. W spoczynku, po najechaniu, marginesy, obramowania etc. Jeśli ktoś liznął kiedykolwiek HTMLa i CSSa to będzie się tu czuł jak ryba w wodzie.
No to mamy już ten obiekt, ale jak go wykorzystać?
using UnityEngine; using System.Collections; public class GUITest : MonoBehaviour { public GUISkin mySkin; private bool toggle = true; void OnGUI () { // Ustawiamy skorke GUI.skin = mySkin; // Ten przycisk, będzie zgodny z ustawieniami naszej skroki GUI.Button (new Rect (10,35,150,20), "Ostylowany przycisk"); // Ustawienie skorki na null przywraca domysle wartosci Unity. Moglibysmy tutaj podac np. drugi obiekt GUISkin GUI.skin = null; // Ten przycisk powstanie juz jako przycisk o klasycznym wygladzie Unity GUI.Button (new Rect (10,75,150,20), "Klasyczny Przycisk"); } }
Taki obiekt podajemy sobie po prostu jako zmienną publiczną, a następnie przypisujemy do zmiennej skin klasy GUI. Wszystkie elementy GUI utworzone po przypisaniu skórki będą generowane w jej stylu. Możemy wewnątrz jednej funkcji OnGUI zmieniać skórkę wielokrotnie. Jeśli chcemy powrócić do klasycznego wyglądu Unity, wystarczy zmiennej skin przypisać wartość null.
Podsumowanie
Tyle istotnych kwestii związanych z klasą GUI. Pozwala nam szybko stworzyć sobie proste menu czy to dla narzędzi developerskich czy jako interfejs wtyczki, czy po prostu do debugowania czy prototypownia. Najważniejsze co musimy pamiętać to fakt, żeby tak przygotowany interfejs nie trafił do końcowego użytkownika. Nie jest to najlepsze rozwiązanie, a do tego daje mniejsze pole manewru w kwestii wyglądu, niż przeznaczona do tego klasa UI.