Trennung von Spiellogik und Grafikausgabe



  • Hallo,
    ich habe mich in diesem Forum angemeldet, weil ich einige Fragen zur Spieleprogrammierung habe. Den rein technischen Teil beherrsche ich. Mir geht es eher um konzeptionelle Geschichten. Dazu möchte ich hier meine erste Frage stellen:

    Es heißt ja immer, man soll Spiellogik von Grafikausgabe trennen. Nun würde ich gerne wissen, wie weit das gehen soll bzw. wie weit das in der Praxis angewandt wird. Stellen wir uns mal ein ganz einfaches Demoprogramm vor, in dem ein einzelnes Männchen auf einem rechteckigen Spielfeld umherläuft. Betrachten wir hierzu mal nur das Männchen:

    Im Prinzip müsste ich ja hier dann zwei Klassen haben:

    Eine Klasse "GameCharacter" für die Spiellogik, in der folgendes gespeichert ist:
    Position auf dem Spielfeld
    Bewegungsstatus (Stehend oder Laufend)
    Blickrichtung
    Geschwindigkeit

    Was in der Spiellogik ja nicht interessiert, ist die Darstellungsweise im fetigen Spiel. Das heißt, ob das Spiel nun eine Top-Down-Ansicht wie "Pac-Man" hat oder als 3-dimensionaler Raum mit frei schwenkbarer Kamera dargestellt wird, ist für die Spiellogik unerheblich. Auch ist es egal, ob die Spielfigur ein 16x16 Pixel großes Bild mit drei Animationsphasen ist oder ein Modell eines Menschen mit absolut realistischen Bewegungsphasen. Deshalb brauchen wir noch eine Klasse "Sprite" für die Grafikausgabe. Nehmen wir an, wir entscheiden uns für die Top-Down-Ansicht. Dann brauchen wir als Member:
    Referenz auf das GameCharacter-Objekt
    Funktion zum Umwandeln der logischen Position auf dem Spielfeld in eine tatsächliche Position auf dem Bildschirm
    Bitmapnummer für die aktuelle Animationsphase
    Wert, nach wie vielen Bewegungsschritten die Animationsphase geändert wird
    Referenz auf die Bitmaps

    Ich würde jetzt gerne wissen: Wird das in der Realität wirklich so gemacht? Ich habe mal in einem Buch zur Spieleprogrammierung gelesen. Und dort hat der Autor eine Sprite-struct erstellt und dort sowohl die spiellogischen Dinge wie den Status, als auch die grafiktechnischen Attribute (inklusive der Bitmap-Variable) eingebaut.

    Oder man denke an die Schutzschilde in "Space Invaders", deren Zustand 1:1 von der Grafik abhängig ist, da die Schüsse einzelne Pixel wegschießen und die Schilde somit durchlässig machen können: Screenshot.



  • Es gibt unzählige Wege. Bastel einfach mal drauf los, mit der Zeit kommt das Gefühl 😉

    Natürlich gibt es auch bestimmte Methoden, die ziemlich gängig bzw. effizient sind, doch selbst da gibt es Unzähliges... google einfach mal ein bisschen.



  • Ich mach das zwar auch nur hobbymäßig, aber ich mache es ziemlich genau so, wie du es beschrieben hast. Ich habe eine Objektklasse, welche irgendein Objekt nur in Koordinaten, Geschwindigkeiten, Ausrichtungen, Beschleunigungen usw. allgemein beschreibt. Von dieser Klasse erben dann alle möglichen Darstellungsklassen, für 2D, 3D, animiert, Standbild usw.
    Ob es in Fachkreisen so gemacht wird weiß ich nicht genau, aber ich nehme es an. Korrigiert mich wenn nicht. 😉



  • Ich habe gehört, man soll bevor man über die Straße geht, erst links schauen, dann rechts, dann wieder links, und dann erst loslaufen, und zwar auf dem kürzesten Weg die Straße überqueren.
    http://www.ruv.de/de/r_v_ratgeber/fahrzeug_verkehr/sicher/1_verkehrserziehungfuerabc_schuetzen.jsp

    Inzwischen schaue ich aber nach links und rechts in willkürlicher Reihenfolge, gerade wie es weniger Arbeit ist, und gehe gerne in einer Traktrix.

    Wenn Du das Warum verstanden hast, darfst und sollst Du von absoluten Regeln meistens abweichen. Natürlich programmiert(e) man Space-Invadors anders.

    Es hängt auch sonst vom Spiel ab. Ein (das!) tile-basiertes MMORPG wie Ultima Online muß man quasi unabhängig von der Grafik schreiben, weil die Grafik gar nicht nötig ist, und man wird sofort belohnt, weil man nicht GUI-Klicken muß zum Debuggen. Außerdem ist die Logik da sehr fett. Man kann sich von Dutzenden Berufen einen oder mehrere aussuchen. Allein mein Client-Bot, der Drachenschiffe bauen konnte, inclusive Holzfällen, Erzschürfen, Werkzeugschmieden, Seilkaufen, Stoffkaufen, Drachenerschlagen, ach, das war eine schöne Programmierherausforderung.

    Je grafiklastiger das Game wird, desto mehr hat man den Drang, die Grafik gleich in die Gamelogik-Klassen reinzumachen. Und das ist auch üblich. Oft ist die Gamlogik sowas von trivial, daß man sie jederzeit quasi ohne Zeitverlust in die Grafik reinmergen könnte, wenn man eine andere Grafikidee hätte. Ungetrennt ist schon manchmal naheliegender.

    Wenn Du sinnvoll trennen kannst, dann trenne. Der Programmieraufwand ist ja nur konstant pro Klasse und der Laufzeitoverhead ganz konstant, je nach Implemetierung auch mal 0. Aber manchmal ist das Trennen einfach irrsinnig.

    Und bei 3d-First-Person-Shooters haben wir einen netten Effekt: Sie sind von Natur aus besonders grafiklastig. Nur triviale Logik. Also nich trennen. Andererseits rotzt man die Grafik nur raus und erwartet optimalerweise keine oder kaum Rückkopplung. Also trennen. Mist.



  • Gamerolaf schrieb:

    Deshalb brauchen wir noch eine Klasse "Sprite" für die Grafikausgabe. Nehmen wir an, wir entscheiden uns für die Top-Down-Ansicht. Dann brauchen wir als Member:
    Referenz auf das GameCharacter-Objekt
    Funktion zum Umwandeln der logischen Position auf dem Spielfeld in eine tatsächliche Position auf dem Bildschirm
    Bitmapnummer für die aktuelle Animationsphase
    Wert, nach wie vielen Bewegungsschritten die Animationsphase geändert wird
    Referenz auf die Bitmaps

    Anstatt ner Referenz auf das Objekt kann man das auch mit Callbacks machen, dein "Sprite" kann ein Observer sein Google: Observer Pattern

    volkard schrieb:

    Und bei 3d-First-Person-Shooters haben wir einen netten Effekt: Sie sind von Natur aus besonders grafiklastig. Nur triviale Logik.

    Wie kommst du darauf? Ich spiel die ja nicht oft, aber ich hab schon gesehen, dass die KI sich hinter Kisten versteckt usw.



  • Gamerolaf schrieb:

    Ich habe mal in einem Buch zur Spieleprogrammierung gelesen. Und dort hat der Autor eine Sprite-struct erstellt und dort sowohl die spiellogischen Dinge wie den Status, als auch die grafiktechnischen Attribute (inklusive der Bitmap-Variable) eingebaut.

    Das passiert, wenn man zu viele Bücher ließt, die sind nämlich meistens auch nur von Menschen geschrieben.

    Gamerolaf schrieb:

    Oder man denke an die Schutzschilde in "Space Invaders", deren Zustand 1:1 von der Grafik abhängig ist, da die Schüsse einzelne Pixel wegschießen und die Schilde somit durchlässig machen können: Screenshot.

    Wenn man jetzt noch eine Hintergrundgrafik will, hat man schon ein Problem. Man kann aber einfach nicht auf der Grafik rumschießen, sondern auf einem array das so aussieht wie die Grafik.



  • pppppppppppppppppuuuuuu schrieb:

    volkard schrieb:

    Und bei 3d-First-Person-Shooters haben wir einen netten Effekt: Sie sind von Natur aus besonders grafiklastig. Nur triviale Logik.

    Wie kommst du darauf? Ich spiel die ja nicht oft, aber ich hab schon gesehen, dass die KI sich hinter Kisten versteckt usw.

    Ich würde erwarten, daß auch die trivial ist. Vielleicht der unsichtbare Keksrucksack.



  • Hab mal kurz gegoogelt, anscheinend läßt sich da schon was nicht triviales machen oder man versuchts.
    http://www.pcgameshardware.de/aid,745961/Ego-Shooter-Brink-soll-mit-menschenaehnlicher-KI-kommen/Action-Spiel/News/



  • pppppppppppppppppuuuuuu schrieb:

    Hab mal kurz gegoogelt, anscheinend läßt sich da schon was nicht triviales machen oder man versuchts.
    http://www.pcgameshardware.de/aid,745961/Ego-Shooter-Brink-soll-mit-menschenaehnlicher-KI-kommen/Action-Spiel/News/

    Ok, diese Leute haben getrennt; sonst wäre das wohl gar nicht möglich.



  • Ego-Shooter Brink soll mit menschenähnlicher KI kommen

    In Brink, you won't have to babysit your AI squad mates

    Wer sieht hier noch einen Wiederspruch? 😃


  • Mod

    Gamerolaf schrieb:

    Ich würde jetzt gerne wissen: Wird das in der Realität wirklich so gemacht? Ich habe mal in einem Buch zur Spieleprogrammierung gelesen. Und dort hat der Autor eine Sprite-struct erstellt und dort sowohl die spiellogischen Dinge wie den Status, als auch die grafiktechnischen Attribute (inklusive der Bitmap-Variable) eingebaut.

    ich denke, das ist nur ein anriss von dem was in wirklichkeit vorgeht, denn es gibt weit mehr als nur gamelogik und graphik, wenn du ein netzwerkspiel hast, hast du z.B.
    -network state (also das was als letztes vom server kam)
    -game logik (das simuliert das spiel anhand des network states,der AI und vom player input)
    -physic simulation (das kann rein logische dinge wie collision detection beinhalten, rein optische wie z.b. hair oder particle simulation oder rigid body simulation was logik, rendering, animation, sound einbezieht)
    -sound rendering
    -graphik rendering

    und all diese dinge muessen miteinander inteagieren, es ist nicht nur weiterleiten von positionsdaten, es gibt z.b. eine animation die ein character abspielt und gleichzeitig ist dieser in einer physic engine simuliert, wird er z.b. angeschossen, muss die physic den rueckschlag am entsprechendem koerperteil simulieren, laeufst du hingegen nur rum, muessen kisten usw. vom spieler weggeschoben werden.
    was logik->rendering angeht, gibt es meistens 99% rein optimischer objekte die in der logik nicht enthalten sind, deswegen werden in diesem fall meist explizit von der logik daten ans rendering geschickt (sowohl graphisches als auch audio rendering).

    Oder man denke an die Schutzschilde in "Space Invaders", deren Zustand 1:1 von der Grafik abhängig ist, da die Schüsse einzelne Pixel wegschießen und die Schilde somit durchlässig machen können: Screenshot.

    es sieht nur so aus als ob das so eng verknuepft ist, es kann sehr gut sein, dass man rausfindet, dass z.b. ein kleiner gegner sehr schwer zu treffen ist, wenn auch realistisch, macht das spiel dann weniger spass, also entscheidet man, dass die kollisionsdetection den schild radius nun um 2pixels rand erweitert, das hat optisch keinen einfluss, das ufo soll ja weiterhin klein aussehen.
    In Doom3 hat man z.b. polygongenaue kollisionsberechnung eingebaut, quasi als erstes spiel was das hat und das haben die leute von splash damage beim erstellen von quake:et wieder ausgebaut, weil es schwerer zu treffen war, gerade sowas wie head-shots waren selten und somit weniger spassig fuer die meisten spieler die auf koepfe zielen.

    es gibt aber kein standard system, es ist von firma zu firma, spiel zu spiel, von architect zu architect anders geloest.

    in hobby projekten die meistens das maximum aus ihrer kleinen entwicklungszeit herauskratzen muessen, sollte man nicht auf perfektion setzen, sondern das noetigste implementieren was einem erlaubt das ziel zu erreichen.



  • Direkt als ich den Artikel las, war mir klar, du suchst sowas wie das MVC-Pattern. Wenn du dich damit auseinandersetzt, fällt dir vielleicht was passendes für dich ein.

    Unsere GameEngine ist komplett in MVC realisiert bzw. als MVVM-Pattern.
    SpacesInvaders in 3D sieht dann so aus

    Falls dir MVC zu sehr nach Overkill aussieht, dann schreibe alles was mit dem View/Grafik zu tun hat per Dependency Injection, denn nichts ist schlimmer als eine Ball-Klasse, die wie folgt realisiert ist:

    class Ball : public YourBaseHere
    {
      void Draw(Pos)
      {
        Canvas = YourSingleton::ptr()->getCanvas();
        // Wie auch immer die Implementierung hier dann aussehen mag
        Canvas->Draw(Pos, ...);
      }
    }
    


  • Danke für die zahlreichen Antworten. Ich denke, der MVC-Ansatz ist richtig für mich.



  • nurf schrieb:

    Unsere GameEngine ist komplett in MVC realisiert bzw. als MVVM-Pattern.

    Magst du kurz anreißen, wie das konkret aussieht? MVC und MVVM lassen sich ja auch recht unterschiedlich implementieren.



  • fdfdg schrieb:

    nurf schrieb:

    Unsere GameEngine ist komplett in MVC realisiert bzw. als MVVM-Pattern.

    Magst du kurz anreißen, wie das konkret aussieht? MVC und MVVM lassen sich ja auch recht unterschiedlich implementieren.

    Das stimmt! Im Grunde genommen sind wir bei MVC gestartet und bei MVVM gelandet.
    Gewisse Teile des Views haben nichts mit dem Spiel-Model zu tun , bspw. welches 3D-Mesh zu einem Objekt gehört, das würde ich mal als "View-Model" bezeichnen. Als Gegensatz zu dem Spiel-Model.
    Nur als Begrifflichkeiten mal vorweg.

    Eine wichtige Anforderung für unsere Game-Engine ist Skalierbarkeit auf Multi-Core Systemen (4-8 Kern).
    Daher haben wir entschieden, die verschiedenen Grundbestandteile via MVC zu trennen.
    Momentan haben wir folgende Module die in verschiedenen Threads laufen (können): Spiel-Model, Grafik, Physik, Input, Sound
    Die Module laufen weiterhin asynchron, d.h. die Game-Engine arbeitet ereignisbaisert, nicht frame-basiert.

    Normalerweise braucht der View die meiste CPU-Zeit (Rendern, etc.), aber die Physik ist auch nicht vernachlässigen.

    Ich glaube das waren die Fakten kurz zusammengefasst.
    Falls jemand an unserer GameEngine mitarbeiten, oder sein eigenes Spiel darauf entwickeln möchte, einfach bei mir melden.


Anmelden zum Antworten