Der ganze Punkt von a Platz ist, um Spielobjekte zu halten. Die Spielobjekte in einem Feld sollten nicht haben irgendein So können Sie mit den Spielobjekten in einem anderen Raum kommunizieren, so dass Leerzeichen ein einfaches Mittel sind, um verschiedene Gruppen von Spielobjekten zu trennen. In diesem Artikel lernen Sie die Vorteile einer solchen Architektur kennen.
Wenn Sie ein Beispiel für die Implementierung von Leerzeichen sehen möchten, sehen Sie sich die Open-Source-Spiel-Engine SEL an. Ich selbst verfasse aktiv SEL und bin stolz darauf, es den Lesern dieses Artikels als voll funktionsfähige Ressource vorzustellen.
Ich möchte mich bei Sean Middleditch dafür bedanken, dass er mich über die Vorteile von Spaces unterrichtet hat.
Spitze: Der Begriff Platz bezieht sich in diesem Artikel auf einen speziellen Container von Spielobjekten. Mir ist eigentlich keine klar definierte offizielle Bezeichnung bekannt. Wenn Sie davon wissen, machen Sie bitte einen Kommentar!
In einer herkömmlichen Spiel-Engine werden Spielobjekte normalerweise in einem einzelnen Container gespeichert. Ein solcher Container kann zusammen mit einem Handle-Manager ein Zuweiser sein. Manchmal ist der Container nur eine verknüpfte Liste. Unabhängig von der tatsächlichen Implementierung kann es nur einen einzigen Container geben, der alle Spielobjekte enthält, und jedes erstellte Spielobjekt befindet sich immer in diesem Container.
Das ist in Ordnung und funktioniert absolut, hat aber einige organisatorische Probleme. Stellen Sie sich zum Beispiel einen traditionellen Game-State-Manager vor. Häufig werden zwischen dem Übergang von einem Zustand zu einem anderen alle aktuell geladenen Spielobjekte freigegeben und neue werden von der Festplatte eingelesen. Zur Optimierung können Spielobjekte für den nächsten Status (oder die nächste Ebene) vorzeitig in einen separaten Thread geladen werden, sodass die Zustandsübergänge sofort erfolgen.
Es gibt jedoch ein ärgerliches Problem, das häufig auftritt: Wie stellen wir GUI-Elemente für Menüs dar? Möglicherweise ist das Spieler-HUD mithilfe von Spielobjekten und Skripts codiert, die an diese Spielobjekte angehängt sind. Eine naive Implementierung der Staatsverwaltung würde erfordern, dass alle HUD-Elemente bei einem Staatsübergang zerstört und neu erstellt werden. Dies bedeutet, dass benutzerdefinierter Code für den Übergang bestimmter Objekte von einem Zustand in einen anderen benötigt wird.
Oder vielleicht erfordert ein Spieldesign verrückte Hintergrundszenen, in denen ein gewaltiger Kampf stattfindet - aber dieser Kampf darf den Vordergrund (oder den Spieler) in keiner Weise stören.
Häufig ergeben sich für diese Art von seltsamen, verrückten Lösungen Lösungen, zum Beispiel, dass HUD-Elemente extrem weit vom Rest des Gameplays in der Welt entfernt sind. Pausenmenüs und ähnliches werden bei Bedarf einfach in das Sichtfeld verschoben und bewegen sich ansonsten fort. Im Allgemeinen ist zur Verwaltung und Organisation von Spielobjekten benutzerdefinierter Code erforderlich, da sich diese alle in einer einzigen Fabrik oder einem einzigen Container befinden.
Eine akzeptable Lösung für dieses Problem wäre die Verwendung von Leerzeichen (siehe die zusätzliche Videobeschreibung meines Kollegen Sean Middleditch). Da alle Spielobjekte in jedem Raum keine Interaktion aufweisen, werden Räume zu einer natürlichen Annäherung an die Organisation von Spielobjekten. Dadurch kann die Notwendigkeit eines speziellen Codes zum Verwalten eines separaten logischen Containers in einem tatsächlichen Container (wie im vorherigen Abschnitt erwähnt) erheblich verringert werden..
Werfen wir einen kurzen Blick auf ein Beispiel, wie eine Weltraumimplementierung in einer Sprache aussehen könnte, die C ++ ähnlich ist:
Klasse Space public: GameObject CreateObject (Name der Zeichenfolge); const string GetName (void) const; privat: string m_name; // Könnte eine Zuteilung sein, vielleicht nur ein std :: vector Container m_objects; ;
Es ist oft nützlich, ein Feld nach Namen suchen zu können. Dies ist besonders gut für Skripts, bei denen ein Skript Code wie folgt verwenden kann:
// Führe eine Logik für den Hintergrund aus. Local space = GetSpace ("Background") tornado = space.CreateObject ("Tornado") // Woanders können wir etwas tun, das völlig vom Hintergrund isoliert ist, // wie das Abrufen des Players (wer für einige) Grund starb) und eine // Tod-Animation über dem lokalen Platz des Spielers gespielt wurde = GetSpace ("CurrentLevel") player = space.GetPlayer () space.CreateObjectAt ("DeathAnimation", player)Diagramm, das die einfache Organisation von Spielobjekten in isolierte Container zeigt. Nicht alle Räume haben die gleiche Anzahl von Spielobjekten oder sogar die gleichen Spielobjekte.
Die Antwort auf diese Frage lautet: Alle! Jede Art von Spielobjekt wird in ein Leerzeichen eingefügt. Wenn Sie mit der Aggregation (oder dem komponentenbasierten Design) vertraut sind, befinden sich ein Spielobjekt und die zugehörigen Komponenten alle im selben Bereich.
Die Idee ist, eine Architekturfunktion zu erstellen, die eine einfache und effektive Möglichkeit bietet, Spielobjekte zusammenzufassen und von anderen Gruppen zu isolieren.
Räume ähneln einigen anderen Konzepten, die seit einiger Zeit im Umlauf sind. Es wurde gesagt, dass Leerzeichen der Anzeigeliste in Flash ähneln. Wenn Sie mit Portalen für das Rendern von Bildern vertraut sind (besonders wichtig bei 3D-Spielen mit vielen Innenräumen), ist die Idee auch hier ähnlich.
Hier ist jedoch eine wichtige Unterscheidung zu treffen. Räume sind nicht eine Form der räumlichen Partitionierung, wie sie mit Portalen oder einer anderen räumlichen Partitionierung (wie der populäre BSP-Baum) für Render-Okklusion gemacht wird. Räume sind ein architektonisch Funktion zur Isolierung allgemeiner Spielobjekte.
Ich persönlich denke gerne an Räume wie Photoshop-Ebenen: Alle Ebenen können gleichzeitig angezeigt (oder angehört) werden. Beim Malen auf einer Ebene sind jedoch keine anderen Ebenen direkt betroffen. Jede Schicht ist einzigartig und isoliert.
Das Konzept von a System, Für die Zwecke dieses Artikels kann als eine Menge von Funktionen (Funktionen oder Methoden) beschrieben werden, die auf die Spielobjekte eines Raums einwirken. Auf diese Weise wird ein Raum an ein System übergeben, um eine Aktion auszuführen. Ein bestimmtes System ist für das gesamte Spiel global.
Diagramm zur Veranschaulichung der Einfachheit eines Systems, das einen Raum als Eingabe bearbeiten kann.Stellen Sie sich ein Grafiksystem vor, das a enthält void Graphics :: DrawWorld (Leerzeichen)
Funktion. Diese DrawWorld
function würde über die Objekte innerhalb des angegebenen Bereichs, die gerendert werden können, eine Schleife bilden und sie auf dem Bildschirm zeichnen.
Die Idee ist nun, Code (Systeme) zu schreiben, der auf eine bestimmte Eingabe von Spielobjekten einwirkt. Innerhalb solcher Systeme muss keine besondere Verfolgung oder Verwaltung von Spielobjekten erfolgen. Ein System sollte nichts anderes tun, als Operationen an Spielobjekten auszuführen.
Dieser Stil bietet einige wirklich gute Vorteile, wie im nächsten Abschnitt beschrieben.
Der unmittelbare Vorteil der Implementierung von Leerzeichen in einer Engine besteht darin, dass die Handhabung von GUI-Elementen oder -Menüs trivial wird. Wir können einen Raum erstellen, der einem bestimmten Menü zugeordnet ist. Wenn dieses Menü nicht aktiv ist, müssen die Systeme den Inhalt des Raums einfach nicht bearbeiten. Wenn ein Menü inaktiv ist, wird es im Speicher abgelegt (die Spielobjekte, aus denen der Speicher besteht, befinden sich innerhalb des Menübereichs) und tun nichts. Es wird weder von einem Logiksystem aktualisiert noch von einem Grafiksystem dargestellt.
Wenn dieses Menü wieder aktiv wird, kann es einfach an die entsprechenden Systeme übergeben werden. Das Menü kann dann entsprechend aktualisiert und gerendert werden. Gleichzeitig kann das Gameplay, das hinter dem Menü abläuft, nicht mehr aktualisiert werden, obwohl es möglicherweise noch an das Grafiksystem übergeben wurde, um gerendert zu werden. Dadurch wird auf triviale Weise eine elegante und robuste Funktionalität für das Anhalten und Wiederaufnehmen implementiert, die aufgrund der Definition von Leerzeichen gerade implizit auftritt.
In RPG-ähnlichen Spielen wie Pokémon wird der Spieler oft Häuser und Hütten betreten und verlassen. In Bezug auf das Gameplay sind diese verschiedenen Häuser in der Regel vollständig isoliert; kleine Häuser oder Höhlen sind ein ideales Szenario für die Anwendung von Räumen. Ein ganzer Raum kann so gebaut werden, dass er die Spielobjekte eines bestimmten Hauses enthält, und diese können geladen und initialisiert werden, bis sie benötigt werden. Sofortige Übergänge können durch einfaches Austauschen des zur Verfügung stehenden Raums an die verschiedenen Motorsysteme erreicht werden.
Eine coole Idee für 2D-Spiele wie Plattformspieler (oder sogar 3D-Spiele) könnte es sein, tatsächliche Level und Feinde aus dem Spiel im Hintergrund zu simulieren. Dies kann die Welt auf eine Weise zum Leben erwecken, die eigentlich keinen zusätzlichen Inhalt und kaum zusätzliche Entwicklungszeit erfordert. Das beste Beispiel dafür ist Rayman Legends:
Tatsächliche Feinde, so wie es der Spieler normalerweise sieht, könnten in der Ferne herumspringen oder an den Wänden krabbeln. Übergänge zwischen diesen verschiedenen "Schichten" können einige sehr interessante Gestaltungsmöglichkeiten bieten.
Diese Art von Möglichkeiten sind eigentlich recht selten, um Beispiele zu finden, und die Idee von Räumen wird von modernen AAA-Studios oder -Maschinen nicht wirklich angenommen. Das Design ist jedoch solide und die Vorteile sind real.
In vielen Spielen mit Multiplayer-Unterstützung, bei denen beide Spieler mit demselben Spielclient spielen, gibt es einige Einschränkungen. Oft können die Spieler nicht in ein neues Gebiet gehen, ohne dass sich beide in ihrer Nähe befinden. Manchmal können die Spieler den Bildschirm des anderen nicht verlassen. Dies könnte auf das Spieldesign zurückzuführen sein, aber ich habe den Verdacht, dass dies häufig auf architektonische Einschränkungen zurückzuführen ist.
Mit Leerzeichen können wir zwei Spieler unterstützen, z. B. mit geteilten Bildschirmen, die sich von einer Ebene oder einem Gebäude zum anderen bewegen. Jeder Spieler kann sich in demselben oder in zwei separaten Räumen aufhalten. Befindet sich jeder Spieler in einem anderen Gebäude, befinden sich beide möglicherweise in zwei getrennten Räumen. Wenn sie auf dieselbe Fläche zusammenlaufen, kann die Engine eines der Spielobjekte des Spielers in das gegnerische Feld übertragen.
Dies ist definitiv mein Lieblingsbeispiel dafür, wie großartig die Räume sind. In Editoren gibt es oft Abschnitte, in denen Sie einen neuen Objekttyp entwickeln können. Dieses Objekt in der Erstellung verfügt normalerweise über ein Ansichtsfenster, um eine Vorschau der Erstellung anzuzeigen, während die Entwicklung summt.
Es kann für die meisten Engines unmöglich sein, einen solchen Editor natürlich zu unterstützen. Was ist, wenn der Benutzer die Position ändert und er plötzlich mit der Simulation kollidiert und Dinge umstößt oder eine KI aktiviert? Benutzerdefinierter Code muss erstellt werden, um das Objekt im Arbeitsspeicher irgendwie ordnungsgemäß zu behandeln. Es muss entweder ein Sonderfall-Isolationscode oder ein anderes Zwischenformat bearbeitet und vom Editor in die eigentliche Simulation übersetzt werden. Zwischenschritte können eine Art Serialisierung oder ein komplexes, nicht intrusives Dummy- "Proxy-Objekt" sein. Für Proxy-Objekte kann es häufig erforderlich sein, dass erweiterte Code-Introspektion auf nützliche Weise implementiert wird. Diese Optionen können für viele Projekte teuer oder unnötig sein.
Wenn jedoch Räume zur Verfügung stehen, können ein Kameraobjekt und das zu erstellende Objekt in einem isolierten Raum platziert werden. Dieser Raum kann dann an alle erforderlichen Systeme übergeben und isoliert und isoliert verarbeitet werden. In einem solchen Szenario wäre kein Sonderfallcode oder zusätzliches Authoring erforderlich.
Mehrere Ebenen können einfach in den Editoren verwaltet werden. Mehrere Ansichtsfenster und Simulationen können gleichzeitig isoliert ausgeführt werden. Was wäre, wenn ein Entwickler die Entwicklung von zwei Ebenen aufteilen wollte, um schnell hin und her zu wechseln? Dies kann eine schwierige Software-Engineering-Aufgabe sein oder die Editorarchitektur könnte eine Form von Leerzeichen implementieren.
Was verwaltet alle Räume? Viele Spieleentwickler mögen es in ihrer Praxis haben, dass alles von einem Manager "besessen" werden muss. Alle Bereiche müssen von dieser einzelnen Entität verwaltet werden können, oder? Eigentlich ist ein solches Paradigma nicht notwendig die ganze Zeit.
In der SEL-Engine werden Leerzeichen von einem Ort aus erstellt und können mit einem Wörterbuch nach Namen gesucht werden. Es kann jedoch am besten sein, dass die meisten Projekte nur von Fall zu Fall verwaltet werden. Oft ist es nur sinnvoll, ein Leerzeichen in einem zufälligen Skript zu erstellen, es eine Zeit lang festzuhalten und dann das Leerzeichen freizugeben. Zu anderen Zeitpunkten wird ein Bereich erstellt, der sich während der gesamten Laufzeit des Spiels im Speicher befindet.
Eine gute Empfehlung wäre, den Benutzer einfach ein Feld zuweisen zu lassen und es nach Belieben freizugeben. Es ist wahrscheinlich sinnvoll, für dieses Verhalten einen einzelnen Zuweiser zu verwenden. Die Verwaltung der Weltrauminstanz selbst, wie sie sich aus Erfahrung zeigt, kann jedoch nicht besorgt sein. Überlassen Sie es dem Benutzer.
Hinweis: Wenn ein Raum zerstört wird, sollten alle darin enthaltenen Objekte aufgeräumt werden! Verwechseln Sie das Fehlen eines Managers nicht mit einem lebenslangen Management.
Komponenten werden häufig mit ihren jeweiligen Systemen in einer komponentenbasierten Engine registriert. Mit Leerzeichen wird dies jedoch unnötig. Stattdessen sollte jedes Leerzeichen enthalten, was als a bezeichnet wird Unterraum. Ein Unterraum kann sehr einfach zu implementieren sein, beispielsweise als Vektor von Komponentenobjekten. Die Idee ist, einfach verschiedene Arten von Komponentencontainern in jedem Raum zu enthalten. Immer wenn eine Komponente erstellt wird, fordert sie an, mit welchem Platz sie verbunden werden soll, und registriert sich bei dem Unterraum.
Ein Leerzeichen muss nicht notwendigerweise jede Art von Unterraum in sich haben. Zum Beispiel wird ein Menübereich wahrscheinlich keine physikalische Simulation erfordern und daher möglicherweise nicht die gesamte Instanz einer physischen Welt, die einen physischen Unterraum darstellt, haben.
Schließlich sollte beachtet werden, dass in einer komponentenbasierten Architektur Ihre Spielobjekte einen Handle oder Zeiger auf den Raum haben sollen, in dem sie sich befinden. Auf diese Weise wird der Raum Teil der eindeutigen Kennung des Spielobjekts selbst.
Räume sind extrem einfach zu implementieren und bieten viele wichtige Vorteile. Für so ziemlich jedes Spiel und jede Spiel-Engine ist die Hinzufügung von Leerzeichen aufgrund der einfachen Implementierung positiv. Verwenden Sie Leerzeichen auch für sehr kleine Projekte und sehr kleine Spiele!
Als Ressource ist meine eigene Implementierung von Räumen Open Source für das Public Viewing innerhalb der Game Engine SEL.