Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Programming

Leerzeichen: Nützliche Spielobjekt Behälter

by
Difficulty:IntermediateLength:LongLanguages:

German (Deutsch) translation by Tatsiana Bochkareva (you can also view the original English article)

Der Sinn eines Raumes besteht darin, Spiel-Objekte zu halten. Die Spielobjekte in einem Raum sollten keine Möglichkeit haben, mit den Spielobjekten in einem anderen Raum zu kommunizieren. Räume bieten daher eine einfache Möglichkeit, 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, lesen Sie bitte die Open Source Game Engine SEL. Ich selbst verfasse SEL aktiv und bin stolz darauf, es den Lesern dieses Artikels als voll funktionsfähige Ressource präsentieren zu können.

Ich möchte Sean Middleditch dafür danken, dass er mich über die Vorteile von Spaces unterrichtet hat.

Tipp: Der Begriff Space im Kontext dieses Artikels bezieht sich auf einen speziellen Container mit Spielobjekten. Mir ist kein klar definierter offizieller Begriff bekannt. Wenn Sie eines kennen, kommentieren Sie bitte!


Konventionelle Objektverwaltung

In einer herkömmlichen Spiel-Engine werden Spielobjekte normalerweise in einem einzigen Container gespeichert. Ein solcher Container kann zusammen mit einem Handle-Manager ein Allokator 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.

Dies ist in Ordnung und funktioniert völlig, hat aber einige organisatorische Probleme. Stellen Sie sich zum Beispiel einen traditionellen Game State Manager vor. Zwischen dem Übergang von einem Zustand in einen anderen werden häufig alle aktuell geladenen Spielobjekte freigegeben und neue von der Festplatte eingelesen. Zur Optimierung können Spielobjekte für den nächsten Status (oder das nächste Level) vorab in einen separaten Thread geladen werden, sodass Statusü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 wird das Spieler-HUD mithilfe von Spielobjekten und Skripten codiert, die an diese Spielobjekte angehängt sind. Eine naive Implementierung des staatlichen Managements würde erfordern, dass alle HUD-Elemente beim Übergang des Staates zerstört und neu erstellt werden. Dies bedeutet, dass benutzerdefinierter Code erforderlich ist, um den Übergang bestimmter Objekte von einem Zustand in einen anderen zu handhaben.

Oder vielleicht erfordert ein Spieldesign eine verrückte Hintergrundlandschaft, in der ein riesiger Kampf stattfindet - aber dieser Kampf darf den Vordergrund (oder den Spieler) in keiner Weise beeinträchtigen.

Oft entstehen seltsame hackige Lösungen für diese Art von Dingen, wie die Darstellung von HUD-Elementen, die extrem weit vom Rest des Spiels in der Welt entfernt sind. Pausenmenüs und dergleichen werden bei Bedarf nur angezeigt und ansonsten entfernt. Im Allgemeinen ist benutzerdefinierter Code erforderlich, um Spielobjekte zu verwalten und zu organisieren, da sich alle in einer einzigen Fabrik oder einem einzigen Container befinden.


Mehrere Game Objekt Behälter

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 haben, werden Räume zu einem natürlichen Weg, um sich der Organisation von Spielobjekten zu nähern. Dies kann den Bedarf an speziellem Code zur Verwaltung eines separaten logischen Containers innerhalb eines tatsächlichen Containers (wie im vorherigen Abschnitt erwähnt) erheblich minimieren.

Lassen Sie uns einen kurzen Blick auf ein Beispiel werfen, wie eine Space-Implementierung in einer Sprache ähnlich wie C++ aussehen könnte:

Es ist oft nützlich, ein Leerzeichen nach Namen suchen zu können. Dies ist besonders gut für Skripte geeignet, bei denen ein Skript Code wie folgt verwenden kann:

Diagram showing the simple organization of game objects into isolated containers.Diagram showing the simple organization of game objects into isolated containers.Diagram showing the simple organization of game objects into isolated containers.
Diagramm, das die einfache Organisation von Spielobjekten in isolierten Containern zeigt. Nicht alle Felder haben die gleiche Anzahl an Spielobjekten oder sogar die gleichen Spielobjekte.

Welche Objekte gehen in Räume?

Die Antwort auf diese Frage lautet: alle! Jede Art von Spielobjekt wird in ein Feld gelegt. Wenn Sie mit Aggregation (oder komponentenbasiertem Design) vertraut sind, befinden sich ein Spielobjekt und die zugehörigen Komponenten alle im selben Bereich.

Die Idee ist, ein Architekturmerkmal zu erstellen, um auf einfache und effektive Weise Spielobjekte zu gruppieren und von anderen Gruppen zu isolieren.

Terminologie

Räume sind einigen anderen Konzepten ziemlich ähnlich, die schon seit einiger Zeit im Umlauf sind. Es wurde gesagt, dass Leerzeichen der Anzeigeliste in Flash ähneln. Wenn Sie mit Portalen zum Rendern von Renderings vertraut sind (besonders wichtig bei 3D-Spielen mit vielen Innenräumen), ist die Idee auch hier ziemlich ähnlich.

Hier ist jedoch ein wichtiger Unterschied zu machen. Leerzeichen sind keine Form der räumlichen Partitionierung, wie dies bei Portalen oder anderen räumlichen Partitionierungen (wie dem beliebten BSP-Baum) zum Rendern der Okklusion der Fall ist. Räume sind ein architektonisches Merkmal, um die Isolierung allgemeiner Spielobjekte zu ermöglichen.

Persönlich denke ich gerne an Räume wie Photoshop-Ebenen: Alle Ebenen können gleichzeitig angezeigt (oder gehört) werden, aber beim Malen auf einer Ebene sind keine anderen Ebenen jemals direkt betroffen. Jede Schicht ist einzigartig und isoliert.

Systeme und Räume

Das Konzept eines Systems für die Zwecke dieses Artikels kann als eine Reihe von Funktionen (Funktionen oder Methoden) beschrieben werden, die auf die Spielobjekte eines Raums einwirken. Auf diese Weise wird ein Leerzeichen an ein System übergeben, um eine Aktion auszuführen. Ein bestimmtes System ist für das gesamte Spiel global.

Diagram exemplifying the simplicity of allowing a system to operate upon a space as input.Diagram exemplifying the simplicity of allowing a system to operate upon a space as input.Diagram exemplifying the simplicity of allowing a system to operate upon a space as input.
Ein Diagramm, das die Einfachheit veranschaulicht, die es einem System ermöglicht, einen Raum als Eingabe zu bearbeiten.

Stellen Sie sich ein Grafiksystem vor, das eine void Graphics::DrawWorld( Space space )-Funktion enthält. Diese DrawWorld-Funktion würde die Objekte innerhalb des agegebenen Bereichs, die renderbar sind, durchlaufen und sie auf dem Bildschirm zeichnen.

Die Idee ist nun, Code (Systeme) zu schreiben, der mit einer bestimmten Eingabe von Spielobjekten arbeitet. Innerhalb solcher Systeme muss keine spezielle Verfolgung oder Verwaltung von Spielobjekten erfolgen. Ein System sollte nichts anderes tun, als Operationen an Spielobjekten durchzuführen.

Dieser Stil bietet Ihnen einige wirklich schöne Vorteile, wie im nächsten Abschnitt beschrieben.


Vorteile von Räumen

Der unmittelbarste Vorteil der Implementierung von Leerzeichen innerhalb 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, und wenn dieses Menü inaktiv ist, müssen Systeme einfach nicht mit dem Inhalt des Raums arbeiten. Wenn ein Menü inaktiv ist, befindet es sich im Speicher (die Spielobjekte, aus denen der Speicher besteht, befinden sich im Menübereich) und tun nichts. Es wird weder von einem Logiksystem aktualisiert noch von einem Grafiksystem gerendert.

Wenn dieses Menü wieder aktiv wird, kann es einfach an die entsprechenden Systeme übergeben werden. Das Menü kann dann aktualisiert und entsprechend gerendert werden. Gleichzeitig kann das Gameplay hinter dem Menü in keiner Weise mehr aktualisiert werden, obwohl es möglicherweise noch zum Rendern an das Grafiksystem übergeben wird. Dies implementiert trivial eine elegante und robuste Funktion zum Anhalten und Fortsetzen, die aufgrund der Art und Weise, wie Räume definiert werden, nur implizit erfolgt.

Isolierte Ebenen

In RPG-Spielen wie Pokémon betritt und verlässt der Spieler häufig Häuser und Hütten. In Bezug auf das Gameplay sind diese verschiedenen Häuser normalerweise vollständig isoliert. Kleine Häuser oder Höhlen sind ein ideales Szenario, um Räume zu nutzen. Ein ganzer Raum kann so konstruiert werden, dass er die Spielobjekte eines bestimmten Hauses enthält. Diese können geladen und im Speicher initialisiert werden und ruhen, bis sie benötigt werden. Sofortige Übergänge können erreicht werden, indem einfach ausgetauscht wird, welcher Raum an die verschiedenen Motorsysteme übergeben wird.

Eine coole Idee für 2D-Spiele wie Plattformer (oder sogar 3D-Spiele) könnte darin bestehen, tatsächliche Levels und Feinde aus dem Spiel im Hintergrund zu simulieren. Dies könnte die Welt auf eine Weise zum Leben erwecken, die keinen zusätzlichen Inhalt und kaum zusätzliche Entwicklungszeit erfordert. Das beste Beispiel dafür ist Rayman Legends:


Tatsächliche Feinde, wie sie der Spieler normalerweise sieht, könnten in der Ferne herumspringen oder an den Wänden kriechen. Übergänge zwischen diesen verschiedenen "Schichten" könnten einige sehr interessante Gestaltungsmöglichkeiten bieten.

Diese Art von Möglichkeiten ist eigentlich ziemlich selten zu finden, und die Idee von Räumen wird von modernen AAA-Studios oder -Motoren nicht wirklich angenommen. Das Design ist jedoch solide und die Vorteile sind real.

Lokaler Multiplayer

In vielen Spielen mit Multiplayer-Unterstützung, in 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 beide nahe beieinander sind. Manchmal können die Spieler nicht einmal den Bildschirm des anderen verlassen. Dies mag am Spieldesign liegen, aber ich habe den Verdacht, dass es oft an architektonischen Einschränkungen liegt.

Mit Leerzeichen können wir zwei Spieler unterstützen, möglicherweise mit geteilten Bildschirmen, die von einem Level oder einem Gebäude zum anderen reisen. Jeder Spieler kann im selben Feld oder in zwei separaten Feldern wohnen. Wenn sich jeder Spieler in einem anderen Gebäude befindet, befinden sich beide möglicherweise in zwei getrennten Räumen. Sobald sie auf demselben Gebiet zusammenlaufen, kann die Engine eines der Spielobjekte des Spielers in das gegnerische Feld übertragen.

Editor-Unterstützung

Dies ist definitiv mein Lieblingsbeispiel dafür, wie großartig Räume sind. In Editoren gibt es häufig Abschnitte, in denen Sie einen neuen Objekttyp entwickeln können. Dieses Objekt in der Erstellung verfügt normalerweise über ein Ansichtsfenster, in dem eine Vorschau der Erstellung angezeigt wird, während die Entwicklung voranschreitet.

Es kann für die meisten Engines unmöglich sein, einen solchen Editor auf natürliche Weise zu unterstützen. Was ist, wenn der Benutzer die Position ändert und plötzlich mit der Simulation kollidiert und Dinge umwirft oder eine KI aktiviert? Es muss ein benutzerdefinierter Code erstellt werden, um das Objekt im Speicher ordnungsgemäß zu handhaben. Entweder muss der Isolationscode für Sonderfälle oder ein Zwischenformat bearbeitet und vom Editor in die eigentliche Simulation übersetzt werden. Zwischenschritte können irgendeine Form der Serialisierung oder ein komplexes nicht-intrusives Dummy- "Proxy-Objekt" sein. Proxy-Objekte erfordern häufig eine erweiterte Code-Introspektion, um auf nützliche Weise implementiert zu werden. 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 isolirten Raum platziert werden. Dieser Raum kann dann an alle erforderlichen Systeme übergeben und isoliert ordnungsgemäß behandelt werden. In einem solchen Szenario wäre kein Sonderfallcode oder zusätzliches Authoring erforderlich.

In den Editoren können problemlos mehrere Ebenen 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 Softwareentwicklungsaufgabe sein, oder die Editorarchitektur kann eine Form von Räumen implementieren.


Implementierungsideen

Raum-Management

Was verwaltet alle Räume? Viele Spieleentwickler haben es vielleicht in ihrer Praxis, dass alles in der Lage sein muss, von einem Manager "besessen" zu werden. Alle Räume müssen von dieser einzelnen Entität verwaltet werden können, oder? Eigentlich ist diese Art von Paradigma nicht immer notwendig.

In der SEL-Engine werden Leerzeichen von einem Ort aus erstellt und können mit einem Wörterbuch namentlich nachgeschlagen werden. Für die meisten Projekte ist es jedoch möglicherweise am besten, Leerzeichen nur von Fall zu Fal verwalten zu lassen. Oft ist es nur sinnvoll, ein Leerzeichen in einem zufälligen Skript zu erstellen, es eine Weile festzuhalten und dann das Leerzeichen freizugeben. In anderen Fällen wird ein Leerzeichen erstellt, das sich über die gesamte Laufzeit des Spiels im Speicher befindet.

Eine gute Empfehlung wäre, den Benutzer einfach einen Speicherplatz zuweisen und ihn nach Belieben freigeben zu lassen. Es wäre wahrscheinlich gut, einen einzelnen Allokator für dieses Verhalten zu verwenden. Die Verwaltung der Space-Instanz selbst, wie sie aus Erfahrung hervorgeht, sollte jedoch am besten nicht besorgt sein. Überlassen Sie es dem Benutzer.

Hinweis: Wenn ein Raum zerstört wird, sollte er alle darin enthaltenen Objekte bereinigen! Verwechseln Sie nicht das Fehlen eines Managers mit einem Mangel an lebenslanger Verwaltung.

Komponenten und Unterräume

Komponenten werden häufig mit ihren jeweiligen Systemen in einer komponentenbasierten Engine registriert. Bei Leerzeichen wird dies jedoch unnötig. Stattdessen sollte jeder Raum einen sogenannten Unterraum enthalten. Die Implementierung eines Unterraums kann sehr trivial 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, welchem Speicherplatz sie zugeordnet werden soll, und registriert sich beim Unterraum.

Ein Raum muss nicht unbedingt jeden einzelnen Unterraumtyp in sich haben. Beispielsweise benötigt ein Menübereich wahrscheinlich keine physikalische Simulation und verfügt daher möglicherweise nicht über eine vollständige Instanz einer Physikwelt, die einen Physikunterraum darstellt.

Abschließend sollte beachtet werden, dass Ihre Spielobjekte in einer komponentenbasierten Architektur ein Handle oder einen Zeiger auf den Bereich haben sollten, in dem sie sich befinden. Auf diese Weise wird der Bereich Teil der eindeutigen Kennung des Spielobjekts selbst.


Schlussfolgerung

Räume sind extrem einfach zu implementieren und bieten viele wichtige Vorteile. Für so ziemlich jedes existierende Spiel und jede existierende Spiel-Engine wird das Hinzufügen von Leerzeichen aufgrund der einfachen Implementierung positiv sein. Verwenden Sie Räume, auch für sehr kleine Projekte und sehr kleine Spiele!

Als Ressource ist meine eigene Implementierung von Räumen Open Source für die öffentliche Wiedergabe innerhalb der Game Engine SEL.

Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.