To pytanie projektowe ... Jestem pewien, że można by to bardziej uogólnić, ale mam z tym trudności. Zastanawiam się nad projektowaniem interakcji między obiektami w grze - oto mój przykład (2D puzzle-platformówka).
Powiedz, że gracz próbuje przejść poziom. Istnieje wiele świateł, które można skierować w różnych kierunkach. Oto przykład interakcji tych lekkich obiektów ...
- Jedno światło rzuca platformę, która pozwala graczowi przekroczyć lukę
- Jedno światło obniża współczynniki tarcia czegokolwiek dotyka, inne zwiększa
- Jedno światło niweluje skutki wszystkich świateł, które powodowałyby, że platforma znikała, gdy światło było włączone, i niwelowało modyfikatory tarcia
- Itp...
Jaki jest najlepszy sposób rozwiązania tego problemu przy użyciu architektury komponentów? Komponenty dla każdego dużego obiektu wydają się oczywiste, a także czysty sposób na zdefiniowanie ich wpływu na środowisko. Klasa „rozwiązująca” interakcję (wygląda na to, że może to szybko popsuć bałagan)? Jakieś użycie wzorca dekoratora do tworzenia połączonych obiektów dla tych, które oddziałują w danym momencie? Struktura danych, która się do tego nadaje?
Czy łączysz audio z tymi interakcjami? Wygląda na to, że podłączenie audio do systemu byłoby jak podłączenie dowolnej innej właściwości, takiej jak widoczność lub ruch / kolizja gracza.
Oczywiście w miarę dodawania kolejnych komponentów byłoby miło, gdyby istniał solidny system, który mógłby obsługiwać nowe z niewielkimi modyfikacjami, ale nie jestem pewien, jak zająć się projektowaniem tego.
Inne informacje: Używam silnika XNA o nazwie IceCream .
źródło
Odpowiedzi:
W systemie zorientowanym obiektowo jedyną prawdziwą odpowiedzią na pytanie, jaki jest najlepszy sposób wykonania X, jest to, że powinieneś to zrobić najprostszym sposobem, w jaki możesz pomyśleć o uruchomieniu czegoś, a następnie zmienić to, gdy łatwiejsza ekspresja staje się oczywista. Zastanawianie się nad wyborem właściwego wzorca przed napisaniem jakiegokolwiek kodu jest dobrym sposobem na osaczenie się z błędną odpowiedzią od samego początku; pozwól, aby wszystkie myśli o wzorach i komponentach stopiły się i po prostu wykonaj następujące kroki, zaczynając od tego, gdzie jesteś dzisiaj (zakładając, że zaimplementowałeś lekki komponent):
W tym momencie będziesz (prawdopodobnie) miał mnóstwo zduplikowanego kodu. Wyodrębnij wspólny kod do funkcji lub innej klasy (może klasy bazowej) lub cokolwiek, co wydaje się odpowiednie. To, że zacząłeś od „lekkiego komponentu”, nie oznacza, że LightComponent jest odpowiednią bazą; może się zdarzyć, że jakikolwiek kod składający się na lekki komponent nie jest tak naprawdę „komponentem” i być może najlepiej będzie to reprezentowane przez zestaw funkcji lub nawet oddzielną klasę, która jest agregowana w nowe komponenty (jako zmienna składowa ).
źródło
Ogólnie rzecz biorąc, gdy obiekt typu A wchodzi w interakcję z obiektem typu B, chcesz mieć pewien efekt C. Nazywa się to „podwójną wysyłką” i bardzo trudno jest go elegancko wykonać w językach podobnych do C.
Skuteczny, ale trudny w utrzymaniu sposób to tylko kilka przełączników i instrukcji if, w zależności od typów obiektów. Będziesz czuł się brudny pisząc to, ale wykona zadanie.
Odwiedzający jest bardziej niezawodne rozwiązanie, które ukrywa paskudny typ przełączania, ale może być clumbersome skonfigurować.
Zwykle każdy rodzaj przełącznika typu w kodzie jest zapachem, ale tutaj próbujesz uogólnić polimorfizm, który normalnie przełącza funkcje oparte na jednym typie, aby przełączać funkcje oparte na dwóch typach. Polimorfizm jest podstawą OOP, więc nie jest zapachem.
źródło
Daj mi zobaczyć. To tylko coś, co ugotowałem sobie w głowie podczas pisania, więc przepraszam, jeśli czegoś brakuje.
Umieść wszystkie lekkie węzły w rozsądnej odległości wokół swojego gościa.
Dla każdego światła renderujesz wielokąt reprezentujący jego obszar działania do obiektu bufora ramki. Zatem stożek światła utworzyłby stożek jednego rodzaju pikseli w twoim FBO. Renderuj wszystkie typy węzłów w odpowiednich priorytetach. Możesz kodować informacje w każdym pikselu, tak jak zielony kanał może być tarciem, czerwony grawitacją, niebieski a alfa czymś innym.
Sprytne techniki mieszania kolorów mogłyby następnie stworzyć ciekawe efekty. Każdy poziom może mieć własne reguły mieszania. Możesz również dodać cieniowanie fragmentów dla psychodelicznych efektów dynamicznych, takich jak pulsująca grawitacja itp.
Na koniec po prostu sprawdź, które piksele dotykają twojej mandude i wykonaj ponowne obliczenie mapy bitowej za każdym razem, gdy zbliżasz się do krawędzi wstępnie obliczonego obszaru.
Szorstki szkic wykonany w 2 minuty ilustrujący mój pomysł:
Edycja: W praktyce oznacza to, że jedyne, czego potrzebujesz, to jeden komponent świetlny emitujący określony kolor. Reguły związane z tym, jaki kolor robi to, co może być gdzie indziej całkowicie. Możesz zakodować wiele danych w 32 bitach, które masz piksel pr. Alternatywnie możesz mieć wiele FBO zawierających różne atrybuty, które nie wpływają na siebie nawzajem. Możesz mieć jeden FBO grawitacyjny / tarcie i 1 FBO jednobitowy. Jeśli to wybierzesz, musisz oczywiście oznaczyć, do którego FBO powinno się renderować twoje światło.
źródło
Wzorzec obserwatora jest jednym z najlepszych rozwiązań. Wiadomość zostanie wysłana tylko do tych obiektów (komponentów), które są nią naprawdę zainteresowane. Więc odbiorca musi subskrybować ten typ wiadomości / zdarzenia.
Istnieje wiele implementacji sygnałów / gniazd. Na przykład w C ++ znajduje się biblioteka sigslot
Aby uzyskać więcej informacji, przeczytaj o sygnałach Qt i gniazdach .
źródło