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ł EventManager
pole? 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?
Odpowiedzi:
Może to być tak proste, jak chcesz.
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.
źródło
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.
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.
źródło
Podstawy obsługi zdarzeń są dość proste.
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.źródło
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.
źródło