Ich möchte eine riesige Weltkarte entwickeln. mindestens 8000 × 6000 Pixel groß. Ich habe es in ein 10 × 10-Raster von 800 × 600-Pixel-PNG-Bildern aufgeteilt. Um zu vermeiden, dass alles in den Speicher geladen wird, sollten die Bilder abhängig von der Position des Players im Raster geladen und entfernt werden.
Hier ist zum Beispiel der Spieler an der Position (3,3)
:
Während er sich nach rechts bewegt (4,3)
, werden die drei Bilder ganz links freigegeben, während die drei Bilder rechts zugewiesen werden:
In jeder Zelle des Gitters sollte sich wahrscheinlich ein Schwellenwert befinden, der das Laden und Entladen auslöst. Das Laden sollte wahrscheinlich in einem separaten Thread erfolgen.
Wie entwerfe ich ein solches System?
Antworten:
Hier sind einige Probleme zu lösen. Die erste ist das Laden und Entladen von Kacheln. Mit dem ContentManager können Sie standardmäßig keine bestimmten Inhalte entladen. Eine benutzerdefinierte Implementierung davon wird jedoch:
Die zweite Frage ist, wie Sie entscheiden, welche Kacheln geladen und entnommen werden sollen. Folgendes würde dieses Problem lösen:
Die letzte Frage ist, wie zu entscheiden ist, wann geladen und entladen werden soll. Dies ist wahrscheinlich der einfachste Teil. Dies kann einfach in der Update () -Methode durchgeführt werden, sobald die Bildschirmposition des Players bestimmt wurde:
Natürlich müssten Sie auch die Kacheln zeichnen, aber wenn Sie tileWidth, tileHeight und das Array Tiles [] angeben, sollte dies trivial sein.
quelle
Was Sie tun möchten, ist ziemlich verbreitet. Ein nettes Tutorial zu dieser und anderen gebräuchlichen Techniken finden Sie in dieser Kachel-Engine-Serie .
Wenn Sie so etwas noch nicht gemacht haben, empfehle ich Ihnen, sich die Serie anzuschauen. Wenn Sie jedoch möchten, können Sie den Code für die letzten Lernprogramme abrufen. Wenn Sie dies später tun, überprüfen Sie die Zeichenmethode.
Kurz gesagt, Sie müssen Ihre minimalen und maximalen X / Y-Punkte um den Spieler herum finden. Sobald Sie das haben, durchlaufen Sie einfach jedes und zeichnen dieses Plättchen.
Wie Sie sehen, ist viel los. Sie benötigen eine Kamera, die Ihre Matrix erstellt. Sie müssen Ihre aktuelle Pixelposition in einen Kachelindex umwandeln. Sie finden Ihre Min / Max-Punkte (ich füge ein wenig zu meinem MAX hinzu, damit es ein wenig über den sichtbaren Bildschirm hinausgeht ), und dann können Sie es zeichnen.
Ich schlage wirklich vor, die Tutorialserie anzuschauen. Er behandelt Ihr aktuelles Problem, wie Sie einen Kacheleditor erstellen, den Player in Grenzen halten, Sprite-Animationen, KI-Interaktionen usw.
Nebenbei bemerkt, TiledLib hat dies eingebaut. Sie könnten auch deren Code studieren.
quelle
Ich habe für mein aktuelles Projekt an etwas sehr Ähnlichem gearbeitet. Dies ist ein kurzer Überblick darüber, wie ich es mache, mit einigen Randnotizen, wie man es sich ein bisschen einfacher machen kann.
Für mich bestand das erste Problem darin, die Welt in kleinere Teile zu zerlegen, die sich zum Laden und Entladen im Handumdrehen eignen. Da Sie eine kachelbasierte Karte verwenden, wird dieser Schritt erheblich einfacher. Anstatt die Positionen der einzelnen 3D-Objekte in der Ebene zu berücksichtigen, ist die Ebene bereits in Kacheln unterteilt. Auf diese Weise können Sie die Welt einfach in X-mal-Y-Kacheln aufteilen und diese laden.
Sie möchten dies automatisch und nicht von Hand tun. Da Sie XNA verwenden, haben Sie die Möglichkeit, die Inhaltspipeline mit einem benutzerdefinierten Exporter für Ihre Level-Inhalte zu verwenden. Sofern Sie keine Möglichkeit kennen, den Exportvorgang ohne Neukompilierung auszuführen, würde ich ehrlich davon abraten. Zwar ist das Kompilieren von C # nicht annähernd so langsam wie in C ++, dennoch müssen Sie Visual Studio nicht jedes Mal laden und Ihr Spiel neu kompilieren, wenn Sie eine geringfügige Änderung an der Map vornehmen.
Ein weiterer wichtiger Punkt ist, sicherzustellen, dass Sie eine gute Namenskonvention für die Dateien verwenden, die die Chunks Ihres Levels enthalten. Sie möchten wissen, dass Sie Block C laden oder entladen möchten, und dann den Dateinamen generieren, den Sie laden müssen, um dies zur Laufzeit zu tun. Denken Sie abschließend an Kleinigkeiten, die Ihnen später helfen könnten. Es ist wirklich schön, die Größe eines Blocks ändern zu können, erneut zu exportieren und dann die Auswirkungen auf die Leistung sofort zu sehen.
Zur Laufzeit ist es immer noch ziemlich einfach. Sie benötigen eine Möglichkeit, Blöcke asynchron zu laden und zu entladen. Dies hängt jedoch stark von der Funktionsweise Ihres Spiels oder Ihrer Engine ab. Ihr zweites Bild ist genau richtig - Sie müssen bestimmen, welche Chunks geladen oder entladen werden sollen, und die entsprechenden Anforderungen stellen, um dies zu tun, falls dies noch nicht geschehen ist. Je nachdem, wie viele Blöcke Sie gleichzeitig geladen haben, können Sie dies immer dann tun, wenn der Spieler eine Grenze von einem Block zum nächsten überschreitet. Schließlich möchten Sie so oder so sicherstellen, dass auch in der schlechtesten (angemessenen) Ladezeit der Block noch geladen ist, bevor der Player ihn sehen kann. Sie werden wahrscheinlich viel mit dieser Zahl spielen wollen, bis Sie ein ausgewogenes Verhältnis zwischen Leistung und Speicherverbrauch gefunden haben.
In Bezug auf die tatsächliche Architektur möchten Sie den Vorgang des tatsächlichen Ladens und Entladens der Daten aus dem Speicher von dem Vorgang des Bestimmens, was geladen / entladen werden soll, abstrahieren. Bei Ihrer ersten Iteration würde ich mir nicht einmal Gedanken über die Leistung beim Laden / Entladen machen und nur das Einfachste holen, das möglicherweise funktioniert, und sicherstellen, dass Sie die entsprechenden Anforderungen zu den entsprechenden Zeiten generieren. Anschließend können Sie das Laden optimieren, um den Müll zu minimieren.
Ich habe aufgrund der von mir verwendeten Engine eine Menge zusätzlicher Komplexität erlebt, aber das ist ziemlich implementierungsspezifisch. Wenn Sie Fragen zu meiner Arbeit haben, kommentieren Sie diese bitte und ich werde alles tun, um Ihnen zu helfen.
quelle