Jakie są wzorce programowania, które są przydatne w tworzeniu gier? [Zamknięte]


129

Mam kilka książek na temat Wzorów projektowych i przeczytałem kilka artykułów, ale nie mogę intuicyjnie ustalić, które wzorce projektowe programowania byłyby przydatne w tworzeniu gier.

Na przykład mam książkę o nazwie ActionScript 3 z wzorami projektowymi, która szczegółowo opisuje kilka wzorców projektowych, takich jak Model View Controller, Singleton, Factory, Command itp.

Jako ktoś nowy w tym, nie mogę dowiedzieć się, który z nich byłby przydatny, a właściwie, jeśli którykolwiek z nich to wzorce projektowe, których powinienem się uczyć i próbować używać. Być może istnieją inne wzorce projektowe specyficzne dla programowania gier, o których nawet nie wiem?

Jeśli masz doświadczenie w stosowaniu określonego wzorca projektowego podczas tworzenia gry, chciałbym go usłyszeć. Rozumowanie, dlaczego zostało użyte, próbki kodu lub zasoby online, byłoby bardzo pomocne, jeśli je masz. W tej chwili najbardziej interesują mnie implementacje ActionScript 3 i C ++, ale zdecydowanie mogę skorzystać z doświadczenia i przykładów z dowolnego języka.

Dzięki!


„Być może istnieją inne, bardziej specyficzne dla programowania gier wzorce projektowe, których nawet nie jestem świadomy?” - nie, te wzorce są ogólne i dotyczą bardziej rozszerzania możliwości używanego języka. Nie mają one nic wspólnego z przedmiotem wniosku.
Kylotan

3
@Kylotan Z mojego ograniczonego punktu widzenia wydaje się, że ponieważ każdy wzór projektowy ma na celu skuteczne rozwiązanie określonego problemu, z natury niektóre wzorce projektowe byłyby bardziej przydatne niż inne, biorąc pod uwagę konkretny zestaw problemów, mianowicie w tym przypadku, te zestawy problemów są unikalne dla rozwoju gier. Z pewnością istnieją jakieś wytyczne lub oparte na twoim doświadczeniu, konkretne wzorce projektowe, których używasz częściej niż inne?
jcurrie33

Zanim ktokolwiek odejdzie i nauczy się 1000 różnych wzorów, przeczytaj to i to
BlueRaja - Danny Pflughoeft

@ BlueRaja-DannyPflughoeft Secon link jest nieprawidłowy. Czy możesz to wysłać ponownie
Emadpres

Odpowiedzi:


163

Czas na mniej niepotrzebną odpowiedź z kilkoma sugestiami. Nie należy traktować ich jako zaleceń wdrożeniowych, a bardziej przykładów możliwych zastosowań.

  • Konstruktor: konfiguruj encję opartą na komponentach pojedynczo, na podstawie danych
  • Metoda fabryczna: utwórz NPC lub widżety GUI na podstawie ciągu odczytanego z pliku
  • Prototyp: przechowuj jedną ogólną postać „Elfa” z początkowymi właściwościami i twórz instancje Elfa poprzez klonowanie.
  • Singleton: to miejsce celowo pozostawiono puste.
  • Adapter: dołącz opcjonalną bibliotekę innej firmy, zawijając ją w warstwę, która wygląda jak istniejący kod. Bardzo przydatne z bibliotekami DLL.
  • Złożony: utwórz wykres sceny obiektów do renderowania lub utwórz GUI z drzewa widżetów
  • Fasada: uprość skomplikowane biblioteki stron trzecich, zapewniając prostszy interfejs, aby ułatwić Ci późniejsze życie.
  • Flyweight: przechowuj wspólne aspekty NPC (np. Modele, tekstury, animacje) oddzielnie od poszczególnych aspektów (np. Pozycja, zdrowie) w przeważnie przejrzysty sposób
  • Proxy: Twórz małe klasy na kliencie, które reprezentują większe, bardziej złożone klasy na serwerze i przesyłaj żądania przez sieć.
  • Łańcuch odpowiedzialności: przetwarzaj dane wejściowe jako łańcuch handlowców, np. klawisze globalne (np. zrzuty ekranu), następnie GUI (np. w przypadku zaznaczenia pola tekstowego lub menu), a następnie gra (np. do poruszania postacią)
  • Polecenie: zawiera funkcjonalność gry jako polecenia, które można wpisywać do konsoli, przechowywać i odtwarzać, a nawet pisać w skryptach, aby pomóc w testowaniu gry
  • Mediator: zaimplementuj elementy gry jako małą klasę mediatora, która działa na różnych komponentach (np. Odczytuje z komponentu zdrowia w celu przekazania danych do komponentu AI)
  • Obserwator: niech renderowalna reprezentacja postaci nasłuchuje zdarzeń z reprezentacji logicznej, aby w razie potrzeby zmienić prezentację wizualną bez potrzeby, aby logika gry wiedziała o renderowaniu kodu
  • Stan: przechowuj AI NPC jako jeden z kilku stanów, np. Atak, Wędrówka, Ucieczka. Każda może mieć własną metodę update () i dowolne inne dane, których potrzebuje (np. Przechowywanie postaci, z której atakuje lub ucieka, obszaru, w którym wędruje itp.)
  • Strategia: przełączaj się między różnymi heurystykami dla wyszukiwania A *, w zależności od rodzaju terenu, a może nawet skorzystaj z tej samej struktury A *, aby zarówno znaleźć ścieżkę, jak i bardziej ogólne planowanie
  • Metoda szablonu: skonfiguruj ogólną procedurę „walki” z różnymi funkcjami haka do obsługi każdego kroku, np. zmniejsz amunicję, oblicz szansę na trafienie, rozstrzygnij trafienie lub chybić, oblicz obrażenia, a każdy rodzaj umiejętności ataku zastosuje metody na swój własny sposób

Niektóre wzory pominięto z powodu braku inspiracji.


Bardzo pouczającą dyskusję na temat singletonów można znaleźć tutaj: misko.hevery.com/2008/08/25/root-cause-of-singletons
Andrew Wang

+1 za wzorzec strategii. Użyłem go do dokładnie określonego celu (podłączenie różnych heurystyk A *).
Mike Strobel,

1
dzięki za odpowiedź, te brzmią bardziej jak
wzorowy

Świetna lista przykładów. Pomimo chronicznego nadużywania wzorca singletonu (ukryty stan globalny) istnieją uzasadnione zastosowania: gdy reprezentuje zasób, którego faktycznie masz (lub chcesz) tylko. Może to być coś takiego jak sprzęt do owijania (np. Klawiatura / mysz) lub owijanie biblioteki, która nie jest ponownie wysyłana (zdarza się, i nie wszystkie języki mają magiczne słowa kluczowe synchronizacji).
charstar

11
Nadal nie używałbym singletonów do zasobów sprzętowych - przedmioty, które według ciebie będziesz miał tylko 1, zwykle się mnożą później, podobnie jak karty graficzne i monitory robione z biegiem lat. Podobnie, pod niektórymi interfejsami API musisz przeczytać 2 joysticki, aby zrozumieć 1 gamepad. Powiedziałbym więc, że jeśli potrzebujesz tylko czegoś, po prostu zrób instancję jednego, nie egzekwuj arbitralnych ograniczeń, które prawdopodobnie nie są konieczne.
Kylotan

59

Napisałem książkę na dokładnie ten temat: Wzorce programowania gier . Rozdziały, które tam są, mogą być dla ciebie pomocne.


2
+1 Miałem nadzieję, że ktoś się z tym powiązał i widzę, że autor to zrobił! Opis wzoru komponentu był bardzo pomocny i podoba mi się, że próbujesz użyć pełnych przykładów kodu, aby to zademonstrować.
CodexArcanum

2
Tak - pamiętam czytanie twojego linka kilka lat temu. Powinieneś skończyć te artykuły!
onedayitwillmake

2
Teraz książka jest skończona :)
dusan

1
Niesamowity zasób, który pomógł mi przełożyć moją wiedzę programistyczną na programowanie gier. Dzięki za napisanie tego!

To objaśnienie wzorców programowania gier pomogło mi zrozumieć - wzorce projektowe - w sposób, którego tak naprawdę nie zrobiła żadna wzorzec projektowania oprogramowania! Jest to po części moc tworzenia gier (konkretne przykłady w języku, który do mnie przemawia i pozwala mi ogólnie poprawić swój rozwój), ale w większej części, ponieważ pisanie jest tak doskonałe.
Kzqai,

19

Jedną rzeczą, którą Brandon Eich miał dobry sens, by poruszyć w Coders at Work, jest to, że wzorce to hacki i obejścia: [Wzory] pokazują pewien defekt w języku. Te wzory nie są darmowe. Nie ma darmowego lunchu. Powinniśmy więc szukać ewolucji w języku, który dodaje odpowiednie elementy.

Jako programiści gier, a nie projektanci kompilatorów, rzadko mamy możliwość ewolucji używanych przez nas języków, ale możemy nauczyć się ewoluować w naszym własnym stylu, aby lepiej dopasować nasz język i wymagania. Wzory są tego częścią, ale nieużywanie wzorców to kolejna część, zwłaszcza że, jak mówi Brandon, wzorce rzadko przebiegają bez zauważalnej wydajności, kosztów pamięci lub sprawności kodu. MVC po prostu nie jest świetnym wzorem dla wielu rzeczy w grach. Singleton jest obejściem dla słabych reguł inicjalizacji statycznej C ++ i prawdopodobnie nie powinieneś ich robić. Fabryka upraszcza tworzenie skomplikowanych obiektów - być może Twoje obiekty powinny być po prostu prostsze. Popularne wzory to narzędzia, do których można się odwoływać, kiedy ich potrzebujemy zarządzać czymś złożonym, a nie narzędziami, których powinniśmy chcieć użyć do zbudowania czegoś złożonego na początku.

Dobry kod (gry) może używać wzorców lub nie. Jeśli używa wzorców, w porządku - są doskonałym narzędziem komunikacyjnym do wyjaśniania struktury kodu innym programistom na wysokim, niezależnym od języka poziomie. Jeśli uważasz, że kod jest lepszy bez użycia wzorca, nie pobijaj się - prawdopodobnie tak jest.


4
Tak, jedną z rzeczy wyjaśnionych w oryginalnej książce (ale często pomijanych) jest to, że gdyby zostały napisane dla C zamiast C ++ / Smalltalk, mogłyby one zawierać wzorzec „Dziedziczenia”, a tym samym niektóre języki może zawierać niektóre z wbudowanych wzorów GoF.
Kylotan

13
Inną często pomijaną w oryginalnej książce (oryginalna oryginalna książka Aleksandra, nie GoF) było to, że wzorce są narzędziem komunikacji , a nie implementacji . Pozwalają projektantom komunikować się o wdrożeniu na wyższym poziomie i są identyfikowani, ponieważ się powtarzają, niekoniecznie dlatego, że należy ich używać, gdy to możliwe.

1
Jednak sama terminologia może pomóc w zrozumieniu problemu i rozpoznaniu, kiedy takie podejście jest dobrym rozwiązaniem. Najlepsze wzorce były z czasem udoskonalane przez wykwalifikowanych i doświadczonych pracowników, a mniej wykwalifikowani pracownicy nie odkryliby samych tych samych wzorów bez tych skodyfikowanych przykładów.
Kylotan

Zgadzam się, że terminologia jest świetna, a częścią definicji wzorca jest to, że jest to dobre, powtarzające się rozwiązanie jakiegoś problemu. Niestety, mniej wykwalifikowani pracownicy zwykle znajdują Singletona i stosują go do każdego problemu, nawet jeśli nie ma jeszcze problemu.

Dziękuję za tę odpowiedź; Czuję ulgę, gdy czytam, że wzorzec projektowy został opracowany w celu rozwiązania problemów związanych z projektem oprogramowania. Myślę, że struktura całego dużego oprogramowania powinna być przemyślana od początku do końca, zanim zacznie coś kodować. Nie zawsze możesz wdrożyć funkcjonalności raz na jakiś czas, czasem musisz pomyśleć o każdej konkretnej funkcji i sprawdzić, czy nie zadziała ona z globalną strukturą oprogramowania lub po prostu przeszkodzi w tym, w jaki sposób oprogramowanie ma zachowywać się. Dzielenie zadań między kilku programistów może czasem tworzyć sprzeczności ...
Jokoon

7

Oczywiście, jak powiedzieli inni, wszystkie wzorce są przydatne w odpowiednich okolicznościach, a częścią uczenia się, jak z nich korzystać, jest nauka, kiedy z nich korzystać. Jednak znakomita książka „ Podstawowe techniki i algorytmy w programowaniu gier” Daniela Sancheza-Crespo Dalmaua wymienia sześć wzorców programowania i sześć wzorców użyteczności jako szczególnie przydatne w programowaniu gier.

Programowanie:

  • Singleton: Nie nienawidzę tego, jak wielu ludzi; może być używany do takich rzeczy, jak odtwarzacz jednoosobowy lub czytnik klawiatury.
  • Fabryka: Umożliwia wydajne tworzenie i niszczenie obiektów.
  • Strategia: Pozwala elegancko zmieniać strategie AI.
  • Indeks przestrzenny: Pomaga wykonywać zapytania dotyczące zbiorów danych przestrzennych.
  • Złożony: Konfiguruje przydatną heirarchię obiektów.
  • Flyweight: Uwalnia pamięć, generując rzeczy takie jak identyczni wrogowie.

Użyteczność:

  • Tarcza: Chroni przed przypadkową aktywacją dramatycznych działań.
  • Stan: Wizualne sygnały statusu świata / interfejsu użytkownika.
  • Automatyczne anulowanie trybu: Sprawia, że ​​gra działa bardziej intuicyjnie.
  • Magnetyzm: Autoimiming i łatwy wybór jednostek.
  • Focus: Eliminowanie rozpraszających elementów interfejsu użytkownika.
  • Postęp: Uniwersalnie przydatny.

Książka zawiera bardziej szczegółowe informacje na temat każdego z nich.


Dzięki za wkład! Nie wiedziałem o tej książce, ale przyjrzę się jej teraz w wyniku twojego postu. Dzięki jeszcze raz!
jcurrie33

2
Singleton dla czytnika klawiatury jest dokładnie taką sytuacją, w której muszę zapytać - czy naprawdę nie możesz tak ustawić globalnego wskaźnika na początku swojej głównej funkcji? Czy kiedykolwiek przypadkowo utworzyłeś instancję dwóch czytników klawiatury?

Proszę, nienawidzę singletona. Źle robi dwie rzeczy. Globalny dostęp i dobro. Często programiści myślą, że globalny dostęp == singleton. Jest bardzo niewiele problemów, niż potrzeba prawdziwego singletonu, i być może kilka innych, które są bardziej eleganckie po rozwiązaniu z singletonem.
deft_code

7

Systemy jednostek są ładnym rodzajem wzoru. To nie jest dokładnie wzór, ponieważ nie jest ostry OOP. Można go jednak łączyć z OOP.

Kilka dobrych linków (zacznij od góry dla wprowadzenia):


3
„To nie jest dokładnie wzór, ponieważ nie jest ostro [sic] OOP.” Wzory projektowe nie mają nic wspólnego z OOP; jeśli już, sam OOP jest wzorem projektowym. Wzorce projektowe pojawiają się nie tylko poza OOP, ale całkowicie poza rozwojem oprogramowania.

Są takie, OOP design patternsktóre zazwyczaj pokazują relacje i interakcje między klasami / obiektami. Istnieje wiele innych wzorów. OOP to zestaw pojęć, a nie wzór. Design patternto także koncepcja.
topright

6
Czy zamiast mówić o semantyce, nie powinieneś oceniać przydatności udzielonej odpowiedzi?
Wernight

6

Wszyscy. Z wyjątkiem Singleton. [/nonszalancja]


Czy mógłbyś wymienić jeden lub dwa wzorce projektowe, których często używałeś podczas tworzenia gry i z jakiego powodu? Jako „początkujący” w zakresie wzorców projektowych „wszystkie z nich” nie są szczególnie pomocną odpowiedzią. Ale dziękuję za odpowiedź.
jcurrie33

5
Pytanie „jakich wzorów użyłeś?” jest jak pytanie „jakich nazw zmiennych użyłeś?” Wszystko sprowadza się do osobistego stylu, wymagań i domeny. W pewnym momencie prawdopodobnie użyjesz dowolnego wzorca, który kiedykolwiek został nazwany. Prawdopodobnie użyjesz wielu, które nie zostały nazwane, a może nawet wymyślisz kilka nowych.

@ jcurrie33: przepraszam, po prostu nie mogłem się powstrzymać przed kopaniem singletonów. ;)
Kylotan

6

Nie tak naprawdę o wzorach, ale o podstawowych zasadach, które się za nimi kryją. W „Design Patterns: Elements of Reusable Object-Oriented Software” (1995) , grupa czterech (Gamma, Erich; Richard Helm, Ralph Johnson i John Vlissides) zaleca tylko dwie zasady projektowania obiektowego: (1) program do interfejs, a nie implementacja i (2) faworyzuj kompozycję obiektów nad dziedziczeniem klas.

Te dwie zasady są bardzo pomocne w wielu zadaniach związanych z tworzeniem gier. Na przykład wielu programistów gier używa głębokiej hierarchii klas do reprezentowania bytów gry. Istnieje inne podejście oparte na kompozycji - obiekty gry oparte na komponentach. Artykuł o tym podejściu. Jeszcze więcej linków . Jest to przykładowy wzór dekoratora .


Komponenty używane w projektowaniu gier przypominają bardziej stanowy wzorzec strategii - co naturalnie wyraża się jako zamknięcia poza C / C ++ / Java / C # oraz jako obiekty komponentów w nich zawarte. Wzór dekoratora bardziej przypomina proxy; jego własność i przepływ danych są przeciwne do tych, które zwykle mamy na myśli, gdy mówimy o systemach składowych w grach.

Komponenty również muszą ze sobą rozmawiać, wprowadzając wzorce, takie jak Mediator, Obserwator i Kompozytor. „Gra oparta na komponentach” sama w sobie jest złożonym wzorcem projektowym.
CodexArcanum

@CodexArcanum, Observer, zdecydowanie, ale nie zawsze Mediator (zamiast tego można zastosować Łańcuch Odpowiedzialności). Jest to Composer tylko wtedy, gdy GameObject (złożony z GameObjectComponent) jest samym GameObjectComponent (niepotrzebny).
topright

6

Ciekawie powtarzający się wzór szablonu mogą być bardzo przydatne dla uniknięcia metod wirtualnych i spadku wydajności, które mogą pochodzić z wywołania funkcji wirtualnych.

Może to być odpowiedni wzorzec, gdy tak naprawdę nie potrzebujesz kontenera klasy podstawowej, który ma interfejs, którego szukasz, ale chcesz mieć podobnie nazwane zachowania i interfejsy.

Na przykład możesz tego użyć podczas kompilacji klas dla wielu platform lub silników (dx vs. opengl), gdzie wariancja typu jest znana w czasie kompilacji.


Zawsze nienawidziłem, że warstwa abstrakcji systemu operacyjnego była wirtualna. Nie jest tak, że kiedykolwiek będziesz potrzebować dwóch warstw abrazyjnych. Znacznie lepiej używać CRTP.
deft_code

Może jestem po prostu stary, ale nie użyłbym nawet CRTP dla DX / OpenGL lub interfejsów platformy. Kompilacja jest zbyt wolna - używałbym po prostu typedefs. CRTP jest dobry, gdy chcesz współdzielić interfejsy i implementacje między klasami, ale nie ma innych relacji, nie kiedy chcesz tylko wybrać jedną strukturę lub inną.

4

Wzorzec projektowy, który ewoluowałem przez wiele lat i który był dla mnie spektakularnie przydatny, jest czymś, co nazywam „zestawem definicji brokera”; jak podsumować to w kategoriach GOF wydaje się być kontrowersyjna, ale to pytanie, które napisałem o tym na StackOverflow, zawiera pewne szczegóły na ten temat.

Podstawową koncepcją jest to, że niektóre właściwości modelu, takie jak gatunek stworzenia, są ustawione tak, aby każda możliwa wartość właściwości miała odpowiadający jej obiekt definicji - pojedynczy, wspólny obiekt na wartość - który określa jego zachowanie, i są one dostępne za pośrednictwem centralnego brokera (który, pod względem GOF, może być rejestrem, fabryką lub jednym i drugim). W moim zastosowaniu są one również ogólnie dostępne za pomocą kluczy skalarnych, aby ułatwić słabe wiązanie do celów morfizmu środowiska wykonawczego.


W ogóle nie rozumiem, jak to jest singleton, a przy omawianiu wzorca masy ciała słowo „rejestr” jest zbędne. To tylko waga muchowa.

Rozumiem z wątku SO, że ludzie zidentyfikowali Singletona jako część tego, ponieważ definicje są ustawione jako klasy. Jeśli chodzi o rejestr, nie widzę, jak może być zbędny, gdy można go wymienić lub połączyć z Factory.
chaos

-1, w zakresie, w jakim wzorce dotyczą szybkiej komunikacji, jest to prawdopodobnie największa awaria, jaką widziałem. Naprawdę nie mogę poważnie traktować tego opisu.

Jezu, wybacz mi, że nie jestem dla ciebie wystarczająco foremką do ciastek. Czy zamierzasz również głosować nad odpowiedzią „Systemy jednostek”, ponieważ nie można jej od razu streścić w kategoriach GOF?
chaos

1
Pewna ilość „foremek do ciastek” lub przynajmniej semantycznej przejrzystości jest dokładnie tym, jakie wzory muszą być użyteczne. Terminy takie jak „waga muchowa” i „singleton”, jak są powszechnie rozumiane, wzajemnie się wykluczają. Pierwszy dotyczy automatycznego udostępniania danych między wieloma instancjami; drugi dotyczy dokładnie jednego wystąpienia. Nie twierdzę, że twój wybór projektu jest bezużyteczny, a nawet zły, ale łączenie razem nazw wzorów „wystarczająco blisko” po prostu jeszcze bardziej dezorientuje wszystkich. (Proszę nie brać osobiście głosów negatywnych, zwłaszcza w CW.)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.