• Batched Updates 25.07.2014 - 18:30 0

    So hier bin ich wieder, wenn auch diesmal mit einer etwas kleineren Neuerung, die allerdings - wie ich finde - ebenfalls erwähnenswert ist. Zu erst einmal möchte die Problematik beschreiben:

     

    Stellen wir uns mal vor, wir hätten ein GameObject, welches ein Sprite rendern möchte, dazu noch ein Licht, etc. etc... Wir haben dazu noch ein zweites GameObject welches ebenfalls ein Sprite hat. Unsere GameObject-Klasse besitzt unter anderem folgende Methoden:

    class GameObject
    {
    public:
    
        // [...]
        void Update(const vxF32 delta);
        void Render();
    };

    Wir würden also zum Rendern eines GameObjects lediglich die Render()-Funktion aufrufen, und das wär's dann. Allerdings ist das eine ziemlich schlechte Implementierung. Für kleine Spiele mag sie durchaus durch ihre einfache Umsetzung überzeugen, aber ich habe mich für etwas fortgeschritteneres entschieden. Für das sogenannte Batched Updating.

     

    So, jetzt habe ich mit einem Begriff um mich geschmissen, und ihr dürft jetzt alle schön raten, was ich damit meine. Nein, ganz so fies bin ich dann doch nicht, ich erkläre es euch. Unter Batched Updating versteht man das Updaten eines Subsystems der Engine in einem Zug. In unserem Beispiel würden wir ein GameObject rendern, dann würden wir irgendetwas anderes machen, dann würden wir wieder ein GameObject rendern, und dann wieder irgendetwas anderes machen. Das ist unpraktisch, da es unter dem Strich dafür sorgt, dass viele Optimierungen schlichtweg sehr schwer bis unmöglich zu implementieren sind. Ein gutes Beispiel hierfür ist zum Beispiel das Sortieren nach einem Material. Hätten wir unsere Objekte, wie es durchaus üblich ist, in einem Szenen-Graphen gekapselt, dann hätten wir keine Chance, Objekte mit gleicher Textur für ihr zugehöriges Sprite in einem Block zu rendern. Wir würden die ganze Zeit die Texturen wechseln müssen, was bei zu häufiger Anwendung durchaus langsam sein kann. Wie können wir also das Rendering komplett verlegen? Ganz einfach: Wir rendern einfach gar nichts! Nein, ganz so nun auch wieder nicht, aber unsere GameObjects haben einfach keine Render()-Methode mehr. Vielmehr erstellen wir eine Singleton-Klasse, welche eine Liste aller Objekte enthält, die gerendert werden sollen. Diese Objekte besitzen dann Methoden, die benötigte Daten bereitstellen und mit denen sie sich selbst zeichnen können. Außerdem besitzen sie auch eine Eigenschaft namens visible (oder so ähnlich) über die wir der Rendering-Engine mitteilen können, ob das Objekt überhaupt gezeichnet werden soll. Unser GameObject bestitzt dann lediglich die Möglichkeit, die Eigenschaften dieses zeichenbaren Objektes zu verändern, und so die Rendering-Phase zu beeinflussen. So können wir zum Beispiel über den Szenen-Graphen iterieren, und einfach sämtliche GameObjects mit Sprites, die sowieso nicht zu sehen sein würden einfach auf unsichtbar stellen, und so gar nicht erst zeichnen lassen. In unserem Main-Loop können wir dann einfach eine Methode aufrufen, die alles zu zeichnende zeichnet, und zwar an einem Stück:

    // Pseudo-Code:
    while(Game.IsRunning())
    {
        // Update all GameObjects:
        world.UpdateAll();
        // [...]
        // Render everything and present the result on-screen:
        RenderSystem::Get()->RenderAndSwapBuffers();
        // [...]
    }

    Das kann nun durchaus effizient ausgeführt werden, da unser Rendering-System nun die Objekte nach Belieben sortieren kann. Es liegt voll und ganz bei ihm. Das heißt im Endeffekt, wir müssen nur anmelden, dass wir etwas zeichnen wollen, und der Rest geschieht automatisch. Wir sagen dann lediglich, wie genau gezeichnet werden soll. Typische Eigenschaften, die wir beeinflussen, sind um Beispiel Transformationen (Position, Rotation, und Skalierung), und Texturen, sowie die visible-Eigenschaft.

    Ich hoffe ihr könnt nachvollziehen, was ich eigentlich sagen wollte. Bis dahin: Macht's gut!

    ~ EuadeLuxe / EuaconLabs ~


    Kommentare: 0
  • Audio endlich implementiert! 19.07.2014 - 17:12 0

    I. Engine

    VoxE hat nun ein auf OpenAL basierendes Audio-System! Unterstützt werden momentan rohe PCM-Daten in Form einer WAV-Datei, welche durch einen In-House-Loader mittels nur einer einzigen Zeile geladen werden können:

    ResourceHandle<AudioBuffer> hSound =
        ResourceManager::Get()->LoadResource<AudioBuffer>(ResourceKey("my_sound"));

    Danach wird der geladene AudioBuffer einfach an eine dreidimensional-positionierbare AudioSource übergeben, und abgespielt:

    AudioSource source;
    source.SetPosition(0.0f, 0.0f, 0.0f);
    source.SetVelocity(0.0f, 0.0f, 0.0f);
    source.SetBuffer(hSound);
    source.Play();

    Einfach, oder?

    Leider bringt OpenAL eine gewisse Limitierung mit sich: PCM-Daten dürfen höchsten 16-Bit tief sein. Für einige Sound-Techniker ist das ein absolutes No-Go, da sie überzeugt davon sind, dass 32-Bit Tiefen einen deutlich merkbaren Unterschied ausmachen. Ich persönlich kann das nicht beurteilen, weshalb ich auch nicht dagegen argumentieren kann, allerdings werde ich es vorerst bei 16-Bit belassen, bis es wirklich von Bedeutung sein sollte.

    II. Editor

    Auch der Editor hat eine Neuerung bekommen: Den ResourceExplorer. Der ResourceExplorer ersetzt den ProjectExplorer und zeigt auf einen Blick alle Assets, die im Spiel verwendet werden können. Über ihn kann man neue Assets importieren, und eine fiktive Ordnerstruktur erschaffen, die so nicht auf dem Dateisystem existiert. Hierzu ein Screenshot:

     

     

     

     

     

     

     

     

     

    Das war es dann leider auch schon, da ich während der vergangenen Tage wenig Zeit für die Entwicklung aufbringen konnte. Andere Dinge waren einfach wichtiger. Ich hoffe dennoch, weiterhin so aktiv an meinem kleinen Projekt hier weiterarbeiten zu können, und wer weiß, vielleicht kann ich ja auch bald mal etwas vorzeigen ;).

    Bis dahin,

    ~ EuadeLuxe / EuaconLabs ~


    Kommentare: 2
  • Tools & Runtime Systems - Untrennbar? 11.07.2014 - 22:43 0

    Wie im letzten Blogpost angekündigt wende ich immer weiter den Gameplay Foundation Systems (d.h. GameObjects, Szenen-Graphen, etc.) zu und versuche, diese möglichst einfach, wenn auch flexibel zu halten. Dafür setze ich auf sogenannte Components. Das sind isolierte Code-Brüchstücke, die innerhalb eines Objektes bestehen, und nur eine ganz klar bestimmte Aufgabe erfüllen. Ein klassisches Beispiel für derlei Components ist zum Beispiel ein MeshInstance- (im 2D-Bereich: Sprite-) Component, d.h. ein Component, welcher einen Mesh oder ein Sprite anzeigt, wenn das Objekt dazu aufgefordert wird, sich selbst zu zeichnen.

     

    Doch vor zwei Tagen bemerkte ich, dass es sinnlos ist, einfach so herumzubasteln: Diese Gameplay-Foundation-Systeme (von nun an GFS genannt) sind extrem komplex und es ist daher ziemlich aufwendig, Beispiele zum Testen aufzusetzen. Aus diesem Grund werde ich zeitgleich zu den GFS auch an dem World-Editor arbeiten. Dieser soll zum einen Beispiel-Fälle liefern können, zum anderen zeigt sich dann aber auch viel schneller, was für Funktionen benötigt werden, sodass ich diese dann zielgerichtet implementieren kann. Eine frühe Version hiervon könnt ihr in Abbildung (1) sehen.

    Abbildung (1)Der Editor selbst basiert auf wxWidgets und ist daher auf allen gängigen Plattformen kompilierbar. Ich habe den Editor weitestgehend von der Engine entkoppelt, was ich auch im weiteren Verlauf des Projektes beibehalten werde, wo es nur geht. Oben links, sieht man die Projekt-Struktur. Wählt man hier eine Ressource aus bekommt man diese (sofern sie ein unterstütztes Dateiformat besitzt) als Vorschau im Fenster untendran angezeigt. In Mitte wird später eine Vorschau der Spielwelt zu sehen sein, ganz rechts findet man eine Tabelle mit den Eigenschaften des jeweiligen Objektes. Diese Eigenschaften sind von Engine insofern entkoppelt, als dass sie nicht festgeschrieben im Editor existieren, sondern zur Laufzeit aus einem "Schema" geladen werden. Ein Schema ist eine XML-Datei, die einem bestimmten Aufbau folgt, um die Attribute eines Objektes zu beschreiben. Die Attribute können verschiedene Typen besitzen: Primitive Datentypen, wie etwa Booleans, Integer, Unsigned Integer, oder Floats (Intensity), fortgeschrittenere Datentypen wie 3-dimensionale Vektoren (Position), oder Farben (Diffuse Color, Specular Color), oder aber Nutzer-definierte Enumerationen (Type) werden unterstützt. In der Abbildung wurde ein Muster-Schema für eine Lichtquelle benutzt.

    Man könnte mir nun unterstellen, dass die zeitgleiche Entwicklung des Editors den Rahmen sprengen würde. Allerdings erhoffe ich mir, dass eher ein gegenteiliger Effekt erzeugt wird. Der Editor erlaubt es mir relativ unkompliziert neue Funktionen in diesen sonst eher heiklen Bereichen zu testen. Das - so hoffe ich - erspart mir eine Unmenge Debugging-Arbeit, und sobald ein gewisser Funktions-Umfang vorhanden ist, können auch andere fortgeschrittenere Teilsysteme der Engine, wie etwa Szenen-Graphen, etc. einfacher umgesetzt werden.

     

    Ich hoffe es hat euch gefallen, einen weiteren Einblick in die Entwicklung zu bekommen. Wie schon zuvor könnt ihr mich gerne bei Fragen, Anregungen, oder Kritik kontaktiere. Ich stehen für Fragen jederzeit offen.

     

    Liebe Grüße,

    ~ EuadeLuxe / EuaconLabs ~


    Kommentare: 0
  • Hashed String IDs & Audio 08.07.2014 - 21:19 0

    So, um diesen nicht vorhandenen Blog mit etwas Inhalt zu füllen, hier einmal ein kleiner Einblick, was die Entwicklung von VoxE, meinem längerfristigen Projekt betrifft.

    Da ich mich neuerdings immer mehr Richtung Gameplay-Foundation-Systems bewege (d.h. GameObjects / Actors, Szenen-Management, ...) nähere ich mich auch den ersten dazu gehörigen Problemen an. Dazu zählen unter anderem auch sogenannte "einzigartige Bezeichner". Wenn ein Game-Designer beispielsweise im Editor ein Objekt bearbeiten will, wird er dem Objekt lieber einen Namen geben wollen, als sich eine Nummer unter Hunderten, oder gar Tausenden zu merken. Daher habe ich nun das Konzept der sog. "Hashed-String-IDs" übernommen. Verwaltet von einer Singleton-Klasse können nun Hash-Werte von Strings gehashed und gespeichert werden. Dadurch wird versucht, das beste von zwei Seiten herauszugreifen: Zum einen die schnelle Vergleichszeit, die benötigt wird, um zwei Integer-Zahlen miteinander zu vergleichen, zum anderen aber auch der Erhalt der Lesbarkeit (und damit auch der Übersichtlichkeit) der Namen. Außerdem ist geplant, sobald wie möglich die "Lookup-Tabelle", d.h. die Tabelle, welche die Hash-Werte wieder zurück auf Strings mappt, in eine Art "Debug-Speicher" zu verschieben. Das hat zur Folge, dass in einem Debug-Build Zusammenhänge besser untersucht werden können, der erhöhte Speicherbedarf für die Zwischenspeicherung der Strings in der Release-Version allerdings entfällt. Eine andere Lösung wäre natürlich auch, mittels Preprocessor die Lookup-Tabelle in der Release-Version schlichtweg wegzulassen.

     

    Außerdem habe ich mich mittlerweile dem Kapitel Audio etwas angenähert. Eine erste Anbindung von OpenAL an VoxE ist geschaff, was jetzt noch fehlt sind Wrapper um die generellen Funktionen (AudioSources, AudioBuffers, (Streaming), ...). Das Schöne an OpenAL ist nunmal seine Plattform-Unabhängigkeit, zumindest für Linux und Windows, und seine Lizensierung (LGPL). Momentan bin ich mir allerdings noch unsicher, wie Audio-Ausgabe auf Android unterstützt werden wird, allerdings werde ich das wahrscheinlich auf einen späteren Zeitpunkt verschieben, voraussichtlich werden allerdings Funktionen des Android NDKs, insbesondere von OpenSL ES, benutzt werden.

     

    Das sollte es für die letzten drei Tage gewesen sein. Bei Fragen, Anregungen, oder Kritik könnt ihr euch jederzeit bei mir melden, oder (geht das auf Pewn?) kommentieren. Ich werde versuchen euch Rede und Antwort zu stehen.

    -----------------------------------------------------------------------------------------------------------------------------------------------------------

    Allgemeines:

    Auch wenn ich versuchen möchte, diesen Blog möglichst kontinuerlich mit Inhalt zu füllen, kann es durchaus vorkommen, dass ich auch über längere Zeiträume hinweg nichts von mir hören lasse, da ich selbst auch nicht immer die hierfür benötigte Zeit aufwenden kann.

    Ich hoffe, dass dieser erste Einblick den ein oder anderen hier interessiert. Auf Anfrage kann ich eventuell auch eine erste Vorab-Dokumentation veröffentlichen, die einige Teilbereiche des Projektes dokumentiert. Allerdings ist diese Dokumentation noch relativ spärlich in ihren Ausmaßen, weshalb ich sie bisher auch noch nicht veröffentlicht habe. Sollte aber Interesse bestehen, bin ich gerne bereit, dies zu tun.

     

    Liebe Grüße,

    ~ EuadeLuxe / EuaconLabs ~


    Kommentare: 1