1 Vorne geschrieben
Es scheint, dass ich „JavsScript Advanced Programming“ eine kleine Demo machen möchte, um meine Fähigkeiten zu üben, also habe ich mich für das Snake-Spiel entschieden. Da zuvor alles in C# geschrieben wurde, wurde Snake in eine Klasse geschrieben und dann nacheinander in kleine Methoden aufgeteilt, und nur die Methoden wurden bereitgestellt, die bereitgestellt werden mussten. Auf diese Weise ist Snake als Modul einsetzbar und überall wiederverwendbar. Da jedoch beim Schreiben in js die Funktionen der js-Sprache für die modulare Programmierung nicht gut genutzt werden können, verfolgt die erste Version der Implementierung vollständig einen prozessorientierten Ansatz und deklariert alle in der Funktion erforderlichen Variablen als globale Variablen. Obwohl dadurch auch Funktionen erreicht werden können, kann es nicht wiederverwendet werden, und es werden viele Variablen der obersten Ebene definiert, wodurch globale Variablen verschmutzt werden. Nach dem Schreiben möchte ich das Geschriebene immer wieder neu kapseln, sodass nur die Variablen oder funktionalen Funktionsschnittstellen, die bereitgestellt werden müssen, der Außenwelt zur Verfügung gestellt werden. Nach Überprüfung vieler Informationen stellt sich heraus, dass die JS-Kapselung mithilfe von Verschlüssen implementiert werden kann. Durch die Deklaration lokaler Variablen und Abschlussfunktionen innerhalb der Funktion als private Variablen und Funktionen des Typs wird dem Objekt dann die Schnittstelle bereitgestellt, die dadurch entwickelt werden muss.
2 Verwendung von Schlangenkomponenten
2.1 Elementares Beispiel
Beispielcode 1 lautet wie folgt :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>贪吃蛇组件</title> </head> <body> <canvas width="600" height="600" id="gameScense"></canvas> </body> <script src="SnakeGame.js"></script> <script> var snakeGame = new SnakeGame("gameScense",{ }); snakeGame.startGame(); </script> </html>
Führen Sie zuerst die SnakeGame.js-Komponente ein, instanziieren Sie dann das SnakeGame-Objekt und übergeben Sie zwei Parameter an den SnakeGame-Konstruktor. Der erste Parameter ist die ID des Canvas und der zweite Parameter ist das Spielkonfigurationsobjekt. Wenn es leer ist, wird die Standardkonfiguration verwendet. Rufen Sie abschließend die startGame()-Methode des Objekts auf, um die Logik der Schlange zu implementieren. Die Standardtasten zur Richtungssteuerung sind die Aufwärts-, Abwärts-, Links- und Rechtstasten und die Pause ist die Leertaste. Der Effekt ist wie folgt:
Wir können das Spiel aktualisieren, indem wir die Konfiguration ändern Objekt, das während der Instanziierung übergeben wurde.
Beispielcode 2:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>贪吃蛇组件</title> </head> <body> <canvas width="600" height="600" id="gameScense"></canvas> </body> <script src="SnakeGame.js"></script> <script> var snakeGame = new SnakeGame("gameScense",{ snakeColor:"red", foodColor:"green", scenseColor:"blue", directionKey:[68,83,65,87], }); snakeGame.startGame(); </script> </html>
Sie können anhand des Namens der Parameter erkennen, die Farbe der Schlange, des Essens, des Spielhintergrunds usw. konfigurieren Steuern Sie die Richtung der Spieltaste. Die Reihenfolge der Konfigurationsrichtungen ist [links, unten, rechts, oben]. Der Effekt ist wie folgt:
Natürlich gibt es noch weitere Konfigurationen. Sie können auch Rückruffunktionen für Punkteänderungen, Rückruffunktionen am Ende des Spiels usw. definieren. Im Folgenden werden die Konfigurationsparameter und -methoden vorgestellt, die SnakeGame-Objekten gemeinsam sind.
2.2 Öffentliche Methoden
•startGame(): Startet das Spiel. Innerhalb dieser Methode werden verschiedene Einstellungen initialisiert. Setzen Sie beispielsweise den Punktestand, den Schlangenkörper, die Geschwindigkeit usw. zurück.
•changeGameStatus(): Spielstatus ändern, also pausieren und starten. Es gibt eine private Variable im SnakeGame-Objekt als Spielstatusvariable.
2.3 Objekt gameConfigObj-Attribute zum Konfigurieren von Spielparametern,
gameConfigObj-Objekt sollte insgesamt 10 Attribute und 3 Rückruffunktionen
Attribute
haben•size: die Größe der Schlangenblöcke und des Futters, Standard ist 20
•rowCount: Zeile, Standard ist 30 Zeilen
•colCount: Spalte, Standard ist 30 Spalten
•snakeColor: Körperfarbe der Schlange , Standard ist Grün
•foodColor: Lebensmittelfarbe, Standard Gelb
•scenseColor: Hintergrundfarbe der Spielszene, Standard Schwarz
•directionKey: Richtungstaste, Standard [39, 40, 37, 38] hoch, runter , links und rechts
•pasueKey: Pausentaste, Standard 32, Leertaste
•levelCount: Geschwindigkeitsstufensteuerung, Standard 10.
•curSpeed: Anfangsgeschwindigkeit, Standard 200 Millisekunden
Rückruf Funktion
•onCountChange: Ereignis, jedes Essen, Punktestand ändert sich, und diese Methode wird aufgerufen, mit einem Parameter (Anzahl)
•onGamePause: Ereignis, wenn sich der Spielstatus ändert, wird diese Methode aufgerufen aufgerufen, mit einem Parameter 1, der eine Pause darstellt, 0 bedeutet, dass das Spiel läuft.
•onGameOver: Ereignis, diese Methode wird aufgerufen, wenn das Spiel endet.
2.4 Verwendung von erweiterten
Durch die oben genannten Attribute können wir ein interaktiveres Programm entwerfen. Der Code lautet wie folgt.
Beispiel 3
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>贪吃蛇组件</title> <style type="text/css"> *{ margin:0px; padding:0px; } #gamebd{ width:850px; margin:50px auto; } #gameScense{ background-color:green; float:left; } #gameSet{ margin-left:10px; float:left; } .gameBoxStyle{ margin-bottom:7px; padding:5px 10px; } .gameBoxStyle h3{ margin-bottom:7px; } .gameBoxStyle p{ line-height: 1.7em; } .gameBoxStyle input{ margin-top:7px; background-color: white; border:1px gray solid; padding:3px 9px; margin-right:9px; } .gameBoxStyle input[type=text]{ width:90px; } .gameBoxStyle input:hover{ background-color: #e2fff2; } .gameBoxStyle #txtValue{ color:red; } </style> </head> <body> <p id="gamebd"> <canvas id="gameScense" width="600" height="600"> </canvas> <p id="gameSet"> <p id="gameControl" class="gameBoxStyle"> <h3>游戏控制</h3> <p>方向键:上,下,左,右</p> <p>开始/暂停:空格</p> </p> <p id="gameStatus" class="gameBoxStyle"> <h3>游戏状态</h3> <p>用户名:<input type="text" placeholder="输入用户名:" id="txtUserName" value="游客123"/> </p> <p>当前用户1得分:<span id="txtValue">0</span></p> <input type="button" value="开始游戏" id="btnStart"/> <input type="button" value="暂停" id="btnPause"/> </p> <p id="game" class="gameBoxStyle"> <h3>游戏记录</h3> <a href="#" rel="external nofollow" rel="external nofollow" >查看历史记录</a> </p> </p> </p> <script src="js/SnakeGame.js"></script> </body> <script src="SnakeGame.js"></script> <script> var btnStart=document.getElementById("btnStart"); var btnPasue=document.getElementById("btnPause"); var gameSnake = new SnakeGame("gameScense",{ snakeColor:"red", onCountChange:function(count){ var txtScore=document.getElementById("txtValue"); txtScore.innerText=count.toString( ); txtScore=null; }, onGamePause:function(status){ if(status){ btnPasue.value = "开始"; }else { btnPasue.value = "暂停" } }, onGameOver:function (status) { alert("游戏结束"); } }); btnStart.onclick=function(event){ if(checkUserName()){ gameSnake.startGame(); btnStart.blur(); } } btnPasue.onclick=function(event) { gameSnake.changeGameStatus(); btnStart.blur(); } function checkUserName(){ var txtUserName = document.getElementById("txtUserName"); if(txtUserName.value.length==0){ alert("用户名不能为空"); return false; }else { return true; } } </script> </html>
Der obige Code realisiert die Interaktion zwischen der Schnittstelle und der Komponente durch Festlegen von drei Rückruffunktionen: OnChangeCount, onGamePause und onGameOver . Der Effekt ist wie folgt:
Im Buch „JavaScript Advanced Programming“ wird ein Modulmodus erwähnt, aber dieser Modus ist ein Singleton-Modus, also der Abschluss gibt ein literales quantitatives Objekt zurück. Aber ich muss in der Lage sein, zwei Snake-Fenster gleichzeitig auf einer Seite zu öffnen. Die beiden Spiele können von zwei Personen gleichzeitig gespielt werden, indem unterschiedliche Richtungstasten und Tastenbedienungen konfiguriert werden. Daher wurde bei der Implementierung der SnakeGame-Komponente nicht auf das von Douglas erwähnte Modulmodell zurückgegriffen. Lassen Sie uns auf einer Seite zeigen, wie zwei Personen gleichzeitig Spiele spielen können. Der Code lautet wie folgt:
Beispiel 4
Erstellen Sie zunächst eine HTML-Datei
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Jaume's贪吃蛇</title> <link rel="stylesheet" href="css/gameStyle.css" rel="external nofollow" > </head> <body> <p id="gamebd"> <canvas id="gameScense" width="600" height="600"> </canvas> <canvas id="gameScense1" width="600" height="600" style="background-color: black"> </canvas> <p id="gameSet"> <p id="gameControl" class="gameBoxStyle"> <h3>游戏控制</h3> <p>方向键:上,下,左,右</p> <p>开始/暂停:空格</p> </p> <p id="gameStatus" class="gameBoxStyle"> <h3>游戏状态</h3> <p>当前用户1得分:<span id="txtValue">0</span></p> <p>当前用户2得分:<span id="txtValue1">0</span></p> <input type="button" value="开始游戏" id="btnStart"/> </p> <p id="game" class="gameBoxStyle"> <h3>游戏记录</h3> <a href="#" rel="external nofollow" rel="external nofollow" >查看历史记录</a> </p> </p> </p> <script src="js/SnakeGame.js"></script> <script src="js/UIScript.js"></script> </body> </html>
样式文件如下:
*{ margin:0px; padding:0px; } #gamebd{ /*width:850px;*/ /*margin:50px auto;*/ width:100%; } #gameScense{ background-color:green; float:left; } #gameSet{ margin-left:10px; float:left; } .gameBoxStyle{ margin-bottom:7px; padding:5px 10px; } .gameBoxStyle h3{ margin-bottom:7px; } .gameBoxStyle p{ line-height: 1.7em; } .gameBoxStyle input{ margin-top:7px; background-color: white; border:1px gray solid; padding:3px 9px; margin-right:9px; } .gameBoxStyle input[type=text]{ width:90px; } .gameBoxStyle input:hover{ background-color: #e2fff2; } .gameBoxStyle #txtValue{ color:red; }
在html中拖入了两个文件,一个是贪吃蛇组件,另一个是UIScript.js,其中的代码如下:
/** * Created by tjm on 8/16/2017. */ var btnStart=document.getElementById("btnStart"); var gameSnake = new SnakeGame("gameScense",{ snakeColor:"red", directionKey:[68,83,65,87], pauseKey:81, onCountChange:function(count){ var txtScore=document.getElementById("txtValue"); txtScore.innerText=count.toString( ); txtScore=null; }, onGameOver:function (status) { alert("游戏结束"); } }); var gameSnake1 = new SnakeGame("gameScense1",{ snakeColor:"green", size:20, onCountChange:function(count){ var txtScore=document.getElementById("txtValue1"); txtScore.innerText=count.toString(); txtScore=null; }, onGameOver:function (status) { alert("游戏结束"); } }); btnStart.onclick=function(event){ gameSnake.startGame(); gameSnake1.startGame(); btnStart.blur(); }
实例化两个SnakeGame对象,一个对象使用默认的上下左右键和空格键作为方向键和暂停键,而另一个使用了,W、A、S、D 以及 Q 作为方向键和暂停键。效果如下:
嗯哼,没错,完美实现了。使用SnakeGame这个组件,创建贪吃蛇游戏就是如此的简单。下面简单介绍一下,组件的实现方式。
3贪吃蛇组件实现方式
在上一节中就提到过,没有采用过道哥拉斯的设计模式,下面给出贪吃蛇设计结构。具体的源代码,可以在后面的链接中进行下载。代码如下:
/** * Created by tjm on 8/18/2017. */ var SnakeGame = function () { /*蛇块和食物组件类*/ function SnakeBlock(row,col){ this.row=row; this.col=col; } SnakeBlock.prototype.draw = function(graphic,color,size){ graphic.fillStyle=color; graphic.fillRect(size*this.col,size*this.row,size-2,size-2); } SnakeBlock.prototype.clearDraw = function(graphic,color,size){ graphic.fillStyle=color; graphic.fillRect(size*this.col,size*this.row,size,size); } SnakeBlock.prototype.equal = function(snakeBlock){ if(snakeBlock.row==this.row && snakeBlock.col==this.col){ return true; }else{ return false; } } /*贪吃蛇组件类*/ function SnakeGame(gameScenseId, gameConfigObj) { // 私有属性 var gameScense = document.getElementById(gameScenseId); var graphic = gameScense.getContext("2d"); var count = 0; var snake; var curFood; var runId; var isMoved = false;//方向改变后,如果没有移动则方向键暂时失效。 var gameStatus = false; var curDirection = 1; var size = gameConfigObj.size || 20; var rowCount = gameConfigObj.rowCount || 30; var colCount = gameConfigObj.colCount || 30; var snakeColor = gameConfigObj.snakeColor || "green"; var foodColor = gameConfigObj.foodColor || "yellow"; var scenseColor = gameConfigObj.scenseColor || "black"; var directionKey = gameConfigObj.directionKey || [39, 40, 37, 38]; var pauseKey = gameConfigObj.pauseKey || 32; var levelCount = gameConfigObj.levelCount || 10; var curSpeed = gameConfigObj.curSpeed || 200; //公开事件 var onCountChange = gameConfigObj.onCountChange || null; //带有一个参数 var onGamePause = gameConfigObj.onGamePause || null; //带有一个参数 var onGameOver = gameConfigObj.onGameOver || null; //判断 if(gameScense.width != size*rowCount || gameScense.height != size*colCount){ throw "场景大小不等于行列大小*蛇块大小"; } //特权方法 this.startGame = startGame; this.changeGameStatus = changeGameStatus; //注册 dom 键盘事件 var preFunc = document.onkeydown; document.onkeydown = function (e) { var key = (e || event).keyCode; handleKeyInput(key); if (typeof preFunc == "function") { preFunc(e); } } //私有方法 /*初始化蛇身*/ function initSnake(){ ··· } /*绘制场景背景色*/ function initScense(){ ··· } /*产生食物*/ function genFood(){ ··· } /*吃食物*/ function eatFood(snakeHead){ ··· } /*判断游戏是否结束*/ function gameOver(){ ··· } /*蛇移动*/ function snakeMove(){ ··· } function changeSpeed(){ ··· } function handleKeyInput(key){ ··· } function initGame(){ ··· } function triggerEvent(callback,argument){ ··· } function runGame(){ ··· } function pauseGame() { ··· } function changeGameStatus(){ ··· } function startGame(){ ··· } } return SnakeGame; //最后返回一个组件构造函数 }();
上面有一个很重要的地方,就是键盘注册的代码,单独列出来分析一下。
var preFunc = document.onkeydown; document.onkeydown = function (e) { var key = (e || event).keyCode; handleKeyInput(key); if (typeof preFunc == "function") { preFunc(e); } }
该段代码的逻辑是,首先判断在 document 上是否注册了onkeydown 事件,如果注册了该事件,则保存所引用的事件处理程序,然后重置onkeydown事件程序,然后在新的事件处理程序中,调用先前的事件处理程序,这样就实现了事件触发后,调用所有监听该事件处理程序,而不是直接覆盖。
另外关于贪吃蛇的设计逻辑,可以参看我另外一篇文章,个人觉得讲的非常详细了,文章:基于控制台实现贪吃蛇游戏
3 小结
通过这次贪吃蛇组件的设计,对 js 的模块化设计稍微了解了一下,但是,我也不知道上文所实现的贪吃蛇模块有哪些缺陷,希望有大神看到这篇文章,能给一些指导。当然了,该组件还可以进行进一步的扩展,比如将游戏的方块,替换成图片。
Das obige ist der detaillierte Inhalt vonBeispielcode für die Implementierung des Snake-Widgets in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!