Wie kann eine Kachelkarte effizient im Web gespeichert und angezeigt werden?

9

Über

Dies sind eigentlich zwei Fragen in einer. Zunächst suche ich nach einer Möglichkeit, große Mengen an Kacheldaten effizient zu speichern. Der andere Aspekt betrifft das Abfragen des Datensatzes und das Anzeigen von Kacheln. Lassen Sie mich zunächst einige Hintergrundinformationen geben.

Wir erstellen ein browserbasiertes Multiplayer-Tycoon-Spiel, das die CraftyJS-Bibliothek verwendet, um es auf Canvas zu rendern. Im Hintergrund der GUI führen wir Yii Framework auf PHP aus und alles verbindet sich mit einem Python Random Map Generator und einer Game Engine.

So sieht das erste grobe Karten-Rendering aus: http://i.imgur.com/khAXtl.png

Speichern der Kartendaten

Die Spielwelt wird bei jedem Spielstart zufällig generiert. Die Größe beträgt 100x100 sechseckige Plättchen für jeden Spieler. Das bedeutet, dass für ein Spiel mit drei Spielern 90.000 Kacheln erstellt werden. Derzeit erstelle ich nur ein JavaScript-Array, aus dem ich die Karte rendere.

Dies funktioniert gut für das Rendern, aber für jede Art von Interaktion mit der Karte müssen wir speichern, welcher Spieler die Kachel besitzt, welche Art von Struktur darauf aufgebaut ist, wie hoch der aktuelle Preis ist und so weiter. Zumindest für den Prototyp wollten wir zunächst MySQL verwenden, aber nach einigen Tests ist es nicht genau so schnell, wie ich es gerne hätte. Möglicherweise ist ein Objektspeicher wie MongoDB besser zum Speichern von Kacheldaten anstelle einer SQL-Tabelle geeignet. Oder vielleicht noch etwas?

Karte anzeigen

Ein weiteres Problem, das ich sehe, ist das Bewegen auf der Karte. Derzeit erstelle ich Crafty-Objekte für jede Kachel, auch wenn sie sich nicht im Ansichtsfenster befindet. Dies ist langsam, da Crafty zwar nur die im Ansichtsfenster rendert, jedoch alle Kacheln jedes Renderereignisses speichert und möglicherweise durchläuft. Was ich derzeit habe, ist eine gezeichnete generierte Karte, die sehr langsam geladen wird und stottert, wenn Sie sich bewegen. Jetzt möchte ich sie spielbar machen.

Meine erste Idee war, die angezeigte Teilmenge der Kacheln zu laden, die sich im Ansichtsfenster befinden. Wenn ein Spieler das Ansichtsfenster in einen leeren Bereich verschiebt, muss er den Server abfragen und auf die Antwort warten. Erst dann kann die Karte gerendert werden. Dies wäre in einer nativen Anwendung in Ordnung, in einem Web-Spiel jedoch verzögert.

Die Möglichkeit, eine reibungslose Leistung der Karte zu erzielen, besteht darin, eine größere Teilmenge von Kacheln in ein Javascript-Array vorzuladen und als Cache zu verwenden. Der Spieler würde ein paar Bildschirme "zwischengespeichert" haben und wenn er das Ansichtsfenster verschiebt, würde ich mehr Kacheln in den JS "Cache" laden.

Bin ich auf dem richtigen Weg? Ich würde gerne mehr Informationen von jemandem bekommen, der etwas Ähnliches getan hat. Ich bin neu in der Spieleentwicklung, habe aber in den letzten Wochen viele Quellen durchgesehen.

Element
quelle
1
Ich bin überrascht, dass Sie MySQL als Engpass identifiziert haben. Was haben Sie getestet, um zu dem Schluss zu kommen, dass es die Dinge verlangsamt?
Bummzack
@bummzack Wenn er eine Reihe pro Fliese hat, kann ich kaum sehen, wie die Dinge nicht langsam sein können.
aaaaaaaaaaaa
1
@eBusiness Das Abfragen von einigen tausend Zeilen aus einer Datenbank sollte eigentlich kein Problem sein. Dies sollte immer noch im Bereich von einigen Millisekunden liegen. Es wären auch nicht 90'000 Reihen, sondern 30'000 Reihen für 3 Spieler (100x100 pro Spieler).
Bummzack
Entschuldigen Sie die verwirrende Mathematik, es gibt neben der Spielerzone auch den doppelten Abstand zwischen den Spielern, so dass sie gleich weit voneinander entfernt sind, was 90 km ergibt. Abfragen ist kein Problem. Das Auswählen von 90.000 Kacheln und das Erstellen einer Karte ist. Aber es ist kein guter Weg, es zu tun. Ich werde die Kartendaten serialisieren und die Kacheln in der Datenbank abfragen, wenn detaillierte Informationen angefordert werden.
Element

Antworten:

2

Gameplay
Zunächst möchte ich Sie fragen, ob Sie tatsächlich 10000 Plättchen pro Spieler benötigen. Obwohl ich nicht weiß, welche Art von Spiel Sie machen, ist es im Allgemeinen wahr, dass große Karten lange Spiele machen. Die größte Karte in Civilization 5 besteht aus 10240 Plättchen, und das funktioniert nur, weil Sie nicht mehr als einen Bruchteil davon spielen müssen.

Datenbank
Sie sollten nicht versuchen, ein Spiel wie dieses aus einer Datenbank heraus auszuführen. Sie müssen die Daten im Anwendungsspeicher behalten. Sie können eine Datenbank verwenden, um das Spiel zu sichern. Speichern Sie für eine vollständige Sicherung eine Serialisierung der Spieldaten. Anschließend können Sie diese erhöhen, indem Sie die erteilten Befehle speichern und diese erneut ausführen, wenn die Sicherung verwendet werden muss.

JavaScript-Speicher
Was den Client betrifft, würde ich sagen, dass Sie die gesamte Karte besser geladen lassen sollten, zumindest wenn Sie sich an die Millionen Kacheln halten, die alles in einem schönen Objektbaum haben, könnte dies etwas zu viel sein, daher sollten Sie die Daten wahrscheinlich behalten in einem "semi-binären" codierten Format. Strings eignen sich hervorragend für diese Art von Dingen. Alternativ können Sie vorzeichenlose Ganzzahlen bis zu 53 Bit sicher in einem 64-Bit-Float speichern, viele davon in einem Array und ich denke, Sie werden einen ziemlich bescheidenen Speicherbedarf sehen.

JavaScript-Visualisierung
Obwohl ich nicht sagen möchte, dass Sie Canvas nicht unbedingt verwenden sollten, benötigen Sie es für solche Dinge eigentlich nicht. Richten Sie alles als eine Reihe von img-Elementen ein und ändern Sie die src-Eigenschaft, um verschiedene Teile der Karte anzuzeigen.

Pro-Tipp
Übrigens ist es manchmal einfacher, den für die Generierung verwendeten Startwert freizugeben, als die gesamte Karte freizugeben.

aaaaaaaaaaaa
quelle
+1, aber leider hat eine in PHP geschriebene Web-App normalerweise keine Möglichkeit, den Spielstatus im Speicher zu halten.
Bummzack
@bummzack, Ahh, richtig, ich glaube, ich habe das Wort PHP irgendwie übersprungen und einfach Python gelesen. Dann könnte eine Änderung des Backend-Frameworks angebracht sein. Node.js könnte eine Option sein.
aaaaaaaaaaaa
Ich baue einen wettbewerbsfähigen Transport-Tycoon, denke an OpenTTD, eine Karte mit der Größe von 512 x 512 (262 KB) ist für ein paar Spieler nicht so groß. Mir ist klar, dass es ehrgeizig ist, aber wenn die Karte nicht so groß ist, würde das Spiel zu früh enden. Da es sich um ein Multiplayer-Spiel handelt, muss ich die Änderungen an der Karte zwischen den Spielern synchronisieren. Mein erster Instinkt war, einfach die Konzepte zu verwenden, die ich aus der Webentwicklung kenne, und mich für eine Datenbank zu entscheiden. Es muss nicht super Echtzeit sein. Ich gehe mit JS-Visualisierung, weil ich dynamische Dinge auf der Karte haben möchte.
Element
Betrachten Sie meine Antwort als einige Hinweise. Am Ende müssen Sie die Leistung selbst herausarbeiten, es ist ein ernstes Problem, und Sie müssen möglicherweise einige Kompromisse eingehen.
aaaaaaaaaaaa
Ich stimme zu, Ihre Antwort gab mir viele Denkanstöße. Ich werde versuchen, einen Weg zu finden, um serialisierte Kartendaten im Speicher zu halten und die Datenbank als Backup zu behalten. Aber dann muss ich herausfinden, wie ich Änderungen zwischen den Spielern teilen kann. Ich werde mit dem, was ich mir ausgedacht habe, zurückkommen, nachdem ich einige weitere Tests durchgeführt habe.
Element
1

MySQL ist nicht langsam. Höchstwahrscheinlich führen Sie naive Abfragen durch oder haben nicht optimale Indizes. NoSQL-Ansätze wie MongoDB sind möglicherweise schneller, möglicherweise auch nicht. Hier kommt es wirklich auf Ihr Zugriffsmuster und die Wahl der Abfrage an. Es ist möglich, Ratschläge zur Verbesserung der Leistung zu geben, aber nicht ohne zu sehen, was Sie bereits tun.

Die Möglichkeit, eine reibungslose Leistung der Karte zu erzielen, besteht darin, eine größere Teilmenge von Kacheln in ein Javascript-Array vorzuladen und als Cache zu verwenden.

Ja, sicher. Hier gibt es nicht viel hinzuzufügen - der Client fordert vom Server Kacheln an, sodass Sie nur sicherstellen müssen, dass die Kacheln, die Sie anfordern, einen Bereich abdecken, der größer als der Bildschirm ist.

Nachtrag:

Wir führen Yii Framework auf PHP aus und alles verbindet sich mit einem Python Random Map Generator und einer Game Engine.

Wenn Sie mit Python vertraut sind, würde ich Ihnen raten, den PHP-Mittelsmann loszuwerden. Wenn Sie Ihr Spiel als Python-Prozess ausführen, können Sie Ihre Kacheldaten viel einfacher im Speicher behalten und die MySQL-Zugriffe erheblich reduzieren. Es hilft, dass Python auch eine viel vernünftigere Sprache als PHP ist.

Kylotan
quelle