Autor Wątek: Tworzenie GUI dla gry, co lepsze: zmienne typu bool czy zdarzenia?  (Przeczytany 3029 razy)

Offline endifreekolesio

  • Użytkownik

# Sierpień 10, 2014, 13:46:48
Witam,
otórz tworzę sobie bardzo uproszczoną bibliotekę interfejsu dla gry we frameworku Monogame i zastanawiam się nad kwestią obsługi kliknięcia czy najechania na dany obiekt(zazwyczaj guzik) poprzez mysz lub palce. Obecnie kod do tego służący wygląda mniej więcej tak:

     void ActionsUpdate()
     {
        if (_IsHovered())
        {
            IsHovered = true;
            if (_IsPressed())
                IsPressed = true;
            else
                IsPressed = false;
        }
        else
        {
            IsHovered = false;
            IsPressed = false;
        }


        if (_IsRelased())
            IsRelased= true;
        else
            IsRelased= false;
     }

Gdzie IsHovered, IsRelased oraz IsPressed są to publiczne zmienne boolowskie klasy TouchableImage(po której dziedziczą wszystkie elementy interfejsu), a _IsHovered(), _IsRelased() oraz _IsPressed() są to prywatne metody, które kolejno sprawdzają czy dane wyrażenie jest prawdziwe. A np wywołanie jakiejś operacji przy kliknięciu na guzik sprowadza się do takiego kodu:

if(someButton.IsRelased)
{
    //tutaj wstawiamy operacje wykonywane przy kliknięciu
}

W każdym bądź razie mam sobie taki kodzik napisany już jakiś czas temu i ostatnio wziąłem się za naukę takich rzeczy jak delegaty i zdarzenia, tu nasuwa się moje pytanie, skoro są one używane w raczej w aplikacjach które w założeniu są bardziej statyczne od gier i nie aktualizują się 60 razy na sekundę i rzeczy takie jak kliknięcie myszą działają poprzez element przyczynowo skutkowy, to czy jest sens wprowadzania czegoś takiego jak zdarzenia do gry? Nie obadałem tego tematu jeszcze wystarczająco aby stwierdzić jakie zyski mi przyniesie taka modyfikacja, więc pytam się was, czy jest sens w to brnąć? Będę wdzięczny za konstruktywną argumentację :).
« Ostatnia zmiana: Sierpień 10, 2014, 14:04:39 wysłana przez endifreekolesio »

Offline Mr. Spam

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

Offline Amun

  • Użytkownik

  • +1
# Sierpień 10, 2014, 15:13:27
Event handling wg mnie jest bardzo ważny szczególnie w grach... najlepszy sposób na informowanie innych podsystemów o jakimś wydarzeniu. Co to daje? Nie sprawdzamy na okrągło, w każdej klatce, czy klawisz został wciśnięty, lecz w przypadku zdarzeń, jeżeli coś zostanie wciśnięte to dopiero wtedy jest dokonywane sprawdzanie itp.

Też bardzo się przydaje ten sposób jeżeli chodzi o OOP - różne podsystemy nic o sobie nie wiedzą nawzajem, a mogą się swobodnie komunikować za pomocą zdarzeń. A jeżeli dodamy dodatkowy podsystem(np. audio) - nie ma to wpływu na pozostałe systemy.

Trochę na szybko to pisałem, więc może być coś nie jasne, jak coś pytaj. Mam nadzieję, że dobrze zrozumiałem pytanie :)

Tutaj masz trochę do poczytania na ten temat:
http://www.gamedev.net/page/resources/_/technical/game-programming/simple-event-handling-r2141

Tutaj trochę argumentów:
http://www.reddit.com/r/gamedev/comments/18xmm9/how_does_event_handling_work/

Offline ArekBal

  • Użytkownik

# Sierpień 10, 2014, 15:19:56
Cytuj
Co to daje? Nie sprawdzamy na okrągło, w każdej klatce, czy klawisz został wciśnięty, lecz w przypadku zdarzeń, jeżeli coś zostanie wciśnięte to dopiero wtedy jest dokonywane sprawdzanie itp.
W podejściu immediate cacheujesz wszystko i też odpytujesz o stan tylko gdy coś cię zapyta.

Oba podejścia mają sens.
To powyższe(tzw. "Immediate GUI") jest prostsze.
Zostań na razie przy tym.
Sam zobaczysz kiedy potrzebujesz dopiąć model zdarzeniowy. Np. wpisywanie przez usera tekstu, albo zdarzenia ruchu myszy... generalnie na cały user input powinien iść na zdarzeniach. Można co prawda zamieniać zdarzenia w kolejki i je opróżniać w update ale będzie to trochę... hmm.

No w ogóle w immediate wielu rzeczy nie zrobisz - trzeba się z tym pogodzić i w tych miejscach zastosować model zdarzeniowy albo coś lepszego jeśli się zna...

Jeśli dobrze zakodować to obie metody mają zastosowanie. Czasami dostaniesz z systemu zdarzenie i pomiędzy updatami zamienisz w stan... a czasami obserwując zmianę stanu wygenerujesz zdarzenie.


Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Sierpień 10, 2014, 16:27:51
Cytuj
Sam zobaczysz kiedy potrzebujesz dopiąć model zdarzeniowy. Np. wpisywanie przez usera tekstu, albo zdarzenia ruchu myszy... generalnie na cały user input powinien iść na zdarzeniach.
Napisałem w Immediate Mode cały edytor do demek 4k i chyba jedynym miejscem, gdzie "zdarzenia" się przydały była obsługa edycji grafu i treeview dla projektu, przy czym zdarzenia były realizowane po prostu jako wywołanie odpowiedniej metody OnCośtam na danym elemencie.

Jeżeli o input chodzi, to EditBox dało się zrobić też bezproblemowo w Immediate Mode:
bool EditBox( void *target, int flags, const UIInputConverter &converter );Gdzie:
- target - wskaźnik na edytowaną rzecz (chociaż jak teraz na to patrze, można by go zrobić jako pole konwertera),
- flags - różne flagi (styl/layout, itp),
- converter - klasa robiąca konwersje string<->to co edytujemy,
- return value - true, jeżeli wartość została właśnie zmieniona


Ale jeżeli chodzi o samo GUI w ogólności, to są tu większe problemy niż decydowanie immediate mode/zdarzenia, zwłaszcza jeżeli chodzi o GUI do gier mobilnych, gdzie wypadało by mieć trochę animacji, multitouch, swipowanie, itp i jeszcze trzeba jakoś w miarę wygodnie samo GUI tworzyć.

Offline endifreekolesio

  • Użytkownik

# Sierpień 10, 2014, 17:05:29
Przekonaliście mnie i przy okazji wpadło mi do głowy kilka pomysłów jak mógłbym uprościć swoją grę dzięki tym całym zdarzeniom. Dzięki wielkie za odpowiedzi :)

Offline ArekBal

  • Użytkownik

# Sierpień 10, 2014, 17:44:09
Cytuj
Jeżeli o input chodzi, to EditBox dało się zrobić też bezproblemowo w Immediate Mode:
KK:
z mojego doświadczenia z inputem przy rozsądnym wpisywaniu tekstu w update można dostać zmianę na 2 znakach jednocześnie i bez zastosowania zdarzeń lub wspomnianych kolejek nie rozpoznasz kolejności wklepywania znaków. Musisz je wtedy interpretować właśnie tak... jako dwa znaki wciśnięte jednocześnie.
O wspomnianych przez ciebie swipeach, czy innych gestach myszą wspominając.
O niestabilnym latency z input do audi, czy czasami też o input do fizyki też nie wspominając.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Sierpień 10, 2014, 18:35:54
Cytuj
z mojego doświadczenia z inputem przy rozsądnym wpisywaniu tekstu w update można dostać zmianę na 2 znakach jednocześnie i bez zastosowania zdarzeń lub wspomnianych kolejek nie rozpoznasz kolejności wklepywania znaków.
Kolejka jest, ale znaków, w kodzie od obsługi wejścia. Kolejka jest jedna dla całej aplikacji i czyszczona na koniec każdej klatki (co by nieobsłużone znaki nie zostawały). W przypadku edycji, aktywny EditBox po prostu sobie znaki z kolejki zczytuje.

Cytuj
O wspomnianych przez ciebie swipeach, czy innych gestach myszą wspominając.
Tutaj to akurat eventy są w komórkowych API bardzo na siłę i musiałem wręcz napisać do tego dodatkową nakładkę, która by to przerobiła do postaci normalnej tablicy dotyków. Od tego miejsca, każdy dotyk może być już zawłaszczany albo tylko oznaczany jako obsłużony przez różne obiekty. Fakt, że momentami robi się z tego trochę system zdarzeń. Przykładowo moduł obsługi dotyku rozpoznaje sytuację, gdy dotyk się pojawił, nie został zawłaszczony ani nie przesunął się o więcej niż epsilon i zniknął - w kolejnej klatce taki dotyk będzie w stanie "pełne kliknięcie ukończone", czyli de facto zdarzeniem. Główną różnicą jest tu jednak fakt, że routing zdarzeń odbywa się tutaj metodą pull - podczas uruchamiania kontrolek IM GUI (w kolejności top->bottom) pierwsza kontrolka której bounding box złapie takie "zdarzenie" po prostu je obsłuży.

Cytuj
O niestabilnym latency z input do audi, czy czasami też o input do fizyki też nie wspominając.
Te dwa to mają akurat mało wspólnego z tematem IM GUI.