howTo :: Edytor poziomów

W tym wpisie postaramy sobie odpowiedzieć na pytanie: jak powinien wyglądać edytor poziomów?

Zanim przejdziemy dalej, to chciałbym przypomnieć że seria howTo składa się z dwóch części: wpisu na blogu (tutaj znajdziesz głównie teorię oraz opis ogólnego rozwiązania problemu) oraz opcjonalnie z materiału wideo (zawierającego implementację przynajmniej części opisanych problemów).

Idee i rozwiązania dla edytora są pisane głównie w kontekście map 2D, chociaż część pomysłów nadaje się również do 3D.

 

Cechy edytora


Edytor poziomów to narzędzie w pierwszej fazie służące głównie developerom, jednak później także i ewentualnym fanom także stopień skomplikowania niektórych elementów może być różny (nie ulega wątpliwości, że wersja dla fanów powinna uniemożliwiać „zepsucie” gry i być bardziej „idioto-odporna”).

Należy jednak pamiętać, że bardzo do tworzenia poziomów zatrudnia się osoby, które niekoniecznie potrafią programować więc powinniśmy zadbać o to, aby edytor:

  • posiadał intuicyjny interfejs,
  • był stosunkowo łatwy i przyjemny w obsłudze,
  • zawierał jak najmniej elementów, które trzeba tłumaczyć,
  • był zbudowany w jak najprostszy i najbardziej przystępny dla użytkownika sposób (użytkownik może edytować położenie poszczególnych modułów, edytować ogólne rozmieszczenie narzędzi).

Dobrze, by było gdyby był względnie uniwersalny dla danego typu gier, ale co ważniejsze to aby umożliwiał uruchomienie poziomu jeszcze przed jego ostatecznym zapisaniem i wyeksportowaniem do gry (nawet jeżeli to edytor zewnętrzny) oraz pozwalał tworzyć nowe obiekty (lub edytować stare) wewnątrz edytora i następnie eksportować je do np. pliku XML, z których to gra może później skorzystać.

 

Obszary użytkownika


Jeżeli spróbujemy sobie wyobrazić ogólny wygląd edytora, tzn poszczególnych bloków, z których będzie składał się edytor to w przypadku prostego edytora, będziemy w stanie wyróżnić 3 główne obszary:

  1. Obszar roboczy, największy ze wszystkich obszarów, to na nim użytkownik wstawia nowe elementy i jest w stanie zobaczyć jak będzie wyglądał poziom po wyeksportowaniu.
  2. Obszar narzędzi, z niego użytkownik może wybrać co chce teraz robić: wstawiać/usuwać obiekty, powiększać/pomniejszać rozmiary poziomu, a może dodać specjalne opcje dla tego poziomu?
  3. Obszar obiektów, tutaj użytkownik jest w stanie wybrać obiekt, który chce wstawić lub (opcjonalnie) zedytować jego własności.
Schematyczne rozmieszczenie obszarów
Schematyczne rozmieszczenie obszarów

 

Omówienie obszarów


Paragraf, który można sobie pominąć ponieważ pomysłów na zawartość tych ogólnych obszarów może być tyle ilu ludzi, jednak dalej postaram się aby moje pomysły i opisy były w miarę uniwersalne.

 

Obszar roboczy

Jest to największy obszar i tutaj jest w stanie się z wizualizować marzenie designera poziomów o jego wymarzonym poziomie.

W najprostszej wersji tego obszaru tutaj będzie działo się stosunkowo niewiele, jedynie co ten obszar potrzebuje to implementacji kontenera przechowującego podstawowe informacje o tym jaki obiekt powinien się znaleźć w danym miejscu.

Dodatkowo w przypadku mapy kafelkowej, wymagane będzie przyciąganie kafli do siatki, ostatecznie całość jest prostsza do napisania niż edytor mapy platformowej (obiekty to nie kafle, mogą być na dowolnej pozycji), bo tutaj możemy po prostu rysować teksturę danego obiektu, podczas gdy w mapie „platformowej” musimy nie dość, że zapamiętać pozycję, renderować obiekt na obszarze to jeszcze wykrywać kolizję z myszą tak aby można było obiekt przesuwać w dynamiczny sposób.

Wracając do mapy kafelkowej to dobrze jest jeszcze renderować siatkę, która na pewno poprawi wyczucie, gdzie po kliknięciu pojawi się kafel.

 

Obszar narzędzi

Czyli zmienianie tego co się stanie po wciśnięciu myszy (wstawianie, usuwanie obiektów, itp), tutaj jedynie polecić zrobienie całości przy użyciu sugestywnych ikon, co konkretnie będzie zawierał ten obszar to zależy tylko od nas.

 

Obszar obiektów

Jest to jeden z najczęściej używanych obszarów, tutaj polecam dorobić wyszukiwarkę obiektów po nazwie (nie ma nic bardziej nieprzyjemnego niż ręczne szukanie jednego konkretnego obiektu z 1000 dostępnych). Nic nie stoi na przeszkodzie aby tą opcję rozbudować także o wyszukiwanie po kategoriach, albo sprawienia, że obiekty będą sortowane według przypisanej kategorii.

Co warto tutaj zamieścić to edytor obiektów, który zezwoli na szybkie zmienienie własności obiektu (nazwę, kategorię, id obiektu, kolizyjność, itp).

Edytor obiektów
Edytor kafli

 

Plik zapisu projektu


Tak duży program jak ten będzie niewątpliwie wymagał własnego typu rozszerzenia pliku zapisu (dotyczy to sytuacji gdy nie robimy najprostszej wersji mapy kafelkowej nie chcemy mieć wszystkiego twardo zakodowanego), chyba że chcemy za każdym uruchomieniem programu zmuszać użytkownika do wczytywania kafli z pliku, ustawiania ich nazw, id itd.

Możemy też chcieć zapisać ustawienia profilu użytkownika (rozstawienie okien, widoczne panele, …), być może niektóre poziomy przy eksporcie do takiego formatu aby gra była w stanie go odczytać będziemy zapisywali w sposób stratny, tzn część informacji nie jest potrzebna w grze, ale wymagana w edytorze.

Zapis projektu powinien składać się z wielu plików, po jednym dla każdej „sekcji”. Całość można rozbić na:

  • zapis ustawień edytora (konfiguracja programu zrobiona przez użytkownika),
  • zapis projektu (ustawienia jakie nie zmienią się ogólnie dla całego projektu, czyli 1 gry, może być to np zestaw używanych obiektów),
  • opcjonalny zapis poziomu (informacje o rozmieszczeniu obiektów wraz z dodatkowymi informacjami dla edytora, które nie są potrzebne grze, np informacje o specjalnym wyróżnieniu obiektu jakimś kolorem),
  • zapis informacji o obiekcie (część wspólna między grą, a edytorem).

Jeżeli chcemy to możemy bazować na tym samym systemie zapisu w przypadku zapisu poziomu po stronie edytora, a tym który wczytuje gra (kwestia preferencji).

Zaletą zastosowania oddzielnych systemów jest to, że możemy wprowadzić bardziej elastyczny schemat zapisu poziomów przez wprowadzenie mini-skryptu do naszego edytora, który zadecyduje jakie informacje będą wyeksportowane do finalnego pliku poziomu bez konieczności zakodowaniu tego bezpośrednio w kodzie programu.

Załóżmy, że nasz edytor będzie obsługiwał mapy kafelkowe i każdy obiekt następuje po znaku białym. Wtedy mapa może zostać wygenerowana przy użyciu schematu:

Powiedzmy, że dyrektywa #def definiuje jakie informacje o każdym kaflu zostaną zapisane przy eksporcie, z kolei być może chcemy aby nasz plik zapisu zawierał także informacje o autorze oraz mniej informacji o kaflu. Przy takim rozwiązaniu nie ma problemu bo wszystko jest łatwe do zrealizowania i w razie zmian nie wymaga edytowania kodu i kompilowania programu od nowa (jednak całość wymaga nieco więcej poświęconej pracy).

 

Implementacja


Ten poradnik będzie zawierał implementację w C++ przy użyciu biblioteki Qt (gdy zrobię film to poinformuję o tym na blogu osobnym wpisem, a poniżej znajdzie się link do playlisty oraz link do kodu źródłowego).

Implementacja będzie zawierała niespecjalnie skomplikowany edytor poziomów kafelkowych, w którym pojawi się (oczywiście poza najuboższą wersją edytora) edytor obiektów i więcej nie chcę obiecywać bo nie chcę aby materiały były za długie (ale pewnie pojawi się też jeszcze plik zapisu ustawień użytkownika).

 

Code ON!