Zastanawiałem się więc, jak monolitycznie spędzają czas moje zajęcia. Na przykład w metodzie Character
klasy Jump
można mieć odniesienie do obiektu z efektem dźwiękowym i odtwarzać to. To samo w sobie jest w porządku, ale jeśli weźmie się pod uwagę fizykę, animację, kolizję itp., Metoda Jump staje się ogromna, a Character
klasa ma wiele zależności od wielu różnych rzeczy. Mimo to może być w porządku. Co jednak, jeśli nie chcemy już odtwarzać dźwięku, gdy postać skacze? Teraz musimy znaleźć ten konkretny wiersz kodu w pomieszanym bałaganie Jump
kodu i skomentować go lub cokolwiek innego.
Więc ... myślałem ...
Co jeśli zamiast tego istniała jakaś AudioSystem
klasa i wszystko, co zrobiła, to subskrybować losowe wydarzenia, którymi interesują się inne klasy. Na przykład Character
klasa może mieć Jumped
zdarzenie (chyba też statyczne), które jest wywoływane w Character
klasie w metodzie. Następnie Character
klasa nie wiedziałaby nic o małym efekcie dźwiękowym, który jest odtwarzany, gdy postać skacze. AudioSystem
Będzie tylko ogromna klasa, że programista mógł wycofać się zahaczyć efekty dźwiękowe z pewnych zdarzeń, które dzieją się w grze dzięki wykorzystaniu imprez statycznych. Następnie, jeśli to ma zbyt duży to może być oddzielone do podklasy, takich jak EffectsAudioSystem
, BackgroundAudioSystem
, AmbientAudioSystem
, et cetera.
Następnie, w opcjach gry, można mieć pole wyboru, aby włączyć lub wyłączyć tego rodzaju dźwięki, a wszystko, co trzeba zrobić, to po prostu wyłączyć ten system za pomocą prostej i pojedynczej flagi boolowskiej. Pomysł systemów można również rozszerzyć na takie rzeczy, jak fizyka, animacje itp., Do tego stopnia, że większość reakcji w grze wynikających z działań gracza jest połączona przez te skomplikowane i oddzielone systemy.
Okej, więc moje pytanie może być trochę niejasne, ale jak to brzmi? Tak naprawdę nigdy nie słyszałem o wielu rozmowach na temat tego rodzaju systemu. To wszystko jest teraz w mojej głowie bez żadnego kodowania, więc być może jest to jedna z tych „dobrych w teorii, ale nie w praktyce” transakcji. Czy ten system działałby z większą grą, czy w końcu mógłby się zepsuć i stałby się jeszcze bardziej bałaganem spaghetti niż oryginalny system?
źródło
Odpowiedzi:
Wiadomości są piekłem do debugowania i zarządzania. Brzmi dobrze w teorii, ale po wdrożeniu robi się bałagan z dużą ilością zduplikowanych danych. Efekt dźwiękowy skoku będzie wymagał na końcu dużo więcej danych, na przykład pozycji, prędkości, materiału, na którym znajduje się postać, nazywasz ją, lista będzie długa na końcu.
Więc albo będziesz musiał zebrać te dane i wysłać je do AudioManager za pomocą bardzo konkretnego zdarzenia / wiadomości z skopiowanymi danymi, albo wyślesz odniesienie do znaku w wiadomości, aby AudioManager mógł uzyskać dostęp do danych, zarówno sposoby stają się chaotyczne, a teraz menedżer audio musi wybrać dźwięk dla podziemnego materiału itp.
Tak więc na koniec konkretne wydarzenie (które jest bardzo specyficzną klasą tylko dla tego komunikatu) ponownie połączy te klasy bardzo głęboko. Niewiele wygranych, a na koniec będziesz mieć bałaganiarską dużą listę bardzo specyficznych wydarzeń / klas, które służą tylko do wysyłania danych, które już istnieją i mogą być nieaktualne i będą cierpieć z powodu wszystkich innych problemów z powielonymi danymi .
Będzie więc ogromna lista niepotrzebnych klas do utrzymania, które wprowadzą głębokie sprzężenie między postacią a AudioManagerem, tyle że teraz jest rozproszone po całym kodzie źródłowym. Nie tylko w klasach Character i AudioManager.
Nadal dobrym pomysłem jest oddzielenie kodu, ale Wiadomości to tak naprawdę kolejny sposób głębokich połączeń. Niektóre kody muszą być tylko połączone, użyj najbardziej bezpośredniego sposobu, aby je połączyć, nie nadużywaj inżynierii.
źródło
Nie sądzę, żeby system przekazywania wiadomości w ogóle skończył się na inżynierii. W rzeczywistości może to znacznie ułatwić wykonywanie zadań w fazie polskiej. Robisz to dobrze!
To, co opisałeś, jest dokładnie tym, co razem wrzuciłem do naszej gry Global Game Jam w zeszłym roku. Byłem odpowiedzialny za tworzenie i edytowanie SFX oraz integrację muzyki, którą ja i inny kompozytor napisaliśmy w grze w sposób, który nie był do bani.
To, co jest świetne w tym podejściu z perspektywy audio, polega na tym, że pozwala ono robić o wiele więcej interesujących rzeczy z dźwiękiem. Jeśli uważasz, że efekt dźwiękowy w grze to tylko plik dźwiękowy, głośność i panoramowanie, oznacza to, że robisz to źle.
Przykład
W naszej grze byłeś dinozaurem latającym statkiem kosmicznym biegnącym na planety, aby zdobyć punkty. Pracowaliśmy we Flashu, więc infrastruktura oparta na danych nie była potrzebna. AudioManager był klasą składającą się z szeregu metod statycznych, których jedynym celem było kontrolowanie dźwięków, które wydarzyły się w wyniku zdarzenia w grze.
Gdybym miał napisać to w C ++, zajęłoby to trochę więcej czasu, aby wyodrębnić wszystkie możliwe zachowania dźwięków. Wymagania dotyczące komunikatu informującego system o podjęciu działania nie byłyby zbyt skomplikowane. Potrzebowałby po prostu typu wiadomości, wpływu na obiekt pochodzenia lub obiekt, dostępu do pewnego rodzaju kontekstu stanu gry i niewiele więcej. Protokół może rosnąć wraz ze wzrostem potrzeb gry. Oczywiście, jeśli robisz to wszystko w implementacji kodu (jak nasz tandetny kod GGJ), masz gorszy problem z klasą monolityczną. Ale łatwo to złagodzić, tworząc system oparty na danych.
W każdym razie, oto jak nasz system audio do gry zareagował na różne wiadomości:
Gracz zderza się z planetą: wywołałoby to dźwięk wybuchu planety, wystarczająco podstawowy. natychmiast po zapytaniu o działający licznik kombinacji. Gdyby był wystarczająco wysoki, zaplanowałby, że efekt dźwiękowy zostanie odtworzony około pół sekundy później dinozaura, który wyda ryk zwycięstwa. Również w tle obliczono losową liczbę ludności planety (coś w rodzaju od 600 do 3000 - nie mam pojęcia, dlaczego ten zakres został wybrany, była to porzucona mechanika rozgrywki i wciąż leżał dookoła, aby użyć mnie, aby dźwięk był interesujący), i wykorzystałem to do skalowania głośności odległego dźwięku krzyków (obywatele planet spotykający przedwczesny los).
Gracz przytrzymuje spację w celu przyspieszenia: po otrzymaniu tego odtwarzano dźwięk „steru”, ale jednocześnie słychać było niski ryk silnika narastający przez 1,5 sekundy. Układ cząsteczkowy wykorzystał to również do odpalenia emitera IIRC
Gracz puszcza spację w celu spowolnienia: Teraz, gdy gracz puścił spację, system audio wiedział, że musi zwolnić pętlę silnika. Gdybym miał więcej czasu, wolałbym nałożyć na niego kolejny dźwięk, który był rodzajem marudzenia obniżającego dźwięk.
Gracz zderza się ze złą miną kosmiczną: miny kosmiczne są złe, więc nie tylko występuje metaliczny dźwięk uderzenia połączony z eksplozją (który jest po prostu wypalony w jednym dźwięku), ale także losowo wybrany dźwięk przerażenia dinozaura. Bardziej prawdopodobne jest, że wybierze więcej „płaczących” dźwięków, gdy zdrowie gracza spadnie.
Już i tak fajna gra staje się przyjemnością, gdy jej ścieżka dźwiękowa jest aktywna i dynamiczna, nawet przy niewielkich prostych zachowaniach, jak opisano powyżej. Tak, istnieje pewna logistyka do dopilnowania, aby upewnić się, że prawidłowe dane zostaną przekazane. Ale hej, BFD. Będzie to dalekie od najbardziej skomplikowanej rzeczy, którą musisz napisać w większym zakresie kodu gry.
W rzeczywistości FMOD i Wwise działają w ten sposób. Nie mają centralnego programu do wysyłania wiadomości, ale skutecznie publikujesz zdarzenia w ich centralnych systemach i reagują, odtwarzając efekt dźwiękowy, który został wcześniej zaprojektowany przez implementatora audio w narzędziu do tworzenia treści. Pomyśl o tym, jakbyś dał swojej grze DJ-a na żywo. Siedzi i obserwuje, co się dzieje, i uruchamia klipy dźwiękowe we właściwym czasie, aby zachować ciekawość, miksując je tak, aby dobrze pasowały do istniejącego środowiska audio.
[EDYCJA] Widzę też, że otagowałeś ten C #. Czy to XNA, a jeśli tak, czy używasz XACT? Jeśli używasz XNA, powinieneś używać XACT.
źródło
EventManager->dispatch("Sound:PlayerJump")
isoundSystem->playFMODEvent("/MyGame/Player/Jump")
.Zgadzam się z Maikiem Semderem, że system przekazywania wiadomości może być nadmiernie inżynierski (na razie zresztą).
Z tego co rozumiem, klasa obecnie wygląda jak „monolitycznego klasy” Bjorn jak widać w „monolitycznego klasy” tutaj .
Sugeruję przeczytanie tego artykułu i chociaż na razie przesadzenie z systemem składowym byłoby przesadą, to jeśli przeczytasz „Podział reszty”, powinno to dać ci dobry sposób na wyodrębnienie swoich zachowań i ewentualnie przejście do bardziej złożonego rozwiązanie. To da ci dobrą bazę do rozpoczęcia.
źródło