Autor Wątek: My own GUI ;P  (Przeczytany 10367 razy)

Offline Esidar

  • Użytkownik

# Czerwiec 24, 2009, 18:42:13
Ciekawy tutorial na temat IMGUI można znaleźć tutaj: http://sol.gfxile.net/imgui/
W tym tutorialu jest "nadinterpretacja" IMGUI :) Ja wolę ten tutorial http://mollyrocket.com/861 w którym wszystko lepiej wyjaśnione.

Główna idea IMGUI to przechowywanie danych/stanów po stronie hosta/użytkownika. Wygląd wszystkich kontrolek może być spokojnie wczytany z pliku i wszystkie animacje, blendingi itp mogą być ustawiane poza kodem. Jeżeli po wciśnięciu "NewGame" plansza ma wyjechać w lewo to mnie to nie interesuje. To jest automatycznie uruchomiona animacja z poziomu GUI.



Gdybym przeczytał tutorial http://sol.gfxile.net/imgui/ to też bym miał wrażenie że w IMGUI chodzi głównie o rysowanie przycisku w moim kodzie (użytkownika) :) Ale to byłaby przecież masakra :) Trzeba by mieć w grze hektolitry kodu w stylu:
if( Button( "KliknijMnie" ) )
{
   NicNieRob_AleNarysujRysunek("Tlo1_lewyrog",10,11);
   NicNieRob_AleNarysujRysunek("Tlo1_prawyrog",50,88);
   NicNieRob_AleNarysujRysunek("Tlo1_dolnypasek",30,11);
   NicNieRob_AleNarysujRysunek("Tlo2",150,121);
   NicNieRob_AleNarysujRysunek("Tlo3",550,388);
   NicNieRob_AleNarysujRysunek("Tlo4",350,111);
}
i za każdym razem musiałbym podawać całą definicję przycisku wklepywaną z palca w Visualu:
if( Button( "KliknijMnie", Position(10,10), Size(100, 30), Image( "LeftCorner", Offset(1,1) ), Image( "RightCorner", Offset(40,3) ) )
Byłoby to "way beyond usability" :) Zamiast tego wizualizację można zdefiniować w pliku (np. XAML). W kodzie korzystasz tylko z ID przycisku:
if( Button( "KliknijMnie" ) )
A wygląd jest zdefiniowany wcześniej i gdziekolwiek.

Ważne też żeby posługiwać się ID a nie tekstem z przycisku. W niektórych przykładach można zobaczyć:
DoTextBox( "To jest przycisk do uruchomienia gry" );
A teraz chcesz zrobić wersję na 16 języków... no i masz "z lekka" problem :) Dlatego wizualizacja jest zupełnie gdzieś indziej i jest nie zależna od kodu.

Główna idea IMGUI to przechowywanie danych/stanów po stronie hosta/użytkownika.

Jedyne czym użytkownik ma się zajmować to odczyt wyniku GUI oraz kontrolowaniem co kiedy ma się pokazać.

Cytuj
(chociaż osobiście wolę stosować automatyczny layouter, który sam wyznacza gdzie ma rysować przyciski)
Grafik "Te 5 przycisków z umiejętnościami postaci ma się ułożyć w pół okrąg, a ta lista to jest ułożona w gwiazdkę. I co ? Pykasz auto-layoutery do każdego przypadku ? :)


Jest jedna też inna rzecz powtarzana w kółko w wielu tutorialach "że zmienne podaje się podczas rysowania". Np.
DoValueEdit( &Player.Position.x );
Jest to kolejna nadinterpretacja IMGUI lub pewne niedomówienie. Równie dobrze może być tak:
DoValueEdit( LuaGlobals["Player.Position.x"] );
Nie jest istotne w jaki sposób przekażemy zmienną do systemu GUI. Czy zrobimy to za pomocą wskaźnika do "float", czy za pomocą nazwy zmiennej w LUA czy cokolwiek innego.

Ja preferuję drugą wersję bo dzięki temu nie określam typu zmiennej. W ten sposób wizualizacja decyduje jaki typ danych obsługuje i w jaki sposób je będzie reprezentować.
DoValueEdit może być TextBoxem z liczbą, może być suwakiem, ComboBox'em, planszą 2D z wyborem itd.


Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Czerwiec 24, 2009, 19:18:54
A moje_dane to strukturka zawierająca wszystkie dane które normalnie znalazłyby się w obiekcie, czyli aktualny tekst, pozycja kursora, czy editbox jest aktywny etc.? A jak nie to gdzie to trzymamy?
Trzyma to jedna z klas GUI. Warto zauważć, że w danym momencie tylko jeden EditBox jest aktywny, więc nie potrzeba trzymać takich informacji per-edit box.

Cytuj
I jeszcze jedno. Nie wiem czy dobrze rozumiem ale czy poszczególne kontrolki nic o sobie nie wiedzą? Wobec tego co w przypadku kiedy dwie kontrolki zasłaniają się, skąd wiemy która jest nad która, tj. która ma przechwycić kliknięcie?
Dwie kontrolki nie powinny się zasłaniać (jak dwa przyciski zachodzą na siebie, to coś z tym GUI jest nie teges). W moim gui o to akurat dba layouter (jak można zauważyć, nigdzie nie przekazuję informacji, jak i gdzie ten przycisk/edit narysować). :)

Cytuj
Ja wolę ten tutorial http://mollyrocket.com/861 w którym wszystko lepiej wyjaśnione.
Ja nie wolę, o mi się to video nie otwiera (swoją drogą, kto słyszał żeby robić tutoriale o kodowaniu w formie video). :)

Cytuj
Gdybym przeczytał tutorial http://sol.gfxile.net/imgui/ to też bym miał wrażenie że w IMGUI chodzi głównie o rysowanie przycisku w moim kodzie (użytkownika) :) Ale to byłaby przecież masakra :) Trzeba by mieć w grze hektolitry kodu
Jeżeli dobrze pamiętam, w tamtym tutorialu wystarczyło wywołać jedną funkcję, a nie samemu rysować przycisk. Co do sposobu wizualizacji - wiadomo, że powinno to być gdzieś indziej, najlepiej z opcją podmiany. :)

Cytuj
A teraz chcesz zrobić wersję na 16 języków... no i masz "z lekka" problem :) Dlatego wizualizacja jest zupełnie gdzieś indziej i jest nie zależna od kodu.
W moim podejściu tekst akurat jest jedyną rzeczą, której nie traktuję jako wizualizacji i jest podawany przez aplikację. Póki co przeróbka "na 16 języków" jest na tyle daleka od rzeczywistych potencjalnych wymagań, że nie zawracam sobie tym głowy. :)

Cytuj
Grafik "Te 5 przycisków z umiejętnościami postaci ma się ułożyć w pół okrąg, a ta lista to jest ułożona w gwiazdkę. I co ? Pykasz auto-layoutery do każdego przypadku ?
Zadaniem mojego GUI jest wspomaganie tworzenia edytorów, a nie menu w grach, więc równie dobrze można próbować układać buttony WinAPI w gwiazdkę z podobnym skutkiem. Mimo wszystko, powyższe da się też załatwić auto-layouterem, któremu podajesz po prostu definicję, gdzie mają leżeć kolejne przyciski. :)

Cytuj
Ja preferuję drugą wersję bo dzięki temu nie określam typu zmiennej. W ten sposób wizualizacja decyduje jaki typ danych obsługuje i w jaki sposób je będzie reprezentować.
DoValueEdit może być TextBoxem z liczbą, może być suwakiem, ComboBox'em, planszą 2D z wyborem itd.
A skąd wizualizacja ma wiedzieć, czym ten DoValueEdit ma być? ;)

Offline yarpen

  • Użytkownik

# Czerwiec 24, 2009, 19:46:05
Cytuj
Ja wolę ten tutorial http://mollyrocket.com/861 w którym wszystko lepiej wyjaśnione.
Ja nie wolę, o mi się to video nie otwiera (swoją drogą, kto słyszał żeby robić tutoriale o kodowaniu w formie video). :)
Akurat wszystkie video Caseya warto obejrzec. To czlowiek, ktory wlasciwie w pojedynke napisal Granny.

Offline Esidar

  • Użytkownik

# Czerwiec 24, 2009, 21:37:59
Cytuj
Ja wolę ten tutorial http://mollyrocket.com/861 w którym wszystko lepiej wyjaśnione.
Ja nie wolę, o mi się to video nie otwiera (swoją drogą, kto słyszał żeby robić tutoriale o kodowaniu w formie video). :)
"U mnie działa" ;p filmik jest we flashu (ja mam Flash Player 10).

Jeżeli dobrze pamiętam, w tamtym tutorialu wystarczyło wywołać jedną funkcję, a nie samemu rysować przycisk. Co do sposobu wizualizacji - wiadomo, że powinno to być gdzieś indziej, najlepiej z opcją podmiany. :)
W tym tutorialu wywołuje się "button" ze współrzędnymi. Ktoś mało roztropny pewnie zaraz by dodał parametr z nazwą wyglądu a to już się prosi o problemy :) Sprawdzając stan przycisku nie powinno się podawać nic poza identyfikatorem. Wizualizacja powinna definiować położenie przycisku względem ekranu bądź względem okna, jego wygląd podczas stanu Normal, Hot i Active, animacje w stylu bujanie się na boki lub skalowanie itd.

Cytuj
A teraz chcesz zrobić wersję na 16 języków... no i masz "z lekka" problem :) Dlatego wizualizacja jest zupełnie gdzieś indziej i jest nie zależna od kodu.
W moim podejściu tekst akurat jest jedyną rzeczą, której nie traktuję jako wizualizacji i jest podawany przez aplikację. Póki co przeróbka "na 16 języków" jest na tyle daleka od rzeczywistych potencjalnych wymagań, że nie zawracam sobie tym głowy. :)
Dobrze jest jeśli wizualizacja ma wbudowaną obsługę języków. Wtedy ktoś kto rysuje/ustawia przyciski wie czy w tym miejscu zmieści się "flugenfachenundermachen".

A skąd wizualizacja ma wiedzieć, czym ten DoValueEdit ma być? ;)
Przykładowo tak może wyglądać wizualizacja EditBoxa
<Panel id="PodajNazweGracza">
   <Rectangle color="black" x=0 y=0 w=100 h=20 />
   <FillRectangle color="white" x=1 y=1 w=98 h=18 />
   <Text editable="true" x=2 y=2 font="Arial" text_color="black" />
</Panel>
A tak suwaka:
<Panel id="PodajNazweGracza">
   <Rectangle color="black" x=0 y=0 w=100 h=20 />
   <FillRectangle color="white" x=1 y=1 w=98 h=18 />
   <Slider x=2 y=2 color="blue" />
</Panel>
Podczas rysowania, każdy element (rect, fillrect, text, slider) ma dostęp do zmiennej podanej przez użytkownika i może go sobie odpowiednio zintepretować.

DoValueEdit( "PodajNazweGracza", &Player.Name );

U mnie zmienną podaną przez użytkownika może być nie tylko float, string czy bool. Może to być również tablica. Z takiej tablicy, wizualizacja może pobrać więcej rzeczy a nie tylko 1 parametr. W ten sposób można tworzyć np. tootlip albo ikonkę narzędzia. Tooltip to nie tylko prosty rectangle i tekst ale również może być tekst z ikonką (różną w zależności od tekstu), jak również ikonka, tekst i obiekt 3D. Wszystkie dane potrzebne do wizualizacji są wtedy pobierane z parametru będącego tablicą z kolejnymi danymi.

Co do jednej rzeczy... tutaj nie ma cudów, trochę kodu w bibliotece GUI trzeba i tak napisać. To nie jest tak, że jedna klasa wszystko działa :) Trzeba mieć prymitywy które będą coś rysować (line, rect, fill), trzeba mieć proste elementy edycyjne jak np. TextBox który potrafi pobierać Input z klawiatury, rysować kursor, wpisywać znaki... również slidery które pozwalają na przesuwanie jakimś suwakiem, albo wyświetlają stan wartości za pomocą paska itd.
Wizualizacja musi mieć również hierarchię aby przycisk się przesuwał po ekranie razem z oknem.

IMGUI definiuje nie wizualizację ale sposób interakcji z wizualizacją. Nie ma tutaj klasy "gui_button" którą się przeciąża aby mieć swój przycisk. Nie ma też "gui_textbox", ale w samej wizualizacji jest "DrawText" i/lub "DrawEditableText".

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Czerwiec 24, 2009, 21:44:59
Cytuj
Dobrze jest jeśli wizualizacja ma wbudowaną obsługę języków. Wtedy ktoś kto rysuje/ustawia przyciski wie czy w tym miejscu zmieści się "flugenfachenundermachen".
OK, tylko pytanie, w czym ten ktoś będzie rysował/ustawiał te przyciski. Zapewne w jakims edytorze, więc najpierw trzeba zrobić ten edytor, a do edytora potrzebne jest GUI. ;) To, o czym piszesz będzie nadawało się jako GUI na potrzeby silnika gry (włącznie z edytorami i obsługą wielu języków), ale na potrzeby domowej produkcji to znaczny overkill. Mi chodzi o koncepcje pisania GUI do edytorów (gdzie tego GUI jest relatywnie najwięcej), a tam już artyści nie będą układać i animować przycisków - edytor ma po prostu być funkcjonalny i działać. :)

Offline Adam B

  • Użytkownik

# Czerwiec 24, 2009, 23:02:35
A ja rozwiązałem mój problem wywoływania funkcji w następujący sposób:

 - do gui_obj (najbardziej podstawowa klasa po której wszystko dziedziczy) dodałem int type; (potem może na enum zmienie zobacze)
 - type dla okna ma wartość 1, dla przycisku wartość 2 itp :)
 - wyświetlanie jest niezależne od GUI i wygląda tak:

void AllegroInterface::drawElement(BITMAP * layer, gui_obj * g){
     if (g->type==1) drawWindow(layer, (gui_window*) g);
     if (g->type==2) drawButton(layer, (gui_button*) g);
     }

 - wywołanie zaś ogólnej funkcja rysującej będzie miało postać:
for (int i=0; i<w1->content.size(); i++){// Rysuje wszystko to co zawiera się w oknie.
    Interface.drawElement(bufor, w1->content[i]);       
}

Myślę że najprostsze rozwiązanie ale mnie satysfakcjonuje.
Do klasy "gui_obj" dołączę funkcję typu getX, getY, getWidth itp. żeby wszystko zapakować ;)
Programując inną wizualizację trzeba będzie tylko wiedzieć co ma jaki: "type". No i oczywiście znać funkcje typu getCOŚ ale są IMHO bardzo intuicyjne + wywoływać funkcję Pressed, Released itp.
Wydaje mi się, że jest to proste rozwiązanie i łatwe do zrozumienia. Co wy na to ?
Pozdrawiam 

Offline Esidar

  • Użytkownik

# Czerwiec 25, 2009, 15:02:44
To, o czym piszesz będzie nadawało się jako GUI na potrzeby silnika gry (włącznie z edytorami i obsługą wielu języków), ale na potrzeby domowej produkcji to znaczny overkill.
Dlatego wcześniej wspomniałem że przydałoby się porządne GUI Open Source z porządnym edytorem :) Jeśli kogoś nie bawi robienie własnego GUI to będzie w sam raz :)


A co do samej koncepcji IMGUI to jest szalenie wygodna i nie tylko w grach. Do napisania biblioteki nie potrzeba nakładu pracy większego niż "zwykłe" GUI oparte o klasy i message, natomiast w samym użyciu jest rewelacyjne. Zwłaszcza trzymanie wszystkich stanów/danych po stronie klienta. Edytory pisze się w tym znakomicie a co najważniejsze dużo szybciej :)
Oczywiście nie mówię tutaj o toolach z jedną listą i jednym butonem, bo to można zrobić jakkolwiek. Ale jeśli masz edytor np. do układania elementów na ekranie to fakt że kontrolki GUI korzystają bezpośrednio z danych programu, jest bardzo wygodne.
Najprostszy przykład: jeżeli masz listę elementów na ekranie (1 kontrolka) oraz wyświetlasz te elementy w widoku (2 kontrolka) to pewnie chcesz aby zaznaczenie elementu było widoczne i tu i tu. Normalnie to trzeba synchronizować takie zmiany między kontrolkami, a tak to kontrolki same się o tym dowiadują/same się o to pytają. Przy okazji trzecia kontrolka wyświetlająca właściwości obiektów (Properties) sama zauważy zmianę zaznaczenia i sama odświeży parametry które pokazuje.


Offline Zombiak

  • Użytkownik

# Lipiec 03, 2009, 15:39:01
Odswieżę trochę topic. Nasuwa mi się pewna wątpliwość co do użyteczności IMGUI. Idea jest fajna tylko jakoś nie wyobrażam sobie rysowania w tym okien. Owszem jeden dialog to nie problem (chociaż byłoby to dziwne troszczyć się o relatywną pozycję kontrolek i samej ramki w kodzie gry) no to wiele takich okien kompletnie odpada. Zakładając, że piszemy te DoButton, rysowanie kontrolki odbywa się tam gdzie jej obsługa. To znaczy, że pewne elementy kontrolki zawsze będą nad innymi. Pomijając nawet okienka to zwykły combobox po rozwinięciu zostanie zasłonięty przez drugi znajdujący się niżej. Czy to ja nie łapię idei czy to faktycznie jest ograniczenie tej techniki?

Offline Dab

  • Redaktor
    • blog

# Lipiec 03, 2009, 15:41:15
Nie. Renderowanie nie odbywa się w DoButton, tylko w momencie EndGUI. Od momentu BeginGUI aż do EndGUI wszystko jest buforowane.