Heim >Web-Frontend >js-Tutorial >Javascript-High-Imitation von Legend of Blood-Spielcode-Sharing

Javascript-High-Imitation von Legend of Blood-Spielcode-Sharing

小云云
小云云Original
2018-02-23 09:20:153246Durchsuche

Die erste Version des Spiels wurde 2014 entwickelt. Der Browser verwendet HTML+CSS+JS, der Server ASP+PHP, die Kommunikation Ajax und die Datenspeicherung Access+MySQL. Aufgrund einiger Probleme (damals wusste ich nicht, wie man Node verwendet, war es wirklich schwierig, komplexe Logik in ASP zu schreiben; zu dieser Zeit gab es nur wenig Geschriebenes auf Canvas und das Dom-Rendering konnte leicht zu Leistungsengpässen führen). , es wurde aufgegeben. Später wurde eine Version mit Leinwand neu angefertigt.

Dieser Artikel stellt Ihnen hauptsächlich den Implementierungscode des JavaScript-High-Imitation-Spiels Legend of Blood vor. Er ist sehr gut und hat Referenzwert. Ich hoffe, er kann jedem helfen.

1. Vorbereitung vor der Entwicklung

Warum Javascript verwenden, um einen komplexeren PC zu implementieren -seitige Spiele

1.js ist möglich, PC-seitige Online-Spiele zu implementieren. Mit der Aktualisierung der Hardwarekonfigurationen von PCs und Mobiltelefonen, der Aktualisierung von Browsern und der Entwicklung verschiedener H5-Bibliotheken wird es immer schwieriger, ein Online-Spiel in js zu implementieren. Die Schwierigkeit liegt hier hauptsächlich in zwei Aspekten: der Leistung des Browsers; ob der js-Code einfach genug zu erweitern ist, um die Iteration eines Spiels mit äußerst komplexer Logik zu erfüllen.

2. Zu diesem Zeitpunkt gibt es unter den js-Spielen nur wenige als Referenz. Die meisten (fast alle) Spiele mit Multiplayer-Verbindungen, serverseitiger Datenspeicherung und komplexen Interaktionen werden mit Flash entwickelt. Aber Flash ist schließlich auf dem Rückzug, während sich JS rasant weiterentwickelt und laufen kann, solange es einen Browser gibt.

Warum haben Sie sich für ein legendäres Spiel aus dem Jahr 2001 entschieden?

Der erste Grund ist natürlich das Gefühl für das alte Spiel; der andere, wichtigere Grund ist, dass... . Entweder kann ich das Spiel nicht spielen, oder ich kann es spielen, habe aber nicht die Materialien (Bilder, Soundeffekte usw.). Ich denke, es ist Zeitverschwendung, sich viel Mühe zu geben, Karten, Charakter- und Monstermodelle, Gegenstände und Ausrüstungsdiagramme eines Spiels zu sammeln und sie dann zu verarbeiten und zu analysieren, bevor sie für die JS-Entwicklung verwendet werden.

Da ich bereits einige Materialien für Legend-Spiele gesammelt und glücklicherweise eine Möglichkeit gefunden habe, die Legend of Blood-Client-Ressourcendateien (Github-Adresse) zu extrahieren, kann ich direkt mit dem Schreiben von Code beginnen, was etwas Vorbereitungszeit spart.

Mögliche Schwierigkeiten

1. Browserleistung: Dies sollte der schwierigste Punkt sein. Wenn das Spiel 40 Frames beibehalten möchte, bleiben für jeden Frame nur noch 25 ms für die Berechnung durch js übrig. Und da das Rendern in der Regel mehr Leistung verbraucht als das Berechnen, beträgt die tatsächlich verbleibende Zeit für js nur etwa 10 Millisekunden.

2. Anti-Cheating: Wie kann verhindert werden, dass Benutzer Schnittstellen direkt aufrufen oder Netzwerkanforderungsdaten manipulieren? Da das Ziel darin besteht, mit js komplexere Spiele zu implementieren, und jedes Online-Spiel dies berücksichtigen muss, muss es eine relativ ausgereifte Lösung geben. Dies ist nicht der Schwerpunkt dieses Artikels.

2. Gesamtdesign

Browserseite

Die Bildschirmdarstellung verwendet Canvas.

Im Vergleich zu dom(p)+css kann Canvas eine komplexere Szenendarstellung und Ereignisverwaltung bewältigen. Die folgende Szene umfasst beispielsweise vier Bilder: Spieler, Tiere, Gegenstände auf dem Boden und das unterste Kartenbild . (Es gibt tatsächlich Schatten auf dem Boden, die entsprechenden Namen, die erscheinen, wenn die Maus auf Charaktere, Tiere und Objekte zeigt, sowie Schatten auf dem Boden. Aus Gründen der Lesbarkeit werden wir nicht so viel Inhalt berücksichtigen.)

Wenn Sie zu diesem Zeitpunkt den Effekt „Klicken Sie auf das Tier, greifen Sie das Tier an; klicken Sie auf den Gegenstand, nehmen Sie den Gegenstand auf“ erzielen möchten, dann benötigen Sie um die Ereignisse auf Tiere und Gegenstände zu überwachen. Wenn Sie die Dom-Methode verwenden, treten mehrere Probleme auf, die schwer zu lösen sind:

a Die Reihenfolge des Renderns und die Reihenfolge der Ereignisverarbeitung sind unterschiedlich (manchmal muss der Z-Index zuerst verarbeitet werden). wenn der Z-Index klein ist), was eine zusätzliche Verarbeitung erfordert. Zum Beispiel im obigen Beispiel: Wenn Sie auf Monster oder Gegenstände klicken, ist es einfach, auf Charaktere zu klicken, daher müssen Sie für die Charaktere eine „Klickereignisdurchdringung“-Verarbeitung durchführen. Darüber hinaus ist die Reihenfolge der Ereignisverarbeitung nicht festgelegt: Wenn ich über eine Fähigkeit verfüge (z. B. Behandlung im Spiel), die die Freilassung eines Charakters erfordert, muss der Charakter zu diesem Zeitpunkt über eine Ereignisüberwachung verfügen. Ob ein Element Ereignisse verarbeiten muss und in welcher Reihenfolge Ereignisse verarbeitet werden, hängt daher vom Spielstatus ab, und die Ereignisbindung von DOM kann die Anforderungen nicht mehr erfüllen.

b. Verwandte Elemente lassen sich nur schwer in den gleichen DOM-Knoten einfügen: wie das Modell des Spielers, der Name des Spielers und die Fähigkeitseffekte des Spielers. Idealerweise sollten sie in einem e388a4556c0f65e1904146cc1a846bee Abschnitt> im Container zur einfachen Verwaltung (auf diese Weise kann die Positionierung mehrerer Elemente vom übergeordneten Element geerbt werden, ohne dass die Position separat behandelt werden muss). Auf diese Weise wird es jedoch schwierig sein, mit dem Z-Index umzugehen. Wenn sich beispielsweise Spieler A über Spieler B befindet, wird A von B verdeckt. Daher muss der Z-Index von A kleiner sein, aber der Name von Spieler A darf nicht durch den Namen oder Schatten von B verdeckt werden, was nicht erreicht werden kann . Vereinfacht ausgedrückt wird die Wartbarkeit der DOM-Struktur den Effekt der Bildschirmanzeige beeinträchtigen und umgekehrt.

c. Leistungsprobleme. Selbst wenn der Effekt geopfert wird, führt die Verwendung von DOM zum Rendern unweigerlich zu vielen verschachtelten Beziehungen, und die Stile aller Elemente ändern sich häufig, was ständig ein Repaint oder sogar einen Reflow des Browsers auslöst.

Trennung der Canvas-Rendering-Logik und der Projektlogik

Wenn die verschiedenen Rendering-Vorgänge von Canvas (z. B. drawImage, fillText usw.) mit dem Projektcode kombiniert werden, führt dies unweigerlich dazu, dass es nicht wartbar ist das Projekt später. Nachdem ich mehrere vorhandene Canvas-Bibliotheken durchgesehen und die Datenbindungs- und Debugging-Tools von Vue kombiniert hatte, erstellte ich eine neue Canvas-Bibliothek Easycanvas (Github-Adresse), die wie Vue das Debuggen von Elementen im Canvas über ein Plug-In unterstützt.

Auf diese Weise wird der Rendering-Teil des gesamten Spiels viel einfacher. Sie müssen nur den aktuellen Status des Spiels verwalten und die Daten basierend auf den vom Server zurückgegebenen Daten aktualisieren. Easycanvas ist für den Link „Änderungen in Daten führen zu Änderungen in der Ansicht“ verantwortlich. Bei der Implementierung der Player-Verpackungselemente im Bild unten müssen wir beispielsweise nur die Position des Verpackungsbehälters und die Anordnungsregeln für jedes Element im Rucksack angeben und dann jedes verpackte Element an ein Array binden und dann Verwalten Sie dieses Array. Ja (Easycanvas ist für die Zuordnung der Daten zum Bildschirm verantwortlich).


Zum Beispiel kann der Stil von insgesamt 40 Artikeln in 5 Zeilen und 8 Spalten in der folgenden Form an Easycanvas übergeben werden (Index ist der Artikelindex). , und der Abstand des Elements in x-Richtung beträgt 36, der Abstand in y-Richtung 32). Und diese Logik ist unveränderlich, unabhängig davon, wie sich die Anordnung der Elemente ändert oder wohin das Paket gezogen wird, die relative Position jedes Elements ist festgelegt. Beim Rendern auf Leinwand muss das Projekt selbst nicht berücksichtigt werden, sodass die Wartbarkeit besser ist.


style: {
 tw: 30, th: 30,
 tx: function () {
 return 40 + index % 8 * 36;
 },
 ty: function () {
 return 31 + Math.floor(index / 8) * 32;
 }
}

Canvas-Layered-Rendering

Annahme: Das Spiel muss 40 Frames beibehalten, der Browser ist 800 breit und 600 hoch und die Fläche beträgt 480.000 (im Folgenden als 480.000 als 1 Bildschirmfläche bezeichnet).

Wenn zum Rendern dieselbe Leinwand verwendet wird, beträgt die Bildnummer dieser Leinwand 40 und es müssen mindestens 40 Bildschirmbereiche pro Sekunde gezeichnet werden. Es ist jedoch wahrscheinlich, dass sich mehrere Elemente am selben Koordinatenpunkt überlappen. Beispielsweise überlappen sich die Benutzeroberfläche, die Gesundheitsleiste und die Schaltflächen unten und blockieren gemeinsam die Szenenkarte. Wenn man diese zusammenzählt, kann die Zeichenmenge des Browsers pro Sekunde leicht mehr als 100 Bildschirmbereiche erreichen.

Diese Zeichnung ist schwer zu optimieren, da die Ansicht überall auf der gesamten Leinwand aktualisiert wird: Es kann sich um die Bewegung von Spielern und Tieren handeln, es können die Spezialeffekte von Schaltflächen sein, es kann der Effekt von sein eine bestimmte Fähigkeitsänderung. In diesem Fall wird die gesamte Leinwand neu gezeichnet, selbst wenn sich der Spieler nicht bewegt, weil die Kleidung „im Wind flattert“ (eigentlich wird die Sprite-Animation mit dem nächsten Bild abgespielt) oder eine Flasche Trank darauf erscheint der Boden. Da es fast unmöglich ist, dass ein bestimmter Frame des Spiels nicht vom vorherigen Frame zu unterscheiden ist, ist es schwierig, auch nur einen Teil des Spielbildschirms unverändert zu lassen. Der gesamte Spielbildschirm wird immer aktualisiert.

Weil es fast unmöglich ist, dass ein bestimmter Frame des Spiels nicht vom vorherigen Frame zu unterscheiden ist und der Bildschirm immer aktualisiert wird.

Daher habe ich dieses Mal die überlappende Anordnung von drei Leinwänden übernommen. Da die Ereignisverarbeitung von Easycanvas die Übermittlung unterstützt, kann auch die nachfolgende Leinwand das Ereignis empfangen, selbst wenn auf die obere Leinwand geklickt wird und kein Element einen Klick beendet. Die drei Leinwände sind für die Benutzeroberfläche, den Boden (Karte) und die Elfen (Charaktere, Tiere, Fertigkeitseffekte usw.) verantwortlich:


Der Vorteil Der Grund für diese Schichtung besteht darin, dass jede Schicht die maximale Anzahl von Frames nach Bedarf anpassen kann:

Zum Beispiel die UI-Ebene, da sich viele Benutzeroberflächen normalerweise nicht bewegen, und selbst wenn sie sich bewegen, ist dies auch nicht erforderlich präzises Zeichnen, so dass die Anzahl der Frames entsprechend reduziert werden kann, beispielsweise auf 20. Wenn die körperliche Stärke des Spielers auf diese Weise von 100 auf 20 sinkt, kann die Ansicht innerhalb von 50 ms aktualisiert werden, und der 50 ms-Wechsel ist für den Spieler nicht spürbar. Da es schwierig ist, Änderungen in den Daten der UI-Ebene, wie z. B. der körperlichen Stärke, mehrmals hintereinander in kurzer Zeit zu ändern, und die Verzögerung von 50 ms für Menschen schwer wahrnehmbar ist, ist kein häufiges Zeichnen erforderlich. Wenn wir 20 Bilder pro Sekunde einsparen, können wir wahrscheinlich 10 Bildschirmbereiche beim Zeichnen einsparen.

Wie der Boden ändert sich auch die Karte nur, wenn sich der Spieler bewegt. Auf diese Weise kann, wenn sich der Player nicht bewegt, 1 Bildschirmbereich pro Frame eingespart werden. Da eine reibungslose Bewegung der Spieler gewährleistet sein muss, sollte die maximale Bildrate am Boden nicht zu niedrig sein. Wenn der Bodenrahmen 30 Bilder umfasst, können 30 Bildschirmbereiche pro Sekunde gespeichert werden, wenn sich der Spieler nicht bewegt (in diesem Projekt wird die Karte fast so gezeichnet, dass sie den Bildschirm ausfüllt). Darüber hinaus wird der Boden durch die Bewegung anderer Spieler und Tiere nicht verändert und es besteht keine Notwendigkeit, die Bodenebene neu zu zeichnen.

Die maximale Bildrate der Sprite-Ebene kann nicht reduziert werden. Diese Ebene zeigt die Kernteile des Spiels, wie z. B. Charakterbewegungen, daher ist die maximale Bildrate auf 40 eingestellt.

In Auf diese Weise wird der pro Sekunde gezeichnete Bereich, Spielerbewegung Wenn sich der Spieler nicht bewegt, können es 80 bis 100 Bildschirmbereiche sein, aber nur 50 Bildschirmbereiche, wenn sich der Spieler nicht bewegt. Im Spiel halten die Spieler im Stehen an, um gegen Monster zu kämpfen, Gegenstände zu sammeln, zu organisieren und Fertigkeiten freizugeben. Daher wird das Ziehen des Bodens für eine lange Zeitspanne nicht ausgelöst, was die Leistung erheblich spart.

Serverseitig

Da das Ziel darin besteht, ein Multiplayer-Onlinespiel mit js zu implementieren, verwendet der Server Node und Socket für die Kommunikation mit dem Browser. Ein weiterer Vorteil besteht darin, dass eine gemeinsame Logik an beiden Enden wiederverwendet werden kann, beispielsweise die Bestimmung, ob sich an einem bestimmten Koordinatenpunkt auf der Karte ein Hindernis befindet.

Spielbezogene Daten wie Spieler und Szenen auf der Node-Seite werden alle im Speicher gespeichert und regelmäßig mit Dateien synchronisiert. Bei jedem Start des Node-Dienstes werden Daten aus der Datei in den Speicher gelesen. Auf diese Weise steigt die Häufigkeit des Lesens und Schreibens von Dateien exponentiell an, wenn mehr Player vorhanden sind, was zu Leistungsproblemen führt. (Um die Stabilität zu verbessern, wurde später ein Puffer zum Lesen und Schreiben von Dateien hinzugefügt, wobei die Methode „Memory-File-Backup“ verwendet wurde, um Dateischäden durch Serverneustarts während des Lese- und Schreibvorgangs zu vermeiden.)

Die Knotenseite ist in mehrere Schichten wie Schnittstelle, Daten und Instanz unterteilt. Die „Schnittstelle“ ist für die Interaktion mit dem Browser verantwortlich. „Daten“ sind einige statische Daten, wie der Name und die Wirkung eines bestimmten Medikaments, die Geschwindigkeit und die körperliche Stärke eines bestimmten Monsters, und sind Teil der Spielregeln. „Instanz“ ist der aktuelle Zustand im Spiel. Beispielsweise ist ein Medikament bei einem bestimmten Spieler eine Instanz von „Medikamentendaten“. Ein anderes Beispiel: „Hirschinstanz“ hat das Attribut „aktuelles Blutvolumen“. Hirsch A kann 10 sein, Hirsch B kann 14 sein und „Hirsch“ selbst hat nur „anfängliches Blutvolumen“.

3. Implementierung der Szenenkarte

Kartenszene

Beginnen wir mit dem Kartenszenenteil, der zum Rendern immer noch auf Easycanvas angewiesen ist.

Denken

Da der Spieler immer in der Mitte des Bildschirms fixiert ist, entspricht die Bewegung des Spielers tatsächlich der Bewegung der Karte. Wenn der Spieler beispielsweise nach links rennt, verschiebt sich die Karte nach rechts. Wie gerade erwähnt, befindet sich der Spieler in der mittleren Ebene der drei Leinwände und die Karte gehört zur unteren Ebene, sodass der Spieler die Karte blockieren muss.

Das scheint vernünftig, aber wenn es einen Baum auf der Karte gibt, dann ist „das Level des Spielers ist immer höher als der Baum“ falsch. Derzeit gibt es zwei große Lösungen:

Kartenebenen, „Boden“ und „Übergrund“ getrennt. Platzieren Sie den Spieler zwischen zwei Ebenen, zum Beispiel im Bild unten, wobei die linke Seite auf dem Boden und die rechte Seite auf dem Boden liegt, und überlappen Sie ihn dann und zeichnen Sie, um den Charakter in der Mitte einzuklemmen:


Dies scheint das Problem zu lösen, führt jedoch tatsächlich zu zwei neuen Problemen: Das erste besteht darin, dass Spieler manchmal durch Dinge „auf dem Boden“ (z. B. einen Baum) blockiert werden. und manchmal müssen sie in der Lage sein, Dinge „auf dem Boden“ zu blockieren (Wenn Sie beispielsweise unter diesem Baum stehen, blockiert Ihr Kopf den Baum). Ein weiteres Problem besteht darin, dass die Leistungskosten beim Rendern steigen. Da sich die Spieler ständig ändern, muss die Ebene „Boden“ häufig neu gezeichnet werden. Dadurch wird auch das ursprüngliche Design gebrochen – um die Darstellung der großen Bodenkarte so weit wie möglich einzusparen, was die Schichtung der Leinwand komplizierter macht.

Die Karte ist nicht geschichtet, „Boden“ und „Übergrund“ werden zusammen gezeichnet. Wenn sich der Spieler hinter einem Baum befindet, stellen Sie die Transparenz des Spielers auf 0,5 ein, wie im folgenden Bild:


Das hat nur einen Nachteil: den Körper des Spielers ist entweder undurchsichtig oder sie sind alle durchscheinend (auf der Karte laufende Monster haben diesen Effekt ebenfalls), was nicht ganz realistisch ist. Denn der ideale Effekt ist eine Szene, in der ein Teil des Körpers des Spielers verdeckt ist. Aber das ist leistungsfreundlich und der Code ist einfach zu warten. Ich verwende derzeit diese Lösung.

Wie kann man also feststellen, welche Teile des „Karten“-Bildes Bäume sind? Spiele verfügen normalerweise über eine große Kartenbeschreibungsdatei (eigentlich ein Array), die Zahlen wie 0, 1 und 2 verwendet, um zu identifizieren, welche Orte passiert werden können, wo es Hindernisse gibt, welche Orte Transferpunkte sind usw. Die „Beschreibungsdatei“ in Legend of Hot Blood wird in 48x32 als kleinster Einheit beschrieben, sodass die Aktionen des Spielers in Legend ein „Schachbrett“-Feeling haben. Je kleiner die Einheit, desto glatter ist sie, aber je größer das Volumen, das sie einnimmt, und desto zeitaufwändiger ist die Erstellung dieser Beschreibung.

Kommen wir zur Sache.

Implementierung

Ich habe einen Freund gebeten, mir beim Exportieren der Karte der „Beach Province“ in den Legend of Legend-Client zu helfen, der 33600 ist breit und 33600 hoch 22400, hundertmal so groß wie mein Computer. Um zu verhindern, dass der Computer explodiert, muss er zum Laden in mehrere Blöcke aufgeteilt werden. Da die kleinste Einheit einer Legende 48x32 ist, teilen wir die Karte in 4900 (70x70) Bilddateien mit 480x320 auf.

Wir haben die Größe der Leinwand auf 800 x 600 festgelegt, sodass Spieler insgesamt nur 3 x 3 Bilder laden müssen, die die gesamte Leinwand abdecken können. 800/480=1,67, warum also nicht 2x2? Denn es kann sein, dass die aktuelle Position des Spielers dazu führt, dass einige Bilder nur teilweise angezeigt werden. Wie unten gezeigt:

Verwandte Empfehlungen:

Codebeispiel für ein JavaScript-Eingabespiel

Komplette grafische Einführung in den Code des HTML5-Puzzlespiels in 2 Stunden

Beschreibung des JavaScript-Whack-a-Mole-Spielcodes_Game Entertainment

Das obige ist der detaillierte Inhalt vonJavascript-High-Imitation von Legend of Blood-Spielcode-Sharing. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn