Wie verwalten Sie Ihre Spielressourcen in XNA?

7

In der Vergangenheit habe ich Content.Load<type>("filename");überall verwendet . Dies wird schnell zu einem Albtraum und schlimmer noch, wenn Sie mehrere Kopien desselben Assets an verschiedenen Orten laden.

Dann habe ich eine Resources-Klasse verwendet, die im Grunde wie folgt aussah:

public class Resources
{
    public static Texture2D particle01;
    ...
    public static Texture2D particle93;

    public static Effect shader01;
    ...
    public static Effect shader32;

    public static Load(ContentManager content, GraphicsDevice device)
    { //load all the resources }

    public static Unload()
    { //unload all the resources }
}

Dann könnte ich einfach verwenden Resources.particle01, um von überall im selben Namespace einen Verweis auf die Ressource zu erhalten.

Dies war ein guter Ansatz, da dadurch die Duplikate beseitigt wurden, die ich in der Vergangenheit hatte. Außerdem wurde das gesamte Laden in einer einzigen Klasse durchgeführt, sodass die Ressourcen leicht im Auge behalten werden konnten. Und schließlich könnte ich zum Beispiel einfach mit der rechten Maustaste klicken particle93und auf Alle Referenzen suchen klicken, um alle Stellen zu finden, an denen diese Textur verwendet wurde.

Es gibt jedoch Probleme mit diesem Ansatz und ich würde gerne wissen, ob es da draußen eine bessere Lösung gibt.

Radenon
quelle

Antworten:

8

Zunächst einmal lädt der XNA-Content-Manager nicht zweimal dasselbe Asset, sondern gibt nur eine Referenz zurück, wenn bereits etwas geladen wurde.

Was Ihren Ressourcenansatz betrifft, weiß ich nicht, ob dies wirklich der richtige Weg ist, da Sie Ihre Inhaltsressourcen im Grunde genommen hart in Ihr Spiel codieren.

Eine mögliche Lösung für Ihr Problem wäre das Fabrikmuster. Angenommen, Sie möchten eine Ebene laden, die als XML gespeichert ist. Sie laden die XML-Datei und die Ebene, indem Sie LevelFactory.Construct (xml) ausführen. Diese Factory überprüft die XML-Datei, lädt alle mit dieser Ebene verknüpften Assets und stellt sie in die Welt. Unterteile der Welt wie NPCs könnten von der Level-Factory erstellt werden, indem die NPC-Factory aufgerufen und ein Teil der XML-Datei übergeben wird, damit die NPC-Factory weiß, welche Texturen und Modelle geladen werden müssen.

Mit diesem Ansatz erhalten Sie eine "kaskadierende Reihe" von Fabriken, die alle datengesteuert sind, sodass Sie eine klare Trennung zwischen Inhalt (der XML-Datei und den Dateien, auf die in der XML-Datei verwiesen wird) und Code (den Fabriken) vornehmen können. Halten Sie den Ladecode für Inhalte weiterhin vom anderen Code fern. Sie müssen jetzt nicht mehr Player = neuer Player (TexturA, TexturB, TexturC); Sie können die Fabrik auch einfach nach einem neuen Spieler fragen und der Rest wird herausgefunden.

Tipp: Sie können immer einige Methoden für Standardobjekte verwenden oder einen Fallback durchführen, wenn im XML nichts angegeben ist.

Hoffe das hilft!

Roy T.
quelle
3

Ich habe FlatRedBall verwendet, das ein erstaunliches Konzept von Bildschirmen hat. Anstatt sich Gedanken über das Laden / Entladen von Texturen zu machen, schreiben Sie stattdessen Code wie:

Sprite s = this.addSprite("spaceship");

Und es wird den Inhaltslebenszyklus für Sie abwickeln. Ich verwende diesen Ansatz auch in meinem eigenen Framework, Radiant Wrench. Ich finde, dass es das Management auf ein Minimum beschränkt und Ihnen einfach aus dem Weg geht.

Der Code zum Verwalten von Sprites ist nicht so trivial (für den Anfang benötigen Sie eine Sprite- und eine Screen-Klasse). Ich würde daher empfehlen, FRB oder RW auszuprobieren. Sie werden immer davon profitieren, neue Wege zu lernen, um Dinge zu tun (manchmal bessere Wege).

Asche999
quelle
2

Dies mag einigen ungünstig erscheinen, aber ich neige dazu, meine Ressourcen lokal im GameState zu halten, der sie benötigt, und jeder GameState verfügt über eine Art ResourcePool. Dies ist eine gute Möglichkeit, Level-Assets getrennt zu halten, da ich keine Menühintergründe benötige. Ihre Resources-Klasse wird besser als Struktur verwendet, und der GameState ist für das Laden und Entladen verantwortlich.

Ein Teil des Ressourcenmanagements in XNA hängt teilweise davon ab, wie Sie Ihre Inhalte überhaupt importieren. Viele Benutzer binden Texturen und Effekte in der Inhaltsverarbeitungsphase des Builds an ihre Modelle, sodass sie nur noch Netze verwalten können und der Rest bereits darin referenziert ist.

Sie scheinen den klassischeren "Mix and Combine" -Ansatz zu wählen, um mehr Flexibilität zu erhalten. Daher benötigen Sie einen Ansatz, der die zugrunde liegende Arbeit in den Schatten stellt und den Code schneidet, den Sie auf lange Sicht schreiben müssen. Ich habe FlatRedBall nicht verwendet, aber nach dem, was ich aus der hier beschriebenen Kurzbeschreibung ersehen kann, klingt es wie das Lazy Loading- Muster. Dies ist ein Konzept, das es wert ist, untersucht zu werden, wenn Sie Ihr Leben durch die Verwaltung vieler Ressourcen erleichtern möchten.

ChrisC
quelle
Kleiner Kommentar, eine Struktur, die Verweise auf Nicht-Werttypen enthält, hat wenig Verwendung.
Roy T.
1

Ich benutze eine öffentliche statische Klasse namens Assets. Es enthält Wörterbücher für jede Art von Asset, Modell, Effekt, Spritefonts usw., verfügt über eine Ladefunktion, in der im Inhaltsordner nach Ordnern wie "Texturen", "Modellen" usw. gesucht und alle Assets geladen werden. Wenn ich dann ein Asset aufrufen möchte, verwende ich einfach so etwas wie Assets.Textures ["SpriteSheetX"];

Ich weiß nicht, ob dies eine schlechte Praxis ist, aber es ist sehr einfach. Ich gebe meistens nur Zeichenfolgen des Dateinamens weiter und tief im Kern wird das Asset aus Assets geladen.

Theodore Enderby
quelle