Tradycyjny projekt gry , tak jak ja to wiem, wykorzystuje polimorfizm i funkcje wirtualnych do aktualizacji gry objects stany. Innymi słowy, ten sam zestaw funkcji wirtualnych jest wywoływany w regularnych odstępach czasu (np. Na klatkę) na każdym obiekcie w grze.
Niedawno odkryłem, że istnieje inny system przesyłania wiadomości sterowany zdarzeniami, który umożliwia aktualizowanie stanów obiektów gry. W tym przypadku obiekty zwykle nie są aktualizowane dla poszczególnych klatek. Zamiast tego budowany jest wysoce wydajny system powiadamiania o zdarzeniach , a obiekty gry są aktualizowane tylko po otrzymaniu prawidłowego komunikatu o zdarzeniu.
Architektura gier sterowana zdarzeniami jest dobrze opisana w: Game Coding Complete autorstwa Mike'a McShaffry'ego .
Czy mogę prosić o pomoc w następujących kwestiach:
- Jakie są zalety i wady obu podejść?
- Gdzie jest jedno lepsze od drugiego?
- Czy projektowanie gier oparte na zdarzeniach jest uniwersalne i lepsze we wszystkich obszarach? Czy jest zatem zalecany do stosowania nawet na platformach mombile?
- Który jest bardziej wydajny, a który trudniejszy do opracowania?
Aby wyjaśnić, moje pytanie nie dotyczy całkowitego usunięcia polimorfizmu z projektu gry. Chcę po prostu zrozumieć różnicę i czerpać korzyści z używania komunikatów sterowanych zdarzeniami w porównaniu do zwykłych (na ramkę) wywołań funkcji wirtualnych w celu aktualizacji stanu gry.
Przykład: To pytanie wywołało tutaj trochę kontrowersji, więc dam wam przykład: Według MVC silnik gry jest podzielony na trzy główne części:
- Warstwa aplikacji (komunikacja sprzętu i systemu operacyjnego)
- Logika gry
- Widok gry
W grze wyścigowej Game View odpowiada za renderowanie ekranu tak szybko, jak to możliwe, co najmniej 30 klatek na sekundę. Widok gry nasłuchuje również danych gracza. Teraz tak się dzieje:
- Gracz naciska pedał paliwa do 80%
- GameView konstruuje komunikat „Pedał paliwa samochodu 2 wciśnięty do 80%” i wysyła go do Game Logic.
- Game Logic odbiera komunikat, ocenia, oblicza pozycję i zachowanie nowego samochodu i tworzy następujące komunikaty dla GameView: „Draw Car 2 Fuel Pedal Pressed 80%”, „Car 2 Sound Acceleration”, „Car 2 Coordinates X, Y” .. .
- GameView odbiera wiadomości i odpowiednio je przetwarza
źródło
update
je wywołaj ). Drugie, co możesz zrobić z wiadomościami z różnych powodów.Odpowiedzi:
Wierzę w konieczność bycia matką wynalazku. Nie lubię niczego kodować, chyba że jego potrzeba jest jasna i dobrze zdefiniowana. Myślę, że jeśli zaczniesz projekt od skonfigurowania systemu powiadamiania o zdarzeniach, robisz to źle. Uważam, że dopiero po utworzeniu i przetestowaniu infrastruktury i posiadaniu wszystkich elementów projektu, które mają dobrze zdefiniowane, działające moduły, powinieneś skoncentrować się na sposobie łączenia tych modułów ze sobą. Próba zaprojektowania systemu powiadamiania o zdarzeniach, zanim zrozumiesz kształt i potrzeby każdego modułu, jest niesprawna.
Jakie są zalety i wady obu podejść?
Myślę, że niektórzy twierdzą, że istnieją dobre systemy przesyłania wiadomości gotowe do zainstalowania i używania. Być może to prawda. Z pewnością wydajność niestandardowego rozwiązania specjalnie dostosowanego do twoich potrzeb byłaby większa niż magistrala komunikatów ogólnego przeznaczenia. Najważniejsze pytanie brzmi: ile czasu poświęcisz na zbudowanie systemu przesyłania wiadomości zamiast na korzystanie z czegoś, co już zostało zbudowane. Oczywiście, jeśli możesz znaleźć system zdarzeń z dokładnie takim zestawem funkcji, jakiego potrzebujesz, to dość łatwa decyzja. Dlatego upewniam się, że dokładnie rozumiem, czego potrzebuję, zanim podejmę tę decyzję.
Gdzie jest jedno lepsze od drugiego?
Tutaj moglibyśmy porozmawiać o pamięci i zasobach. Jeśli projektujesz dla dowolnego sprzętu z ograniczonymi zasobami, z pewnością problemem jest użycie systemu zdarzeń, który znacznie się w to zaangażuje. Naprawdę myślę, że problem sprowadza się do tego, czego potrzebujesz, co, jak już wspomniałem, jest czymś, czego nie wiesz, dopóki nie zobaczysz, jak wyglądają wszystkie elementy. Jeśli masz wystarczające doświadczenie w budowaniu tych systemów, które wiesz z góry dokładnie, jak będą wyglądać wszystkie elementy, możesz również wcześniej odpowiedzieć na to pytanie. Zgaduję, że nie masz tego doświadczenia, ponieważ nie zadałbyś tego pytania, gdybyś miał.
Czy projektowanie gier oparte na zdarzeniach jest uniwersalne i lepsze we wszystkich obszarach? Czy jest zatem zalecany do stosowania nawet na platformach mobilnych?
Uniwersalny i lepszy we wszystkich obszarach? Takie dość ogólne oświadczenie można łatwo odrzucić. Wszystko, co dodaje koszty ogólne, musi być obciążone pracą. Jeśli nie używasz zdarzeń wystarczająco, aby uzasadnić narzut projektu, oznacza to, że jest to projekt niewłaściwy.
Który jest bardziej wydajny, a który trudniejszy do opracowania?
Wydajność zależy od sposobu jej wdrożenia. Myślę, że dobrze rozwinięty tradycyjny projekt przewyższy system oparty na wydarzeniach każdego dnia tygodnia. Wynika to z faktu, że komunikacja między elementami może być mikro-zarządzana i super wydajna. Oczywiście utrudnia to również projektowanie z punktu widzenia doświadczenia i czasu potrzebnego na jego ukończenie i zwiększenie wydajności. Z drugiej strony, jeśli nie masz wystarczającego doświadczenia lub nie masz czasu, aby dobrze rozwinąć aplikację, to bardziej efektywne będzie zastosowanie projektu opartego na zdarzeniu, który odpowiada Twoim potrzebom. Jeśli masz niestandardowe potrzeby dotyczące zdarzeń, które nie mieszczą się łatwo w strukturze opartej na zdarzeniu, może to bardzo utrudnić zaprojektowanie struktury opartej na zdarzeniu - szczególnie w celu utrzymania wydajności projektu.
źródło
Myślę, że porównujesz tutaj jabłka i pomarańcze. Polimorfizm wcale nie jest zastępowany wiadomościami. Prawdopodobnie chciałbyś, aby zdarzenia / komunikaty łączyły luźno powiązane komponenty. Na przykład. wysłać wiadomość od bytu, gdy nastąpi kolizja, zaktualizować wynik gracza lub może wywołać efekt dźwiękowy. Aby te poszczególne klasy nie znały innych klas i po prostu wysyłały i / lub obsługiwały wiadomości.
Ale gra jest najprawdopodobniej będzie mieć gdzieś pętli aktualizacji i ponieważ mają tę pętlę aktualizacji, to może być łatwo wykorzystane do aktualizacji wszystkich podmiotów gry, które muszą być aktualizowane co ramki, jak również. Nie przeszkadza to jednak w korzystaniu z wiadomości ...
Jeśli masz jakąś strukturę, w której dodajesz / usuwasz elementy gry, możesz równie dobrze uwzględnić je w pętli aktualizacji, zamiast wysyłać im komunikat aktualizacji w każdej ramce. Dlaczego więc nie wywołać aktualizacji bezpośrednio na elementach gry, gdy używasz wiadomości do łączenia różnych podsystemów gry? Podoba mi się również koncepcja Signal / Slot ( patrz przykład qt ) dla systemów podobnych do zdarzeń.
Podsumowując: Nie ma lepszego podejścia, ani nie są one wyłączne.
źródło
Zaczęło się to jako komentarz do odpowiedzi Bummzacka, ale stało się długie.
O ile faktycznie nie uczynisz go asynchronicznym (wysyłanie zdarzeń do nowego wątku), twoje obiekty nadal otrzymają notatkę synchronicznie. Zakładając, że dyspozytor zdarzeń korzysta z podstawowej tabeli skrótów z połączoną listą w komórce, kolejność będzie kolejnością, w której obiekty zostały dodane do tej komórki.
Ponadto, chyba że z jakiegoś powodu zdecydujesz się użyć wskaźników funkcji, nadal używasz wirtualnych wywołań funkcji, ponieważ każdy obiekt otrzymujący komunikat musi implementować IEventListener (lub jakkolwiek to nazwiesz). Wydarzenia to abstrakcja wysokiego poziomu, którą budujesz za pomocą polimorfizmu.
Skorzystaj z wydarzeń, w których musisz wywołać listę prania metod różnych wydarzeń w grze, aby zsynchronizować różne systemy w grze lub gdzie różne obiekty i reakcje systemów, więc wspomniane zdarzenia nie mogą być jasno zdefiniowane lub chcesz dodać więcej reakcji na te wydarzenia w przyszłości.
Są doskonałym narzędziem, ale jak powiedział bummzack, nie zakładaj, że polimorfizm i zdarzenia rozwiązują ten sam problem.
źródło
Powiedziałbym, że wybranie jednego lub drugiego jest całkiem złe. Niektóre obiekty wymagają wywołania każdej klatki, niektóre nie. Jeśli masz obiekt, który chcesz wyrenderować, musisz wykonać wywołanie renderowania do każdej klatki. Wydarzenia nie mogą wprowadzić tej zmiany. To samo dotyczy wszelkich obiektów fizycznych opartych na czasie - musisz wywoływać je w każdej klatce.
Jednak nie wykonuję wywołań co ramkę do moich obiektów zarządzania obiektami, obiektów wejściowych użytkownika ani niczego podobnego. Masowe wirtualne połączenia z każdym obiektem w ramce to straszny pomysł.
Projekt zastosowany do dowolnego konkretnego obiektu powinien opierać się na potrzebach tych obiektów, a nie na nich na jakiejś ideologii dla całego systemu.
Edytowane, aby było bardziej jasne w pierwszym zdaniu.
źródło