Also mache ich ein HTML5-RPG nur zum Spaß. Die Karte ist eine <canvas>
(512 Pixel breite, 352 Pixel hohe | 16 Kacheln breite, 11 Kacheln von oben nach unten). Ich möchte wissen, ob es eine effizientere Methode zum Malen gibt <canvas>
.
So habe ich es gerade.
Wie Kacheln auf die Karte geladen und gemalt werden
Die Karte wird von Fliesen (32x32) mit dem Image()
Stück gemalt . Die Bilddateien werden über eine einfache for
Schleife geladen und in einem Array tiles[]
abgelegt, das bei Verwendung von PAINTED aufgerufen wird drawImage()
.
Zuerst laden wir die Fliesen ...
und so wird's gemacht:
// SET UP THE & DRAW THE MAP TILES
tiles = [];
var loadedImagesCount = 0;
for (x = 0; x <= NUM_OF_TILES; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "js/tiles/t" + x + ".png";
imageObj.onload = function () {
console.log("Added tile ... " + loadedImagesCount);
loadedImagesCount++;
if (loadedImagesCount == NUM_OF_TILES) {
// Onces all tiles are loaded ...
// We paint the map
for (y = 0; y <= 15; y++) {
for (x = 0; x <= 10; x++) {
theX = x * 32;
theY = y * 32;
context.drawImage(tiles[5], theY, theX, 32, 32);
}
}
}
};
tiles.push(imageObj);
}
Wenn ein Spieler ein Spiel startet, lädt er natürlich die Karte, die er zuletzt verlassen hat. Aber für hier ist es eine reine Graskarte.
Derzeit verwenden die Karten 2D-Arrays. Hier ist eine Beispielkarte.
[[4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 1, 1, 1],
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 13, 13, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 1],
[13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 13, 1],
[1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1]];
Ich bekomme verschiedene Karten mit einer einfachen if
Struktur. Sobald das 2d-Array oben angezeigt wird return
, wird die entsprechende Nummer in jedem Array entsprechend dem darin Image()
gespeicherten gemalt tile[]
. Dann drawImage()
wird es passieren und malen nach dem x
und y
und mal indem 32
man auf die richtige x-y
Koordinate malt .
Wie mehrfache Kartenumschaltung erfolgt
Mit meinem Spiel Karten hat fünf Dinge im Auge zu behalten: currentID
, leftID
, rightID
, upID
, und bottomID
.
- currentID: Die aktuelle ID der Karte, auf der Sie sich befinden.
- leftID: Welche ID
currentID
soll geladen werden, wenn Sie auf der linken Seite der aktuellen Karte beenden . - rightID: Welche ID
currentID
soll geladen werden, wenn Sie auf der rechten Seite der aktuellen Karte beenden . - downID: Welche ID
currentID
soll geladen werden, wenn Sie am unteren Rand der aktuellen Karte beenden . - upID: Welche ID
currentID
soll geladen werden, wenn Sie am oberen Rand der aktuellen Karte beenden .
Etwas zu Anmerkung: Wenn entweder leftID
, rightID
, upID
, oder bottomID
ist nicht spezifisch, das heißt sie ein sind 0
. Das bedeutet, dass sie diese Seite der Karte nicht verlassen können. Es ist nur eine unsichtbare Blockade.
Sobald eine Person eine Seite der Karte verlässt, hängt es davon ab, wo sie sie verlassen hat. Wenn sie beispielsweise unten die Karte verlassen hat, bottomID
wird die Nummer der map
zu ladenden Person auf die Karte gezeichnet.
Hier ist ein gegenständliches .GIF, mit dem Sie sich besser vorstellen können:
Wie Sie sehen, beschäftige ich mich früher oder später mit vielen Karten mit vielen IDs. Und das kann möglicherweise etwas verwirrend und hektisch werden.
Die offensichtlichen Vorteile sind, dass 176 Kacheln gleichzeitig geladen, eine kleine 512x352-Zeichenfläche aktualisiert und jeweils eine Karte verarbeitet werden. Der Nachteil ist, dass die MAP-IDs beim Umgang mit vielen Maps manchmal verwirrend sein können.
Meine Frage
- Ist dies eine effiziente Methode zum Speichern von Karten (bei Verwendung von Kacheln), oder gibt es eine bessere Methode zum Behandeln von Karten?
Ich dachte an eine riesige Karte. Die Karte ist groß und es ist alles ein 2D-Array. Das Ansichtsfenster hat jedoch immer noch eine Größe von 512 x 352 Pixel.
Hier ist eine weitere .gif-Datei, die ich (für diese Frage) erstellt habe, um sie zu visualisieren:
Entschuldigung, wenn Sie mein Englisch nicht verstehen können. Bitte fragen Sie alles, was Sie nicht verstehen können. Hoffentlich habe ich es klar gemacht. Vielen Dank.
quelle
Antworten:
Bearbeiten: Ich habe gerade gesehen, dass meine Antwort auf Ihrem Code basiert, aber Ihre Frage nicht wirklich beantwortet hat. Ich habe die alte Antwort behalten, falls Sie diese Informationen verwenden können.
Edit 2: Ich habe 2 Probleme mit dem Originalcode behoben: - Die +1-Addition in der Berechnung von Ende x und y war versehentlich in den Klammern, muss aber nach der Division hinzugefügt werden. - Ich habe vergessen, die x- und y-Werte zu validieren.
Sie könnten einfach die aktuelle Karte im Speicher haben und die umgebenden Karten laden. Stellen Sie sich eine Welt vor, die aus einem 2D-Array von einzelnen Ebenen der Größe 5x5 besteht. Der Spieler beginnt in Feld 1. Da sich die obere und die linke Grenze des Levels am Rand der Welt befinden, müssen sie nicht geladen werden. In diesem Fall ist Level 1/1 aktiv und Level 1/2 und 2/1 werden geladen ... Wenn der Spieler sich jetzt nach rechts bewegt, werden alle Level (außer dem, zu dem Sie sich bewegen) entladen und die neue Umgebung wird geladen geladen. Mittelstufe 2/1 ist jetzt aktiv, 1/1, 2/2 und 3/1 sind jetzt geladen.
Ich hoffe, das gibt Ihnen eine Idee, wie es gemacht werden könnte. Dieser Ansatz wird jedoch nicht sehr gut funktionieren, wenn jedes Level während des Spiels simuliert werden muss. Aber wenn Sie nicht verwendete Ebenen einfrieren können, sollte dies gut funktionieren.
Alte Antwort:
Beim Rendern der Ebene (auch kachelbasiert) berechne ich, welche Elemente aus dem Kachelarray das Ansichtsfenster schneiden, und rendere dann nur diese Kacheln. So können Sie große Karten haben, müssen aber nur den Teil auf dem Bildschirm rendern.
Hinweis: Der obige Code ist nicht getestet, sollte aber eine Idee geben, was zu tun ist.
Nachstehend ein einfaches Beispiel für eine Ansichtsfensterdarstellung:
Eine Javascript-Darstellung würde so aussehen
Wenn Sie mein Codebeispiel nehmen, müssen Sie einfach die int- und float-Deklarationen durch var ersetzen. Stellen Sie außerdem sicher, dass Sie Math.floor für die Berechnungen verwenden, die den int-basierten Werten zugewiesen sind, um dasselbe Verhalten zu erzielen.
Eine Sache, die ich in Betracht ziehen würde (obwohl ich nicht sicher bin, ob dies in Javascript von Bedeutung ist), ist, alle Kacheln (oder so viele wie möglich) in einer großen Textur zu platzieren, anstatt viele einzelne Dateien zu verwenden.
Hier ist ein Link, der erklärt, wie es geht: http://thiscouldbebetter.wordpress.com/2012/02/25/slicing-an-image-into-tiles-in-javascript/
quelle
640, 480
.. aber es kann512, 352
richtig funktionieren ?Das Speichern von Karten als Kacheln ist nützlich, damit Sie Assets wiederverwenden und die Karte neu gestalten können. Realistisch gesehen bietet es dem Spieler nicht wirklich viel Nutzen. Außerdem zeichnen Sie jedes Mal eine neue Kachel. Folgendes würde ich tun:
Speichern Sie die gesamte Karte als ein großes Array. Es hat keinen Sinn, Karten und Submaps sowie potenzielle Sub-Sub-Karten zu haben (wenn Sie beispielsweise Gebäude betreten). Sie laden sowieso alles und das hält alles schön und einfach.
Rendern Sie die Karte auf einmal. Haben Sie eine Leinwand außerhalb des Bildschirms, auf der Sie die Karte rendern, und verwenden Sie diese dann in Ihrem Spiel. Diese Seite zeigt Ihnen, wie Sie dies mit einer einfachen Javascript-Funktion tun können:
Dies setzt voraus, dass sich an Ihrer Karte nicht viel ändert. Wenn Sie Unterkarten an Ort und Stelle rendern möchten (z. B. das Innere eines Gebäudes), rendern Sie diese einfach auch auf einer Zeichenfläche und zeichnen sie dann oben auf. Hier ist ein Beispiel, wie Sie dies zum Rendern Ihrer Karte verwenden können:
Dadurch wird ein kleiner Teil der Karte zentriert gezeichnet
mapCentreX, mapCentreY
. Auf diese Weise können Sie reibungslos über die gesamte Karte scrollen und Bewegungen unter den Kacheln ausführen. Sie können die Position des Spielers als 1 / 32stel einer Kachel speichern, um eine reibungslose Bewegung über die Karte zu erzielen (ganz klar, wenn Sie möchten) Bewegen Sie Kacheln für Kacheln, um eine stilistische Auswahl zu treffen.Sie können Ihre Karte nach wie vor zerlegen, wenn Sie möchten oder wenn Ihre Welt riesig ist und auf Ihren Zielsystemen nicht in den Arbeitsspeicher passt (denken Sie daran, dass eine 512 x 352-Karte selbst für 1 Byte pro Pixel 176 KB groß ist), aber vorab - Wenn Sie Ihre Karte so rendern, werden Sie in den meisten Browsern einen großen Leistungsgewinn feststellen .
Dies gibt Ihnen die Flexibilität, Kacheln auf der ganzen Welt wiederzuverwenden, ohne dass Sie ein großes Bild bearbeiten müssen. Sie können dies jedoch auch schnell und einfach ausführen und nur eine "Karte" (oder so viele "Karten", wie Sie möchten) berücksichtigen. .
quelle
In allen Implementierungen, die ich gesehen habe, werden Kachelkarten oft als ein großes Bild erzeugt und dann in kleinere Stücke "zerlegt".
https://gamedev.stackexchange.com/a/25035/10055
Diese Chunks haben normalerweise Potenzen von 2, sodass sie optimal in den Speicher passen.
quelle
Eine einfache Möglichkeit, den Überblick über die IDs zu behalten, besteht darin, einfach ein anderes 2D-Array mit diesen IDs zu verwenden: Indem Sie nur x, y in diesem "Meta-Array" beibehalten, können Sie die anderen IDs problemlos nachschlagen.
Abgesehen davon ist hier Googles Version von 2D-Spielen auf Kacheln (nun ja, eigentlich HTML5-Multiplayer, aber die Kachel-Engine wird auch behandelt) aus dem letzten I / O 2012: http://www.youtube.com/watch?v=Prkyd5n0P7k It hat auch Quellcode zur Verfügung.
quelle
Ihre Idee, die gesamte Karte zuerst in ein Array zu laden, ist ein effizienter Weg, aber es wird einfach sein, JavaScript Injection'd zu erhalten. Jeder kann die Karte kennen und los geht das Abenteuer.
Ich arbeite auch an einem Web-basierten RPG-Spiel. Ich lade meine Karte über Ajax von einer PHP-Seite, die die Karte aus der Datenbank lädt, in der die X-, Y-, Z-Position und der Wert angegeben sind Zeichnen Sie das Plättchen und bewegen Sie den Spieler.
Ich arbeite immer noch daran, es effizienter zu machen, aber die Karte wird schnell genug geladen, um es bis jetzt so zu halten.
quelle
Nein , ein Array ist die effizienteste Methode zum Speichern einer Kachelkarte .
Es kann einige Strukturen geben, die etwas weniger Speicher benötigen, jedoch nur auf Kosten der wesentlich höheren Kosten für das Laden und den Zugriff auf die Daten.
Was jedoch berücksichtigt werden muss, ist, wann Sie die nächste Karte laden werden. Angesichts der Tatsache, dass die Karten nicht besonders groß sind, wird es am längsten dauern, bis der Server die Karte bereitstellt. Das eigentliche Laden dauert nur wenige Millisekunden. Aber dieses Warten kann asynchron erfolgen, es muss nicht den Spielfluss blockieren. Das Beste ist also, die Daten nicht bei Bedarf, sondern vorher zu laden. Der Spieler befindet sich in einer Karte, jetzt laden Sie alle angrenzenden Karten. Der Spieler bewegt sich in der nächsten Karte, lädt alle angrenzenden Karten erneut usw. usw. Der Spieler bemerkt nicht einmal, dass Ihr Spiel im Hintergrund geladen wird.
Auf diese Weise können Sie auch die Illusion einer Welt ohne Grenzen erzeugen, indem Sie auch die angrenzenden Karten zeichnen. In diesem Fall müssen Sie jedoch nicht nur die angrenzenden Karten, sondern auch die angrenzenden Karten laden.
quelle
Ich bin mir nicht sicher, warum Sie denken: Wie Sie sehen, werde ich früher oder später mit vielen Karten mit vielen Ausweisen zu tun haben. Und das kann möglicherweise etwas verwirrend und hektisch werden.
Die LeftID ist immer -1 der CurrentID, die RightID ist immer +1 der CurrentID.
Die UpID ist immer - (gesamte Kartenbreite) der aktuellen ID und die DownID ist immer + (gesamte Kartenbreite) der aktuellen ID, mit Ausnahme von Null, was bedeutet, dass Sie die Kante erreicht haben.
Eine einzelne Karte kann in mehrere Karten unterteilt werden und wird nacheinander mit mapIDXXXX gespeichert, wobei XXXX die ID ist. Auf diese Weise gibt es nichts zu verwechseln. Ich war auf Ihrer Website und es scheint, dass ich mich irren könnte, dass das Problem an Ihrem Karteneditor liegt, der eine Größenbeschränkung auferlegt, die Ihre Automatisierung daran hindert, eine große Karte beim Speichern in mehrere kleine zu zerlegen, und diese Einschränkung ist wahrscheinlich eine technische Lösung einschränken.
Ich habe einen Javascript-Karteneditor geschrieben, der in alle Richtungen scrollt, 1000 x 1000 (ich würde diese Größe nicht empfehlen) Kacheln und es bewegt sich immer noch so gut wie 50 x 50 Karten und das mit 3 Ebenen einschließlich Parallaxen-Scrolling. Es speichert und liest im json-Format. Ich sende Ihnen eine Kopie, wenn Sie sagen, dass Ihnen eine E-Mail von ca. 2meg nichts ausmacht. Es soll auf Github sein, aber ich habe kein anständiges (legales) Kachelset, weshalb ich mich noch nicht darum gekümmert habe, es dort anzubringen.
quelle