Architektura Gry

Mam pytanie dotyczące gry XNA, którą robię, ale jest to również ogólne Pytanie dotyczące przyszłych gier. Robię grę Pong i nie wiem dokładnie, co zaktualizować, gdzie, więc wyjaśnię lepiej, co mam na myśli. Mam grę klasową, wiosło i piłkę i np. chcę zweryfikować kolizje między piłką z limitem ekranu lub wiosłami, ale natknąłem się na 2 podejścia, aby to zrobić:

Podejście wyższego poziomu - upublicznienie właściwości wiosła i piłki oraz na Gra.Aktualizacja sprawdzania kolizji?

Podejście niższego poziomu - dostarczam wszystkie potrzebne informacje (limity ekranu i informacje o wiosłach) do klasy piłki (według parametru lub we wspólnej publicznej klasie statycznej) i na piłce.Aktualizacja sprawdzam kolizje?

Moje pytanie w bardziej ogólny sposób brzmi:

Czy obiekt musi wiedzieć, jak się aktualizować i rysować, nawet mając zależności z wyższych poziomów, które w jakiś sposób są dostarczane do oni?

Lub

Jest lepiej przetwarzać go na wyższych poziomach w grze.Aktualizacja lub gra.Rysowanie czy używanie menedżerów do upraszczania kodu?

Myślę, że jest to pytanie modelu logiki gry, które odnosi się do każdej gry. Nie wiem, czy wyraziłem swoje pytanie jasno, jeśli nie, możesz zapytać.

Author: davidsbro, 2011-03-28

4 answers

Trudną częścią odpowiedzi na twoje pytanie jest to, że pytasz zarówno: "co powinienem zrobić teraz, dla ponga" i "co powinienem zrobić później, w jakiejś ogólnej grze".


Aby zrobić Ponga, nie potrzebujesz nawet klasy piłki i wiosła, ponieważ są one w zasadzie tylko pozycjami. Po prostu wsadź coś takiego do swojej klasy Gry:

Vector2 ballPosition, ballVelocity;
float leftPaddlePosition, rightPaddlePosition;

Następnie po prostu zaktualizuj i narysuj je w dowolnej kolejności w funkcjach Update i Draw W grze. Spokojnie!


But, say you chcesz utworzyć wiele kulek, a kulki mają wiele właściwości (położenie, prędkość, obrót, kolor itp.): możesz chcieć utworzyć klasę lub strukturę Ball, którą możesz instancjonować (to samo dotyczy łopatek). Można nawet przenieść niektóre funkcje do tej klasy, gdzie są one samodzielne (Funkcja Draw jest dobrym przykładem).

Zachowaj jednak koncepcję projektu - cała obsługa interakcji obiekt-obiekt (czyli rozgrywka) odbywa się w twojej klasie Game.

To wszystko dobrze, jeśli masz dwa lub trzy różne elementy rozgrywki (lub klasy).


Postulujmy jednak bardziej skomplikowaną grę. Weźmy podstawową grę pong, dodać kilka elementów pinball jak mutli-ball I gracz sterowane płetwy. Dodajmy kilka elementów z węża, powiedzmy, że mamy kontrolowanego przez AI "węża", a także niektóre przedmioty pickupa, które kulki lub wąż może trafić. I na dobrą miarę powiedzmy, że łopatki mogą również strzelać laserami jak w Space Invaders i śruby laserowe robią różne rzeczy w zależności od tego, w co uderzają.

rany, to jest ogromny bałagan w interakcji! Jak sobie z tym poradzimy? Nie możemy umieścić tego wszystkiego w grze!

Proste! Tworzymy interfejs (lub abstrakcyjną klasę lub wirtualną klasę), z którego wywodzić się będzie każda "rzecz" (lub "aktor") w naszym świecie gry. Oto przykład:

interface IActor
{
    void LoadContent(ContentManager content);
    void UnloadContent();

    void Think(float seconds);
    void UpdatePhysics(float seconds);

    void Draw(SpriteBatch spriteBatch);

    void Touched(IActor by);

    Vector2 Position { get; }
    Rectangle BoundingBox { get; }
}

(to tylko przykład. Nie ma " jednego prawdziwego interfejsu aktora", który będzie działał w każdej grze, będziesz trzeba zaprojektować własne. Dlatego nie lubię DrawableGameComponent.)

Posiadanie wspólnego interfejsu pozwala graczowi po prostu rozmawiać o aktorach - zamiast wiedzieć o każdym typie gry. Pozostaje tylko robić rzeczy wspólne dla każdego typu-wykrywanie kolizji , rysowanie, aktualizowanie, ładowanie, rozładowywanie itp.

Gdy już będziesz w aktorem, możesz zacząć martwić się o konkretne typy aktorów. Na przykład, może to być metoda w Paddle:

void Touched(IActor by)
{
    if(by is Ball)
         ((Ball)by).BounceOff(this.BoundingBox);
    if(by is Snake)
         ((Snake)by).Kill();
}

Teraz, Lubię, aby piłka odbiła się od wiosła, ale to naprawdę kwestia gustu. Możesz to zrobić na odwrót.

W końcu powinieneś być w stanie trzymać wszystkich aktorów na dużej liście, którą możesz po prostu powtórzyć w grze.

W praktyce możesz mieć wiele list aktorów różnych typów ze względu na wydajność lub prostotę kodu. To jest ok - ale ogólnie staraj się trzymać zasady gry tylko wiedząc o generic aktorzy.

Aktorzy mogą również chcieć zapytać, co inni aktorzy istnieją z różnych powodów. Daj więc każdemu aktorowi odniesienie do gry i upublicznij listę aktorów w grze (nie musisz być bardzo surowy w kwestii publicznego/prywatnego, gdy piszesz kod rozgrywki i jest to twój własny kod wewnętrzny.)


Teraz możesz nawet pójść o krok dalej i mieć wiele interfejsów. Na przykład: jeden do renderowania, jeden do tworzenia skryptów i sztucznej inteligencji, jeden do fizyki itp. Następnie mają wiele implementacje, które mogą być złożone w obiekty.

Jest to opisane szczegółowo w w tym artykule . A ja mam prosty przykład w tej odpowiedzi. Jest to odpowiedni kolejny krok, jeśli zaczniesz odkrywać, że twój interfejs pojedynczego aktora zaczyna przekształcać się w bardziej "drzewo" abstrakcyjnych klas.

 45
Author: Andrew Russell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:29:38

Możesz również zdecydować się na rozpoczęcie myślenia o tym, jak różne elementy gry muszą ze sobą rozmawiać.

Piłka i wiosło, oba są obiektami w grze, a w tym przypadku, Renderowalnymi, ruchomymi przedmiotami. Wiosło ma następujące kryteria

Może poruszać się tylko w górę i w dół]}
    [[10]}wiosło jest przymocowane do jednej strony ekranu lub do dołu [[10]}wiosło może być kontrolowane przez użytkownika (1 vs komputer lub 1 vs 1)
  1. wiosło może być rendered
  2. Wiosło może być przesunięte tylko na dół lub górę ekranu, nie może przekroczyć swoich granic]}

Piłka ma następujące kryteria

Nie może opuścić granic ekranu

  1. może być renderowany
  2. W zależności od tego, gdzie zostanie uderzony w wiosło, możesz sterować nim pośrednio (prosta fizyka)
  3. jeśli pójdzie za wiosłem, runda jest skończona
  4. po rozpoczęciu gry piłka jest zazwyczaj przymocowany do wiosła osoby, która przegrała.

Identyfikacja wspólnych kryteriów można wyodrębnić interfejs

public interface IRenderableGameObject
{
   Vector3 Position { get; set; }
   Color Color { get; set; }
   float Speed { get; set; }
   float Angle { get; set; }
}

Masz też trochę GamePhysics

public interface IPhysics
{
    bool HasHitBoundaries(Window window, Ball ball);
    bool HasHit(Paddle paddle, Ball ball);
    float CalculateNewAngle(Paddle paddleThatWasHit, Ball ball);
}

Potem jest jakaś logika gry

public interface IGameLogic
{
   bool HasLostRound(...);
   bool HasLostGame(...);
}

To nie jest cała logika, ale powinno dać ci wyobrażenie o tym, czego szukać, ponieważ budujesz zestaw bibliotek i funkcji, których możesz użyć, aby określić, co się wydarzy i co może się wydarzyć i jak musisz działać, gdy te rzeczy się zdarzają.

Ponadto, patrząc na to, można to udoskonalić i refaktorować, aby był to lepszy projekt.

Poznaj swoją domenę i zapisz swoje pomysły. Niepowodzenie w planowaniu oznacza niepowodzenie
 2
Author: Pieter Germishuys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-28 14:19:52

Możesz zobaczyć swoją piłkę i wiosło jako element Twojej gry, a XNA daje Ci klasę bazową GameComponent to ma Update(GameTime gameTime) metoda, którą możesz nadpisać, aby wykonać logikę. Dodatkowo istnieje również DrawableGameComponent klasy, która ma swój własny Draw metoda obejścia. Każda GameComponent klasa ma również Game właściwość, która przechowuje obiekt gry, który je stworzył. Tam możesz dodać niektóre usługi, które twój komponent może wykorzystać do uzyskania informacji przez siebie.

To, jakie podejście chcesz zrobić, albo mieć obiekt "master", który obsługuje każdą interakcję, albo dostarczać informacje komponentom i sprawić, by same zareagowały, zależy wyłącznie od Ciebie. Ta ostatnia metoda jest preferowana w większym projekcie. Ponadto, byłby to obiektowy sposób obsługi rzeczy, aby dać każdej jednostce własne metody aktualizacji i rysowania.

 1
Author: Lanbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-28 12:21:35

Zgadzam się z tym, co powiedział Andrew. Ja również uczę się XNA i na moich zajęciach, np. na Twoich zajęciach z piłką. Chciałbym mieć w nim przynajmniej metodę Update(gametime) i metodę Draw (). Zwykle również Initialize (), Load (). Następnie z głównej klasy gry nazwę te metody od swoich kuzynów. To było zanim dowiedziałem się o GameComponent. Oto dobry artykuł o tym, czy powinieneś go używać. http://www.nuclex.org/blog/gamedev/100-to-gamecomponent-or-not-to-gamecomponent

 0
Author: nportelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-28 14:17:03