Czy ja i jak rozdzielam obawy związane z obiektami wejściowymi i obiektami gry?

20

Prawdopodobnie w każdej grze deweloper musi jakoś poradzić sobie z wprowadzaniem danych, może to być proste zdarzenia z klawiatury i myszy, zdarzenia dotykowe lub coś takiego jak wprowadzanie danych z akcelerometru. Ten wkład bezpośrednio pośrednio wpływa na obiekty w grze. Czasami to samo wejście może wpływać na różne obiekty. Teraz zastanawiałem się, jak to wymodelować. Moim zdaniem istnieją dwa różne podejścia.

  • Pozwól, aby sam obiekt gry sobie z tym poradził, zasubskrybuj zdarzenia i wywołaj własne metody. Ma to tę zaletę, że same obiekty gry decydują, które dane wejściowe powodują, które działanie. Wadą wydaje się być to, że kod wejściowy zostaje zniekształcony przez „podstawowy” kod obiektu gry. Również obiekty gry nie są świadome stanu reszty gry i czasami mogą nie działać na podstawie zdarzeń wejściowych. To nie wydaje się właściwe.

  • Poproś ogólnego kontrolera wejściowego, aby zajął się wszystkimi danymi wejściowymi i podejmował decyzje o tym, kto może obsłużyć dane zdarzenie. Wydaje się, że lepiej oddziela to obawy, ale ściśle łączy klasę kontrolera wejściowego z obiektami gry. W jakiś sposób musi wiedzieć, kto chce otrzymać dane wydarzenie i w jakim stanie. To też nie wydaje się właściwe.

Jakich strategii używasz do tego?

Robert Massa
źródło

Odpowiedzi:

7

Zalecam oddzielenie zdarzeń wejściowych od obiektów gry, abyś mógł szybko zmieniać / aktualizować metody wprowadzania bez konieczności edytowania i debugowania 10 klas obiektów. Przykładami są przejścia z elementów sterujących tylko z klawiatury na mysz + klawiatura lub po prostu zmiana przypisania klawiszy.

Zamiast ściśle łączyć wejście z poszczególnymi obiektami gry, wywołaj tylko jedną metodę na unikalny sygnał wejściowy na obiekcie gry i pozwól mu zdecydować, jak go wykonać.

Użyj kontrolera wejściowego, aby śledzić stan wejściowy:

Up press event   -> dir = up
Down press event -> dir = down

Za każdym razem, gdy zmienia się stan wejściowy, oceń, czy obiekty gry są gotowe do modyfikacji:

set dir  ->  if gamestate != paused && battlemode == false
             ->  character.changeDir(dir);

Zaimplementuj ogólne metody na obiektach gry, które mogą być wywoływane przez kontroler wejściowy lub inne obiekty gry, w zależności od potrzeb:

changeDir (dir)
setSpeed (walk/run)
Edwardian
źródło
7

Polecam podejście MVC. W MVC obiekty gry muszą jedynie martwić się o modelowanie systemu gry i zapewnić interfejs wysokiego poziomu, taki jak move_left. Następnie mieć obiekt kontrolera, który martwi się o mapowanie danych wejściowych na wywołania modelu. Pozwala to nie tylko na łatwą zmianę sterowania, ale także zapewnia dobry interfejs AI, są one po prostu kolejnym kontrolerem.

W drugiej opcji podzieliłbym kontroler wejściowy na dwie części, z których jedna obsługuje rzeczywisty dotyk urządzenia, klawiaturę, przyspieszenie, cokolwiek innego, co możesz na niego rzucić, zmapować je na ogólny zestaw danych wejściowych. Następnie przygotuj drugą część, która mapuje ogólne dane wejściowe na dane właściwe dla gry. Powiedz klawisze w górę mapy strzałek do wejścia 1, a następnie dotknięcie górnej części ekranu dotykowego mapuje również wejście 1, a teraz piszesz drugi kawałek, który mapuje wejście 1, aby przejść. Możesz teraz zmapować dowolne urządzenie IO, jak również zapisane odtwarzanie lub wejścia AI do tego ogólnego systemu wejściowego i mieć małą część specyficzną dla gry, która ładuje to, co wejście 1 oznacza dla modelu.

kamieniste
źródło
5
W innych miejscach tej strony jest wiele dyskusji na temat tego, dlaczego MVC ogólnie nie jest odpowiednim wzorem dla gier; to, co opisuje stonemetal, nie jest nawet MVC, to tylko abstrakcja; a „Użyj MVC” nie jest odpowiedzią, ponieważ MVC jest opisem całej klasy architektur, a nie szczególnym sposobem na rozdzielenie problemów (ani jedynym sposobem na zrobienie tego).
2
MVC powinien mu dać A) artykuł w Wikipedii do przeczytania B) szereg wariantów podejścia do rozwiązania, które okazało się działać C) Wspominam o tym, jak to skonfigurowałem, gdy model udostępnia interfejs wysokiego poziomu, który kontroler mapuje dane wejściowe niskiego poziomu (rzeczywiste lub syntetyczne) na akcję wysokiego poziomu i bezpośrednio manipuluje modelem, a nie jakimś systemem zdarzeń.
stonemetal
1

Sugerowałbym, aby twoja gra ( Model ) zdefiniowała listę możliwych zdarzeń wejściowych (zaimplementowanych jako wyliczenia lub obiekty ze wspólnym interfejsem podstawowym). Rzeczy takie jak MovingRightStarted, MovingRightStopped, FiredWeapon1, Escape, itd ...

Gra definiuje strukturę danych (na przykład a queue), którą Twój kod wejściowy ( kontroler ) może wypełnić zdarzeniami wejściowymi.

Następnie gra może sondować strukturę danych, aby uzyskać zdarzenia wejściowe.

W ten sposób możesz podłączyć różnego rodzaju kontrolery, aby zasilić model:

  • Tylko klawiatura
  • Klawiatura + Mysz
  • Drążek sterowy
  • Ekran dotykowy
  • Sztuczna inteligencja

Wystarczy, że wypchną zdarzenia wejściowe do modelu.

Splo
źródło
Myślę, że rozumiem, co masz na myśli, z wyjątkiem tego, że wybrałeś queuetyp danych do przechowywania tego. Czy możesz wyjaśnić dlaczego?
Robert Massa,
Pomiędzy 2 sondowaniami zdarzeń wejściowych z modelu sterownik mógł przesłać kilka zdarzeń akcji, i ważne jest, aby zachować kolejność wprowadzania danych przez użytkownika. Właśnie dlatego wybrałem strukturę danych FIFO. W rzeczywistości może być konieczne określenie dokładnego czasu, w którym dane wejściowe miały miejsce.
Splo