Disclamer: Ich weiß , was ein Unternehmen System Muster ist , und ich bin nicht mit ihm.
Ich habe viel über das Trennen von Objekten und das Rendern gelesen. Über die Tatsache, dass die Spielelogik unabhängig von der zugrunde liegenden Rendering-Engine sein sollte. Das ist alles in Ordnung und gut und es macht vollkommen Sinn, aber es verursacht auch viele andere Schmerzen:
- Notwendigkeit der Synchronisation zwischen dem Logikobjekt und dem Renderingobjekt (das den Status der Animation, der Sprites usw. beibehält)
- Das Logikobjekt muss für die Öffentlichkeit geöffnet werden, damit das Rendering-Objekt den tatsächlichen Status des Logikobjekts lesen kann (was häufig dazu führt, dass sich das Logikobjekt leicht in ein dummes Getter- und Setter-Objekt verwandelt).
Das klingt für mich nicht nach einer guten Lösung. Andererseits ist es sehr intuitiv, sich ein Objekt als 3D- (oder 2D-) Darstellung vorzustellen, und es ist auch sehr einfach zu warten (und möglicherweise auch viel gekapselter).
Gibt es eine Möglichkeit, die grafische Darstellung und die Spielelogik miteinander zu verbinden (um Synchronisationsprobleme zu vermeiden), aber die Rendering-Engine zu abstrahieren? Oder gibt es eine Möglichkeit, Spielelogik und Rendering zu trennen, die die oben genannten Nachteile nicht verursacht?
(möglicherweise mit Beispielen, ich bin nicht sehr gut darin, abstrakte Gespräche zu verstehen)
quelle
Antworten:
Angenommen, Sie haben eine Szene die aus einer Welt , einem Spieler und einem Boss besteht. Oh, und das ist ein Spiel für Dritte, also hast du auch eine Kamera .
Ihre Szene sieht also so aus:
(Zumindest, das ist die Grunddaten . Wie Sie die Daten enthalten, zu Ihnen auf.)
Sie möchten die Szene nur aktualisieren und rendern, wenn Sie das Spiel spielen, nicht wenn sie angehalten ist oder im Hauptmenü ... also hängen Sie sie an den Spielstatus an!
Jetzt hat Ihr Spielstatus eine Szene. Als Nächstes möchten Sie die Logik für die Szene ausführen und die Szene rendern. Für die Logik führen Sie einfach eine Aktualisierungsfunktion aus.
Auf diese Weise können Sie die gesamte Spiellogik in der behalten
Scene
Klasse . Und nur als Referenz könnte ein Entitätskomponentensystem dies stattdessen so machen:Wie auch immer, Sie haben es jetzt geschafft, Ihre Szene zu aktualisieren. Jetzt möchten Sie es anzeigen! Für die wir etwas Ähnliches tun wie oben:
Los geht's. Das renderSystem liest die Informationen aus der Szene und zeigt das entsprechende Bild an. Vereinfacht ausgedrückt könnte die Methode zum Rendern der Szene folgendermaßen aussehen:
Wirklich vereinfacht, müssten Sie beispielsweise noch eine Rotation und Übersetzung anwenden, die darauf basiert, wo sich Ihr Spieler befindet und wo er sucht. (Mein Beispiel ist ein 3D-Spiel. Wenn Sie sich für 2D entscheiden, ist dies ein Spaziergang im Park.)
Ich hoffe das ist was du gesucht hast? Wie Sie sich hoffentlich aus dem oben Gesagten erinnern können, ist das Render-System kümmert sich nicht um die Logik des Spiels . Es wird nur der aktuelle Status der Szene zum Rendern verwendet, dh es werden die erforderlichen Informationen zum Rendern daraus abgerufen. Und die Spiellogik? Es ist egal, was der Renderer macht. Heck, es ist egal, ob es überhaupt angezeigt wird!
Außerdem müssen Sie der Szene keine Rendering-Informationen hinzufügen. Es sollte ausreichen, dass der Renderer weiß, dass er einen Ork rendern muss. Du hast bereits ein Ork-Modell geladen, das der Renderer dann anzeigen kann.
Dies sollte Ihren Anforderungen entsprechen. Die grafische Darstellung und die Logik sind gekoppelt , da beide dieselben Daten verwenden. Dennoch sind sie getrennt , weil sich keiner auf den anderen verlässt!
EDIT: Und nur um zu beantworten, warum man es so machen würde? Weil es einfacher ist, ist der einfachste Grund. Sie müssen nicht darüber nachdenken, "so und so ist passiert, ich sollte jetzt die Grafiken aktualisieren". Stattdessen machst du Dinge möglich, und in jedem Frame des Spiels wird untersucht, was gerade passiert, und es wird auf irgendeine Weise interpretiert, sodass du ein Ergebnis auf dem Bildschirm erhältst.
quelle
Ihr Titel stellt eine andere Frage als Ihr Körperinhalt. Im Titel fragen Sie, warum Logik und Rendering getrennt werden sollten, aber im Hauptteil fragen Sie nach Implementierungen von Logik- / Grafik- / Rendering-Systemen.
Die zweite Frage wurde bereits angesprochen , daher werde ich mich auf die erste Frage konzentrieren.
Gründe für die Trennung von Logik und Rendering:
In einer OOP-Einstellung ist das Instanziieren neuer Objekte mit Kosten verbunden, aber meiner Erfahrung nach sind die Kosten für Systemressourcen ein geringer Preis für die Fähigkeit, über die spezifischen Dinge nachzudenken und diese zu implementieren, die ich erledigen muss.
quelle
Diese Antwort dient nur dazu, eine Vorstellung davon zu entwickeln, warum die Trennung von Rendering und Logik wichtig ist, anstatt direkt praktische Beispiele vorzuschlagen.
Nehmen wir an, wir haben einen großen Elefanten , niemand im Raum kann den ganzen Elefanten sehen. Vielleicht sind sich alle sogar nicht einig darüber, was es tatsächlich ist. Weil jeder einen anderen Teil des Elefanten sieht und nur mit diesem Teil umgehen kann. Aber am Ende ändert dies nichts an der Tatsache, dass es sich um einen großen Elefanten handelt.
Der Elefant repräsentiert das Spielobjekt mit all seinen Details. Aber niemand muss wirklich alles über den Elefanten (Spielobjekt) wissen, um seine Funktionalität ausführen zu können.
Das Koppeln der Spiellogik und des Renderns ist eigentlich so, als würde jeder den ganzen Elefanten sehen. Wenn sich etwas geändert hat, muss jeder davon wissen. Während sie in den meisten Fällen nur den Teil sehen müssen, an dem sie nur interessiert sind. Wenn etwas die Person verändert hat, die davon weiß, muss sie nur der anderen Person über das Ergebnis dieser Änderung erzählen, das ist nur für sie wichtig (Betrachten Sie dies als Kommunikation über Nachrichten oder Schnittstellen).
Die Punkte, die Sie erwähnt haben, sind keine Nachteile, sondern nur Nachteile, wenn es mehr Abhängigkeiten gab, als es in der Engine geben sollte. Mit anderen Worten, Systeme sehen Teile des Elefanten mehr als sie sollten. Und das bedeutet, dass der Motor nicht "richtig" konstruiert wurde.
Sie müssen nur mit der formalen Definition synchronisiert werden, wenn Sie eine Multithread-Engine verwenden, bei der die Logik und das Rendering in zwei verschiedenen Threads zusammengefasst sind, und selbst eine Engine, die viel Synchronisation zwischen Systemen erfordert, ist nicht besonders gut ausgelegt.
Andernfalls besteht die natürliche Art, mit einem solchen Fall umzugehen, darin, das System als Eingabe / Ausgabe zu entwerfen. Das Update führt die Logik aus und gibt das Ergebnis aus. Das Rendering wird nur mit den Ergebnissen des Updates gespeist. Sie müssen nicht wirklich alles aussetzen. Sie legen nur eine Schnittstelle offen, die zwischen den beiden Stufen kommuniziert. Die Kommunikation zwischen verschiedenen Teilen der Engine sollte über Abstraktionen (Schnittstellen) und / oder Nachrichten erfolgen. Es sollten keine internen Logik oder Zustände offengelegt werden.
Nehmen wir ein einfaches Beispiel für ein Szenendiagramm, um die Idee zu erklären.
Die Aktualisierung erfolgt normalerweise über eine einzelne Schleife, die als Spieleschleife bezeichnet wird (oder möglicherweise über mehrere Spielschleifen, die jeweils in einem separaten Thread ausgeführt werden). Sobald die Schleife jemals ein Spielobjekt aktualisiert hat. Es muss nur über Messaging oder Schnittstellen mitteilen, dass die Objekte 1 und 2 aktualisiert wurden, und sie mit der endgültigen Transformation versorgen.
Das Rendering-System nimmt nur die endgültige Transformation vor und weiß nicht, was sich tatsächlich am Objekt geändert hat (z. B. ist eine bestimmte Kollision aufgetreten usw.). Um dieses Objekt zu rendern, benötigt es nur die ID dieses Objekts und die endgültige Transformation. Danach füttert der Renderer die Rendering-API mit dem Netz und der endgültigen Transformation, ohne etwas anderes zu wissen.
quelle