Jakie jest właściwe podejście obiektowe do projektowania klas w rozwoju gier?

31

Jestem w trakcie opracowywania opartej na XNA gry opartej na sprite'ach 2D dla Windows 7 Phone. Dostępne szkolenia i samouczki są bardzo pomocne, ale napotykam problem, ponieważ każdy z nich podchodzi do projektu swojej klasy inaczej, a kod nie jest szczególnie dobrze przemyślany. W rezultacie trudno mi było dobrze zrozumieć, jakie obowiązki powinienem powierzyć konkretnej klasie.

Na przykład mógłbym mieć podstawową klasę sprite, BaseSpritektóra umie rysować, sprawdzać kolizje itp. Mógłbym mieć AnimatedSpriteklasę, która wiedziałaby, jak poruszać się po jej arkuszu, ExplodingSpriteklasę i tak dalej. Technikę tę zademonstrowano w przykładzie Space Invaders w materiałach Windows 7 Phone Jumpstart Session 2 .

Alternatywnie, mógłbym zamiast tego przypisać większą część renderowania i kierowania odpowiedzialnością za grę w GameScreenklasie; klasa ta i jej pochodne zachowują się bardziej jak formularze lub strony internetowe pod względem odpowiedzialności. Klasy sprite są prostszymi kontenerami o znacznie mniejszej logice.

Jest to technika stosowana w grze Alien Sprite w zestawie Windows 7 Phone Training Kit i innych przykładach menedżera stanu gry.

Jakie jest właściwe podejście obiektowe do projektowania klas w rozwoju gier?

Josh E.
źródło

Odpowiedzi:

26

Używam podejścia bardziej zorientowanego na komponenty, w którym miałbyś klasę Sprite, która ma komponenty takie jak Visual, Collision, Animation, Input, itp. Dzięki takiemu podejściu nie mam głębokiej hierarchii klas (co jest dobre) .

Więcej informacji na temat projektowania zorientowanego na komponenty można znaleźć tutaj .

thbusch
źródło
2
+1 artykuł, do którego linkujesz, był fantastyczny. Byłem tak skupiony na czystym projektowaniu OO, że całkowicie przeoczyłem model typu komponent / dekorator.
Josh E
1
Wzór komponentu nie jest tak naprawdę „mniej czysty” OO :)
Srekel
2
W rzeczy samej. OO jest często utożsamiane z dziedziczeniem. Ale dziedziczenie to tylko jedno narzędzie, które oferuje OO, skład to drugie.
haffax
Tak więc. Powinienem był bardziej precyzyjnie sformułować; chodziło mi o to, że skupiłem się w dużej mierze na dziedziczeniu po stronie OO, zamiast myśleć o wzorcach projektowych OO / innych aspektach OO, które mogłyby pomóc mi osiągnąć to, czego chciałem.
Josh E
Chociaż podejście oparte na zestawieniu jest dość oczywiste i często stosowane, nie znalazłem jeszcze rozwiązania, które pozwoliłoby zachować przenośny komponent renderujący. Wszelkie wskazówki byłyby świetne.
Andreas
11

W grach wzór komponentu jest powszechnym rozwiązaniem.

hojny
źródło
to kolejny fantastyczny artykuł - wart przeczytania.
Josh E
1
Świetny, świetny, świetny artykuł!
Kevin
6

W STAŁE Zasady stosuje się znacznie do projektowania kodu gra jak do każdego innego zawodu - przynajmniej dopóki nie przyjdzie, aby zoptymalizować, więc użyję pierwszy przykład jako punkt wyjściowy.

Chciałbym pójść dalej, ponieważ BaseSprite brzmi, jakby miał tendencję do stania się megaklasą. Zasada pojedynczej odpowiedzialności określa, że ​​kolizja, renderowanie i nawigacja powinny być obsługiwane przez komponenty, a nie poszczególne wpisy w hierarchii klas. Klasa trzymania wszystkich tych elementów powinna obsłużyć tylko pchające pozycje świata między nimi.

tenpn
źródło
5

W ostatnich kilku projektach bardziej skupiłem się na podejściu w stylu MVC.

Na początku nie byliśmy pewni, czy to zadziała, ale działało idealnie.

Model

Obiekty danych. Tylko czyste dane. Bez zachowania, bez renderowania.

Menedżer danych. Po prostu obsługa „list” obiektów danych. (Można również ulepszyć w celu obsługi łączenia).

Widok

Nazywamy ich rendererami. Dla każdego typu obiektu danych istnieje moduł renderujący. Po wywołaniu z menedżerem wyświetli wszystkie obiekty z tej listy.

Kontroler

Taki sam jak renderery, ale kontroluje zachowanie.

Przykład

Menedżer statków ma listę statków. ShipController poruszy statki zgodnie z ich stanem. ShipRenderer renderuje statki zgodnie z ich stanem.

Czemu

W ten sposób widok i logika są ściśle oddzielone. Dzięki temu przenoszenie na nową platformę jest bardzo łatwe. Optymalizacja układu danych w XxxManager jest również bardzo łatwa.

Andreas
źródło
2
Głosuję za tobą, bo mam dość oglądania mniej więcej nagiego „Użyj MVC” jako akceptowalnej odpowiedzi. Jeśli rozwijasz się na dowolnej nowoczesnej platformie, już używasz MVC na wielu poziomach. To nie jest konkretna odpowiedź i nie jest dobra odpowiedź, ponieważ tak naprawdę nie mówi ludziom, jak ustrukturyzować klasy, która jest specyficzna dla zadania / domeny. Skończyło się na tym, że wiele osób pisze „class Modal ...; class View ...; class Controller…” MVC jest wzorcem z dużą ilością dobrej mocy wyjaśniającej wysokiego poziomu, kiedy mówi się o istniejącym kodzie. To nie jest wzór o dużej sile planowania.
4
@ Joe Rozumiem, o co chodzi, ale uważam, że wybór słów jest niepotrzebny, niegrzeczny. Właśnie wyjaśniłem, jak to robimy. Ponieważ wybór architektury wyższego poziomu powoduje, że wybór projektu niższego poziomu jest przestarzały, uważam to za prawidłową odpowiedź.
Andreas