Ich glaube, dass jeder schon einmal das klassische Minesweeper-Spiel gespielt hat. Es hat einfache Regeln, aber ist sehr süchtig machend. Hast du jemals darüber nachgedacht, es selbst zu entwickeln? Heute werden wir eine webbasierte Version von Minesweeper erstellen. Zunächst schauen wir uns einen Screenshot der Schnittstelle an.
👀 Vorschau
🎯 Aufgaben
In diesem Projekt wirst du lernen:
Wie man den Spielalgorithmus für das Minesweeper-Spiel entworfen
Wie man die Dateistruktur für das Projekt erstellt
Wie man die Seitenlayout mit HTML und CSS implementiert
Wie man das Gitter mit JavaScript zeichnet
Wie man Klickereignisse auf die Zellen hinzufügt, um das Spiel zu steuern
Wie man Spielsteuerfunktionen wie das Starten und Beenden des Spiels implementiert
🏆 Errungenschaften
Nach Abschluss dieses Projekts wirst du in der Lage sein:
Spielalgorithmen zu entwerfen und umzusetzen
Die Dateistruktur für ein Webanwendungsprojekt zu erstellen
HTML und CSS verwenden, um Seitenlayouts zu erstellen
JavaScript verwenden, um Gittern zu zeichnen und Ereignisse zu behandeln
Spielsteuerfunktionen umzusetzen
Entwicklung vorbereiten
Bevor wir mit der Entwicklung beginnen, entwerfen wir zunächst den Spielalgorithmus.
Die Regeln des Minesweeper-Spiels sind einfach:
Es gibt mehrere Quadrate auf der Spielfläche. Jedes Quadrat enthält eine Zahl (leer bedeutet, dass die Zahl 0 ist) oder eine Bombe. Die Zahl im Quadrat repräsentiert die Anzahl der Bomben in den umliegenden Quadrate. Die Aufgabe des Spielers ist, die Zahlquadrate in möglichst kurzer Zeit zu finden.
Abgesehen von den Quadraten an den Rändern hat jedes Quadrat 8 Nachbarquadrate: oben, unten, links, rechts und 4 diagonale Quadrate. Daher liegt der Zahlenbereich zwischen 0 und 8.
Unser Algorithmus lautet daher:
Basierend auf dem Schwierigkeitsgrad, den der Benutzer wählt (es gibt drei Stufen: Beginner, Intermediate und Advanced, wobei die Anzahl der Bomben und Quadrate mit zunehmender Stufe zunimmt), generieren wir zufällig eine bestimmte Anzahl von Bomben und legen sie zufällig auf den Quadraten ab. Anschließend durchlaufen wir die Quadrate, berechnen die Zahl in jedem Quadrat und markieren sie auf dem Quadrat. Wenn der Spieler mit der linken Maustaste auf ein Quadrat klickt, wird der Inhalt des Quadrats angezeigt (wenn das Quadrat eine Bombe enthält, scheitert die Herausforderung und das Spiel endet), und wenn der Spieler mit der rechten Maustaste auf ein Quadrat klickt, wird das Quadrat als Bombe markiert. Die Herausforderung ist nur dann erfolgreich, wenn alle Bomben richtig markiert und alle nicht-bombigen Quadrate geöffnet sind, und das Spiel endet.
Nützlicher Tipp: Da der Zahlenbereich in den Quadraten zwischen 0 und 8 liegt, können wir die Zahlen in den Quadraten, in denen die Bomben liegen, als 9 markieren, um die Berechnung zu erleichtern.
Zunächst benötigen wir ein Panel, um Spielinformationen anzuzeigen, einschließlich der Anzahl der verbleibenden Minen, der vergangenen Zeit, des Schwierigkeitsgrads usw. Da die Anzahl der Quadrate nicht festgelegt ist, zeichnen wir die Quadrate vorerst nicht und zeichnen sie stattdessen im JS-Code.
Erstellen Sie eine Datei index.html und fügen Sie den folgenden Code hinzu:
<!-- index.html -->
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Minesweeper mit JavaScript</title>
<link
href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
rel="stylesheet"
/>
<link rel="stylesheet" type="text/css" href="index.css" />
</head>
<body class="bg-gray-100">
<div
id="JMS_main"
class="container mx-auto p-4 bg-white shadow-lg rounded-lg"
>
<table id="landmine" class="mx-auto"></table>
<div id="operation" class="text-center">
<div class="text-lg text-red-600">
Anzahl der verbleibenden Minen:
<span class="font-semibold" id="landMineCount">0</span>
</div>
<div class="text-lg text-orange-500">
Dauer: <span class="font-semibold" id="costTime">0</span> s
</div>
<fieldset class="my-4">
<legend class="text-lg font-semibold">Schwierigkeitsauswahl:</legend>
<input
type="radio"
name="level"
id="llevel"
checked="checked"
value="10"
class="mr-2"
/>
<label for="llevel">Einfach (10*10) </label><br />
<input
type="radio"
name="level"
id="mlevel"
value="15"
class="mr-2"
/>
<label for="mlevel">Mittel (15*15) </label><br />
<input
type="radio"
name="level"
id="hlevel"
value="20"
class="mr-2"
/>
<label for="hlevel">Schwer (20*20) </label><br />
</fieldset>
<button
id="begin"
class="px-4 py-2 bg-blue-500 text-white font-semibold rounded-lg hover:bg-blue-700"
>
Spiel starten</button
><br />
<div class="text-left mt-4">
<div class="font-semibold">Hinweis:</div>
<ul class="list-disc ml-6">
<li>
1. Klicken Sie auf "Spiel starten", um den Spielzeiger zu starten.
</li>
<li>
2. Klicken Sie während des Spiels auf "Spiel starten", um ein
neues Spiel zu beginnen.
</li>
</ul>
</div>
</div>
</div>
<script src="jms.js"></script>
<script src="index.js"></script>
</body>
</html>
Als nächstes müssen wir die Position der Spielinformationen auf dem Panel anpassen und einige Stile hinzufügen. Fügen Sie den folgenden Code zu index.css hinzu und speichern Sie:
Nach Abschluss der vorherigen Schritte müssen wir das Gitter zeichnen. Um den Code übersichtlicher zu gestalten, trennen wir den Spielimplementierungsteil und den Aufrufsteil. Der Spielimplementierungsteil wird in jms.js platziert, das im selben Verzeichnis wie index.html liegt, und der Spielaufrufsteil wird in index.js, ebenfalls im selben Verzeichnis, platziert.
Um das Gitter zu zeichnen, müssen wir einige Parameter übergeben, wie die id der Tabelle, in der das Gitter platziert werden soll, und die Anzahl der Zellen (dargestellt durch die Anzahl der Zeilen und Spalten). Darüber hinaus müssen andere spielbezogene Daten initialisiert werden.
Teil von jms.js
Fügen Sie den folgenden Code zu jms.js hinzu und speichern Sie ihn:
(function () {
// Initialisiere das Minesweeper-Objekt und initialisiere die Daten
var JMS = function (
id,
rowCount,
colCount,
minLandMineCount,
maxLandMineCount
) {
if (!(this instanceof JMS))
return new JMS(
id,
rowCount,
colCount,
minLandMineCount,
maxLandMineCount
);
this.doc = document;
this.table = this.doc.getElementById(id); // Tabelle zum Zeichnen des Gitters
this.cells = this.table.getElementsByTagName("td"); // Zellen
this.rowCount = rowCount || 10; // Anzahl der Zeilen im Gitter
this.colCount = colCount || 10; // Anzahl der Spalten im Gitter
this.landMineCount = 0; // Anzahl der Minen
this.markLandMineCount = 0; // Anzahl der markierten Minen
this.minLandMineCount = minLandMineCount || 10; // Mindestanzahl der Minen
this.maxLandMineCount = maxLandMineCount || 20; // Maximalanzahl der Minen
this.arrs = []; // Array, das den Zellen entspricht
this.beginTime = null; // Startzeit des Spiels
this.endTime = null; // Endzeit des Spiels
this.currentSetpCount = 0; // Anzahl der durchgeführten Schritte
this.endCallBack = null; // Callback-Funktion, wenn das Spiel endet
this.landMineCallBack = null; // Callback-Funktion, um die verbleibende Anzahl der Minen zu aktualisieren, wenn eine Mine markiert wird
this.doc.oncontextmenu = function () {
// Deaktiviere den Rechtsklick-Menü
return false;
};
this.drawMap();
};
// Erstelle Zellen im Prototype von JMS
JMS.prototype = {
// Zeichne das Gitter
drawMap: function () {
var tds = [];
// Für die Browserkompatibilität
if (
window.ActiveXObject &&
parseInt(navigator.userAgent.match(/msie ([\d.]+)/i)[1]) < 8
) {
// Erstelle eine neue CSS-Stildatei
var css = "#JMS_main table td{background-color:#888;}",
// Hole das Head-Tag
head = this.doc.getElementsByTagName("head")[0],
// Erstelle ein Style-Tag
style = this.doc.createElement("style");
style.type = "text/css";
if (style.styleSheet) {
// Weise die CSS-Stil an das Style-Tag zu
style.styleSheet.cssText = css;
} else {
// Erstelle einen Knoten im Style-Tag
style.appendChild(this.doc.createTextNode(css));
}
// Füge das Style-Tag als Kind-Tag des Head-Tags hinzu
head.appendChild(style);
}
// Schleife, um die Tabelle zu erstellen
for (var i = 0; i < this.rowCount; i++) {
tds.push("<tr>");
for (var j = 0; j < this.colCount; j++) {
tds.push("<td id='m_" + i + "_" + j + "'></td>");
}
tds.push("</tr>");
}
this.setTableInnerHTML(this.table, tds.join(""));
},
// Füge HTML zur Tabelle hinzu
setTableInnerHTML: function (table, html) {
if (navigator && navigator.userAgent.match(/msie/i)) {
// Erstelle eine Div innerhalb des Besitzerdokuments der Tabelle
var temp = table.ownerDocument.createElement("div");
// Erstelle den Inhalt der tbody der Tabelle
temp.innerHTML = "<table><tbody>" + html + "</tbody></table>";
if (table.tBodies.length == 0) {
var tbody = document.createElement("tbody");
table.appendChild(tbody);
}
table.replaceChild(temp.firstChild.firstChild, table.tBodies[0]);
} else {
table.innerHTML = html;
}
}
};
window.JMS = JMS;
})();
Der obige Code enthält einige Codezeilen zur Kompatibilität mit IE-Browsern, die ignoriert werden können.
Teil von index.js
Im Aufrufscode in index.js müssen wir das Ereignis der Schwierigkeitsauswahl-Schaltflächen binden und dann den oben definierten JMS aufrufen, um das Gitter zu zeichnen.
Fügen Sie den folgenden Code zu index.js hinzu und speichern Sie ihn:
var jms = null,
timeHandle = null;
window.onload = function () {
var radios = document.getElementsByName("level");
for (var i = 0, j = radios.length; i < j; i++) {
radios[i].onclick = function () {
if (jms != null)
if (jms.landMineCount > 0)
if (!confirm("Möchten Sie das aktuelle Spiel beenden?")) return false;
var value = this.value;
init(value, value, (value * value) / 5 - value, (value * value) / 5);
document.getElementById("JMS_main").style.width =
value * 40 + 180 + 60 + "px";
};
}
init(10, 10);
};
function init(rowCount, colCount, minLandMineCount, maxLandMineCount) {
var doc = document,
landMineCountElement = doc.getElementById("landMineCount"),
timeShow = doc.getElementById("costTime"),
beginButton = doc.getElementById("begin");
if (jms != null) {
clearInterval(timeHandle);
timeShow.innerHTML = 0;
landMineCountElement.innerHTML = 0;
}
jms = JMS("landmine", rowCount, colCount, minLandMineCount, maxLandMineCount);
}
Öffnen Sie dann index.html im Browser, und das Gitter sollte angezeigt werden. Der Effekt ist wie folgt:
Klicken Sie auf die Schwierigkeitsauswahl rechts, um die Anzahl der Zellen zu sehen, die sich ändert.
Jetzt ist es erforderlich, Klickereignisse für die Zellen hinzuzufügen. Beim Linksklick wird die Zahl in der Zelle angezeigt (wenn es eine Mine ist, endet das Spiel). Beim Rechtsklick wird sie als Mine markiert.
Zudem sollte, wenn die Zelle zum ersten Mal geklickt wird (was normalerweise Glück involviert), wenn es eine leere Fläche in ihrer Nähe gibt, direkt erweitert werden.
Fügen Sie den folgenden Code zu JMS.prototype in jms.js hinzu:
// Element abrufen
$: function (id) {
return this.doc.getElementById(id);
},
// Klickereignisse (Links- und Rechtsklick) für jede Zelle binden
bindCells: function () {
var self = this;
for (var i = 0; i < this.rowCount; i++) {
for (var j = 0; j < this.colCount; j++) {
(function (row, col) {
self.$("m_" + i + "_" + j).onmousedown = function (e) {
e = e || window.event;
var mouseNum = e.button;
var className = this.className;
if (mouseNum == 2) {
if (className == "flag") {
this.className = "";
self.markLandMineCount--;
} else {
this.className = "flag";
self.markLandMineCount++;
}
if (self.landMineCallBack) {
self.landMineCallBack(self.landMineCount - self.markLandMineCount);
}
} else if (className!= "flag") {
self.openBlock.call(self, this, row, col);
}
};
})(i,j);
}
}
},
// Fläche ohne Minen erweitern
showNoLandMine: function (x, y) {
for (var i = x - 1; i < x + 2; i++)
for (var j = y - 1; j < y + 2; j++) {
if (!(i == x && j == y)) {
var ele = this.$("m_" + i + "_" + j);
if (ele && ele.className == "") {
this.openBlock.call(this, ele, i, j);
}
}
}
},
// Anzeige
openBlock: function (obj, x, y) {
if (this.arrs[x][y]!= 9) {
this.currentSetpCount++;
if (this.arrs[x][y]!= 0) {
obj.innerHTML = this.arrs[x][y];
}
obj.className = "clicked-cell";
if (this.currentSetpCount + this.landMineCount == this.rowCount * this.colCount) {
this.success();
}
obj.onmousedown = null;
if (this.arrs[x][y] == 0) {
this.showNoLandMine.call(this, x, y);
}
} else {
this.failed();
}
},
// Minen anzeigen
showLandMine: function () {
for (var i = 0; i < this.rowCount; i++) {
for (var j = 0; j < this.colCount; j++) {
if (this.arrs[i][j] == 9) {
this.$("m_" + i + "_" + j).className = "landMine";
}
}
}
},
// Informationen aller Zellen anzeigen
showAll: function () {
for (var i = 0; i < this.rowCount; i++) {
for (var j = 0; j < this.colCount; j++) {
if (this.arrs[i][j] == 9) {
this.$("m_" + i + "_" + j).className = "landMine";
} else {
var ele=this.$("m_" + i + "_" + j);
if (this.arrs[i][j]!= 0)
ele.innerHTML = this.arrs[i][j];
ele.className = "normal";
}
}
}
},
// Angezeigte Zellinformationen löschen
hideAll: function () {
for (var i = 0; i < this.rowCount; i++) {
for (var j = 0; j < this.colCount; j++) {
var tdCell = this.$("m_" + i + "_" + j);
tdCell.className = "";
tdCell.innerHTML = "";
}
}
},
// Die an den Zellen gebundenen Ereignisse entfernen
disableAll: function () {
for (var i = 0; i < this.rowCount; i++) {
for (var j = 0; j < this.colCount; j++) {
var tdCell = this.$("m_" + i + "_" + j);
tdCell.onmousedown = null;
}
}
},
Bis jetzt ist der Hauptteil des Spiels abgeschlossen. Der nächste Schritt besteht darin, Spielsteuerungsfunktionen hinzuzufügen, um das Spiel reibungslos laufen zu lassen. Die Hauptschritte sind wie folgt:
Fügen Sie einem Klickereignis-Listener für die Startschaltfläche hinzu, um die Spielparameter zurückzusetzen.
Beginne die Zeitmessung, wenn das Spiel startet.
Stoppe die Zeitmessung und zeige eine Meldung an, wenn das Spiel endet.
Abschnitt jms.js
Fügen Sie die Spiel-Eintrittspunkt- und Startfunktion zu JMS.prototype in jms.js hinzu:
// Spielstart
begin: function() {
this.currentSetpCount = 0; // Setze die Schrittzahl auf Null zurück
this.markLandMineCount = 0;
this.beginTime = new Date(); // Spielstartzeit
this.hideAll();
this.bindCells();
},
// Spielende
end: function() {
this.endTime = new Date(); // Spielendezeit
if (this.endCallBack) { // Rufe die Callback-Funktion auf, wenn sie existiert
this.endCallBack();
}
},
// Spielgewonnen
success: function() {
this.end();
this.showAll();
this.disableAll();
alert("Glückwunsch!");
},
// Spielverloren
failed: function() {
this.end();
this.showAll();
this.disableAll();
alert("SPIEL OVER!");
},
// Eintrittspunkt
play: function() {
this.init();
this.landMine();
this.calculateNoLandMineCount();
},
Abschnitt index.js
In index.js fügen Sie einem Ereignis-Listener für die Startschaltfläche hinzu, um das Spiel zu starten, und zeigen Sie die Spielzeit und die verbleibende Anzahl von Minen an (nach jms = JMS("landmine", rowCount, colCount, minLandMineCount, maxLandMineCount); in der init-Funktion von index.js):
jms.endCallBack = function () {
clearInterval(timeHandle);
};
jms.landMineCallBack = function (count) {
landMineCountElement.innerHTML = count;
};
// Binde Ereignis an die Schaltfläche "Spiel starten"
beginButton.onclick = function () {
jms.play(); // Initialisiere das Spiel
// Zeige die Anzahl der Minen an
landMineCountElement.innerHTML = jms.landMineCount;
// Starte das Spiel
jms.begin();
// Aktualisiere die vergangene Zeit
timeHandle = setInterval(function () {
timeShow.innerHTML = parseInt((new Date() - jms.beginTime) / 1000);
}, 1000);
};
In diesem Experiment wird hauptsächlich JavaScript verwendet, um eine Webbversion des klassischen Spiels Minesweeper zu implementieren. Es wird angenommen, dass Benutzer durch dieses Experiment ihr Verständnis und ihre Anwendungsfähigkeiten von JavaScript verbessern können. Darüber hinaus können Benutzer auch lernen, wie man das JavaScript-Sprache verwendet, um Objekte im Spiel zu abstrahieren und zu kapseln.