Zaczynam od pierwszego „właściwego” projektu gry i nieuchronnie uderzyłem w blok, próbując zdecydować, w jaki sposób komponenty gry w XNA powinny się komunikować.
Od poprzednich zdarzeń programowania GUI (Java), procedury obsługi i nasłuchiwania wydawały się być rozwiązaniem. Więc miałbym jakąś magistralę zdarzeń, która akceptuje rejestracje zdarzeń i klasy subskrybowane do tych zdarzeń, z programami obsługi zajmującymi się nimi. Na przykład (pseudokod):
class SpriteManager
Update(){
if(player.collidesWith(enemy)
// create new 'PlayerCollisionEvent'
}
class HUDManager
onPlayerCollisionEvent(){
// Update the HUD (reduce lives etc)
}
Jednak nie jestem pewien konfiguracji kodu (w języku C #), który byłby wymagany do pełnego osiągnięcia tego celu. Co śledzi wydarzenia (jakiś autobus?) I jak jest zorganizowane?
Wydaje się również, że wiele mówi się o usługach gier, w których można zarejestrować GameComponent w głównej klasie Game.cs, a następnie pobrać go z dowolnego miejsca w kodzie, który ma odniesienie do głównego obiektu „Game”. Próbowałem tego z moim obiektem SpriteBatch i wydaje się to bardzo łatwe .. nie widzę jednak, aby był on tak elastyczny jak model zdarzeń.
Weźmy na przykład śmierć wroga. Chcemy zaktualizować wynik gry. Korzystając z usług, mogę uzyskać odniesienie do mojego obiektu StateManager utworzonego w Game1 i dodanego jako usługa, a następnie ustawić „score” na nową wartość. Myślałem, że zdarzenie „onEnemyDeath”, które może być obsługiwane w różny sposób przez wiele klas, ale zainicjowane przez 1 linię kodu w odpowiedniej sekcji „wykrywanie śmierci wroga”, byłoby lepsze niż indywidualne rzucanie każdego wymaganego GameComponent, a następnie wywoływanie metody są wymagane.
A może są to gorsze strategie niż coś innego?
Zdaję sobie sprawę, że jest to częściowo moja słaba znajomość języka C #, podobnie jak paradygmaty komunikacji w grach, ale naprawdę chciałbym, aby ta podstawowa rzecz była właściwa.
Aktualizacja
Patrząc na Usługi, jestem bardziej szczegółowy, jestem mniej przekonany - w zasadzie przekazuje zmienną globalną (z tego, co rozumiem).
Aktualizacja 2
Po zapoznaniu się z tym podstawowym samouczkiem na temat obsługi zdarzeń i testowania przykładowego kodu wydaje się, że zdarzenia byłyby logicznym wyborem dla tego, co omawiam. Ale nie mogę tego wiele użyć w próbkach, które widziałem. Czy jest jakiś oczywisty powód, dla którego nie należy?
źródło
Odpowiedzi:
Powodem, dla którego nie znajdziesz wiele na temat magistrali zdarzeń w języku C #, jest to, że moim zdaniem nikt poza Javą nie nazywa czegoś takiego „autobusem”. Częstszymi terminami mogą być kolejka wiadomości, menedżer zdarzeń, sygnały / sloty, publikacja / subskrypcja itp.
Nie potrzebujesz żadnego z nich, aby stworzyć działającą grę, ale jeśli jest to system, z którym czujesz się komfortowo, to również ci dobrze pomoże. Niestety, nikt nie jest w stanie powiedzieć dokładnie, jak to zrobić, ponieważ wszyscy je rzucają inaczej, nawet jeśli w ogóle z nich korzystają. (Na przykład nie.) Możesz zacząć od prostego
System.Collections.Generic.List<Event>
dla kolejki, z różnymi zdarzeniami będącymi podklasami Zdarzenia i listą subskrybentów dla każdego typu zdarzenia. Dla każdego zdarzenia w kolejce pobierz listę subskrybentów, a dla każdego subskrybenta wywołajhandle(this_event)
ją. Następnie usuń go z kolejki. Powtarzać.Prawdopodobnie nie jest tak elastyczny, ale łatwiej go debugować. Zdarzenia i komunikaty są trudne, ponieważ oddzielają funkcję wywołującą od funkcji wywoływanej, co oznacza, że stosy wywołań nie są strasznie pomocne podczas debugowania, akcje pośrednie mogą spowodować zerwanie czegoś, co normalnie działa, a rzeczy mogą zawieść cicho, gdy nie zostaną właściwie podłączone , i tak dalej. Wyraźna metoda „pobierz komponent i wywołaj to, czego potrzebujesz” działa dobrze, jeśli chodzi o wczesne wykrywanie błędów i posiadanie jasnego i wyraźnego kodu. To po prostu prowadzi do ściśle powiązanego kodu i wielu złożonych zależności.
C # jest prawie identycznym językiem jak Java. Cokolwiek zrobiłeś w Javie, możesz zrobić w C #, tylko z inną składnią. Jeśli masz problem z przetłumaczeniem pojęcia, prawdopodobnie dzieje się tak dlatego, że znasz tylko jego nazwę.
źródło
Czy próbowałeś po prostu użyć prostych zdarzeń statycznych? Na przykład, jeśli chcesz, aby twoja klasa wyników wiedziała, kiedy wróg zginął, zrobiłbyś coś takiego:
Score.cs
EnemySpaceship.cs
SpaceshipDeathEventArgs.cs
źródło
Jeśli czujesz się nieswojo z podejściem opartym na wydarzeniach, wypróbuj Artemis C #, jest to system Entity System oparty na http://t-machine.org/index.php/2007/09/03/entity-systems-are -the-future-of-mmog-development-part-1 /
Źródło: https://github.com/thelinuxlich/artemis_CSharp Przykładowa gra: https://github.com/thelinuxlich/starwarrior_CSharp
źródło
spróbuj użyć agregatora zdarzeń takiego jak ten
źródło