O czym powinienem pamiętać przy projektowaniu systemu Event Manager?

9

Grzebię w podstawach silnika gry Java i doszedłem do momentu, w którym jestem gotowy do dodania w systemie Event Manager.

Wiem teoretycznie , co powinien zrobić Menedżer zdarzeń: zezwalać obiektom na „rejestrację” określonych zdarzeń, a gdy Menedżer zdarzeń zostanie powiadomiony o zdarzeniu, przekaże je „zarejestrowanym” odbiorcom. Zastanawiam się, jak zacząć to wdrażać.

Nie byłem w stanie znaleźć niczego online na temat wdrażania systemu zdarzeń od zera, dlatego szukam informacji na temat najlepszych praktyk w tym przypadku - co powinienem, a czego nie powinienem robić.

Na przykład, czy naprawdę konieczne jest, aby każdy z moich obiektów gry miał EventManagerpole? Ponieważ wszystkie moje obiekty gry dziedziczą po jednej, abstrakcyjnej klasie nadrzędnej, myślę, że powinienem móc użyć statycznego odwołania, aby istniała tylko jedna instancja Event Managera, współdzielona między wszystkimi obiektami gry. Z apletem robię coś podobnego, czego już używam do renderowania każdego obiektu.

Podejrzewam, że musiałbym utrzymywać jakąś kolekcję dla każdego możliwego subskrybowanego zdarzenia - dodając i usuwając obiekty gry z listy, w razie potrzeby. Myślę, że powinna istnieć możliwość utworzenia kolejki zdarzeń, które muszą być transmitowane, w takim przypadku mógłbym po prostu dodać „EventManager.Update ()” do głównej pętli gry i pozwolić Update()metodzie wyemitować zdarzenia, które miały miejsce na końcu każdej ramki. Na koniec każdy obiekt miałby HandleEvent(Event e)metodę, którą mogliby odpowiednio przeanalizować i odpowiednio zareagować.


Czy to brzmi jak właściwy kierunek do wdrożenia takiego systemu, czy też jestem zejść z toru i / lub brakuje czegoś oczywistego?

Raven Dreamer
źródło
2
gamedev.stackexchange.com/questions/7718/… To jest Q / AI podane wcześniej, które mogą pomóc Ci zacząć.
James
@James Ah - wygląda jak dobry link. Dzięki! Myślę, że wcześniej mi tego brakowało.
Raven Dreamer
4
Kilka dodatkowych wskazówek: zdecyduj, czy niektóre zdarzenia powinny faktycznie zadziałać natychmiast, a nie na końcu ramki, zwłaszcza jeśli program obsługi zdarzeń wyzwala dodatkowe zdarzenia; pomyśl, co się stanie, gdy otrzymasz pętle zdarzeń; jeśli wybierzesz kolejkę, być może będziesz potrzebować systemu priorytetowego lub sposobu na ominięcie kolejki.
sam hocevar,

Odpowiedzi:

6

Może to być tak proste, jak chcesz.

for each object in the subscriber list:
    object.notify(this event) // (or 'HandleEvent' if you prefer)

Nie próbuj ustalać, co powinien zrobić menedżer wydarzeń - ustal, czego potrzebujesz. Reszta powinna podążać stamtąd, a przynajmniej powinna sugerować bardziej szczegółowe pytania.

Kylotan
źródło
3
+1 za „Nie próbuj ustalać, co X powinien zrobić” - ustal, co musisz zrobić. ” W rzeczywistości nie dodawaj menedżera zdarzeń, dopóki nie poczujesz, że potrzebujesz jakiegoś oddzielnego, a jednocześnie scentralizowanego sposobu wywoływania funkcji.
@JoeWreschnig O Boże tak =) „ustal, co musisz zrobić” Jest to jedna z 3 najlepszych porad, które każdy programista powinien wziąć sobie do serca.
Patrick Hughes,
Na początku chciałem się nie zgodzić z twoim drugim zdaniem na temat nie dodawania menedżera zdarzeń, ponieważ większość gier może korzystać z oddzielnego, ale scentralizowanego sposobu wywoływania funkcji, ale potem pomyślałem o tym, ile małych gier stworzyłem, ale nie mieć dowolnego menedżera wydarzeń. więc tak
jhocking
3

Trzy podstawowe metody, których potrzebuje system zdarzeń, to metoda addListener (), metoda removeListener () oraz metoda dispatchEvent (). Oznacza to, że obiekty metody używają do rejestracji zdarzenia, obiekty metody używają do wyrejestrowania się oraz metoda faktycznej transmisji zdarzenia do wszystkich detektorów. Cała reszta to sos.

Jak zauważysz, na pewno będziesz potrzebować jakiejś struktury danych, aby śledzić zarejestrowanych słuchaczy. Najprostszym podejściem jest tablica asocjacyjna (słownik lub obiekt w JavaScript), która wiąże wektor (lub po prostu tablicę w zależności od języka) ze zdarzeniem. Ten wektor jest listą wszystkich zarejestrowanych słuchaczy; dodaj detektory do listy lub usuń je w metodach add / removeListener ().

Aby wyemitować zdarzenie w dispatchEvent (), może być tak proste, jak zapętlenie wektora. Możesz zwiększyć złożoność wysyłania, sortując priorytet zdarzeń lub cokolwiek innego, ale nie przejmuj się tym, dopóki go nie potrzebujesz. W wielu przypadkach nie będziesz go potrzebować.

Jest trochę niuansów w stosunku do dispatchEvent (), gdy rozważasz, jakie dane przekazać wraz ze zdarzeniem. Na najbardziej podstawowym poziomie możesz nie przekazywać żadnych dodatkowych danych; słuchacz musi tylko wiedzieć, że wydarzenie miało miejsce. Jednak większość zdarzeń ma dodatkowe dane, które się z nimi wiążą (np. Gdzie zdarzenie miało miejsce), dlatego chcesz, aby dispatchEvent () akceptował i przekazywał niektóre parametry.

Na przykład, czy naprawdę konieczne jest, aby każdy z moich GameObjects miał pole „EventManagner”? Ponieważ wszystkie moje obiekty GameObject dziedziczą po jednej, abstrakcyjnej klasie nadrzędnej, myślę, że powinienem móc użyć statycznego odwołania, aby istniała tylko jedna instancja menedżera zdarzeń, współdzielona przez wszystkie obiekty gry.

Istnieje wiele sposobów nadania wszystkim obiektom gry odniesienia do klasy EventManager. Odniesienie statyczne to z pewnością jeden sposób; inny jest z Singletonem. Oba te podejścia są jednak dość mało elastyczne, więc większość ludzi tutaj poleca lokalizator usług lub zastrzyk zależności. Robiłem zastrzyk zależności; oznacza to oddzielne pole EventManager dla każdego obiektu, co wydaje się być tym, czego chcesz unikać, ale nie jestem pewien, dlaczego jest to problem. Nie jest tak, że przechowywanie wielu wskazówek jest dużym obciążeniem.

jhocking
źródło
tak, po raz pierwszy naprawdę zrozumiałem i zaimplementowałem zastrzyk zależności dla obiektu EventDispatcher. Kiedy już to założyłem, miałem ochotę przerobić wiele rzeczy według tego wzoru.
jhocking 12.10.11
0

ZRZECZENIE SIĘ

Nie jestem programistą Java, ale napisałem artykuł wyjaśniający, jak stworzyć system zdarzeń w C89, jednym z najłatwiejszych języków (IMHO), sprawdź to

https://prdeving.wordpress.com/2017/04/03/event-driven-programming-with-c-89/

Podstawy obsługi zdarzeń są dość proste.

  • zarejestrować wydarzenie za pomocą oddzwaniania
  • zdarzenie wyzwalające
  • przeglądaj słuchaczy, aby sprawdzić, czy istnieje dopasowanie
  • program obsługi ognia, jeśli został znaleziony
  • powtarzać

Wiedząc o tym (ale nie wiedząc, jak zaimplementować go w Javie), łatwo zrozumieć, że potrzebujesz niektórych programów obsługi (funkcji do obsługi zdarzeń) i dodaj je do tablicy (ze wskaźnikami w C) w połączeniu z nazwą zdarzenia. Po uruchomieniu zdarzenia zapisujesz nazwę wyzwalanego zdarzenia i jego argumenty w stosie, jest to nazywane pulą zdarzeń.

Następnie masz podsumowanie zdarzenia (prosta pętla), który wyskakuje pierwsze zdarzenie w tym stosie, próbuje znaleźć dla niego moduł obsługi, a jeśli istnieje, uruchamia go z parametrami.

Oczywiście to podsumowanie zdarzeń można uruchomić w dowolnym momencie, na przykład raz na klatkę po wywołaniu Update()funkcji.

PRDeving
źródło
-2

Dla pola EventManager użyj zmiennej statycznej. Singleton dla EventManager również byłby świetnym pomysłem.

Twoje podejście brzmi dobrze, ale nie zapomnij, aby było bezpieczne dla wątków.

Dobrze jest wykonywać zdarzenia IO przed lub po „GameEvent”, więc w jednej klatce każde „GameEvent” zajmuje się tymi samymi danymi.

Sibbo
źródło
„Zapisywanie wątku”? Hmmm
U62,
-1 za całkowicie niepotrzebną i nieuzasadnioną sugestię singletonu.