Maison >interface Web >js tutoriel >Exemple de code pour implémenter le widget Snake en JavaScript
1 Écrit devant
Il semble que "JavsScript Advanced Programming", je souhaite faire une petite démo pour mettre en pratique mes compétences, j'ai donc choisi le jeu Snake. Comme tout était auparavant écrit en C#, Snake a été écrit dans une classe, puis divisé en petites méthodes une par une, et seules les méthodes qui devaient être fournies ont été fournies. De cette façon, Snake peut être utilisé comme module et peut être réutilisé n’importe où. Cependant, lors de l'écriture en js, étant donné que les caractéristiques du langage js ne peuvent pas être bien utilisées pour la programmation modulaire, la première version de l'implémentation adopte complètement une approche orientée processus et déclare toutes les variables requises dans la fonction comme variables globales. Bien que cela puisse également réaliser des fonctions, il ne peut pas être réutilisé et de nombreuses variables de niveau supérieur sont définies, polluant les variables globales. Après avoir écrit, je veux toujours ré-encapsuler ce que j'ai écrit afin que seules les variables ou les interfaces de fonctions fonctionnelles qui doivent être fournies soient fournies au monde extérieur. Après avoir vérifié de nombreuses informations, il s'avère que l'encapsulation js peut être implémentée à l'aide de fermetures. En déclarant les variables locales et les fonctions de fermeture à l'intérieur de la fonction en tant que variables privées et fonctions du type, l'objet reçoit alors l'interface qui doit être développée via celle-ci.
2 Utilisation des composants Snake
2.1 Exemple élémentaire
L'exemple de code 1 est le suivant :
<!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>
Introduisez d'abord le composant SnakeGame.js, puis instanciez l'objet SnakeGame et transmettez deux paramètres au constructeur SnakeGame. Le premier paramètre est l'identifiant du canevas et le deuxième paramètre est l'objet de configuration du jeu. S'il est vide, la configuration par défaut sera utilisée. Enfin, appelez la méthode startGame() de l'objet pour implémenter la logique du serpent. Les touches de contrôle de direction par défaut sont les touches haut, bas, gauche et droite, et la pause est l'espace. L'effet est le suivant :
Nous pouvons mettre à jour le jeu en modifiant la configuration. objet transmis lors de l’instanciation. Plusieurs contrôles.
Exemple de code 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>
Vous pouvez connaître par le nom des paramètres, configurer la couleur du serpent, la nourriture, l'arrière-plan du jeu, et contrôlez la direction de la touche de jeu. La séquence de direction de configuration est [gauche, bas, droite, haut]. L'effet est le suivant :
Bien sûr, il existe d'autres configurations. Vous pouvez également définir des fonctions de rappel pour les changements de score, des fonctions de rappel en fin de partie, etc. Ce qui suit présente les paramètres de configuration et les méthodes communes aux objets SnakeGame.
2.2 Méthodes publiques
•startGame() : Démarre le jeu. Dans le cadre de cette méthode, divers paramètres sont initialisés. Par exemple, réinitialisez le score, le corps du serpent, la vitesse, etc.
•changeGameStatus() : Changer l'état du jeu, c'est-à-dire mettre en pause et démarrer. Il y a une variable privée dans l'objet SnakeGame comme variable d'état du jeu.
2.3 Attributs de l'objet gameConfigObj pour la configuration des paramètres du jeu,
l'objet gameConfigObj doit avoir un total de 10 attributs et 3 fonctions de rappel
Attributs
•size : la taille du bloc de serpent et de la nourriture, la valeur par défaut est 20
•rowCount : ligne, la valeur par défaut est 30 lignes
•colCount : colonne, la valeur par défaut est 30 colonnes
•snakeColor : La couleur du corps du serpent, la valeur par défaut est vert
•foodColor : couleur alimentaire, jaune par défaut
•scenseColor : couleur d'arrière-plan de la scène de jeu, noir par défaut
•directionKey : touche de direction, par défaut [39, 40 , 37, 38] haut, bas, gauche et droite
•pasueKey : touche Pause, par défaut 32, barre d'espace
•levelCount : contrôle du niveau de vitesse, par défaut 10.
•curSpeed : vitesse initiale, par défaut 200. millisecondes
Fonction de rappel
•onCountChange : événement, chaque aliment, le score change, et cette méthode est appelée, avec un paramètre (count)
•onGamePause : événement, quand l'état du jeu change, cette méthode est appelée, avec un paramètre 1, représentant la pause, 0 signifie que le jeu est en cours.
•onGameOver : événement, cette méthode est appelée à la fin de la partie.
2.4 Utilisation avancée
Grâce aux attributs ci-dessus, nous pouvons concevoir un programme plus interactif. Le code est le suivant.
Exemple 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>
Le code ci-dessus réalise l'interaction entre l'interface et le composant en définissant trois fonctions de rappel : OnChangeCount, onGamePause et onGameOver . L'effet est le suivant :
Dans le livre "JavaScript Advanced Programming", un mode module est mentionné, mais ce mode est un mode singleton, c'est-à-dire la fermeture finalement renvoie un objet quantitatif littéral. Mais je dois pouvoir ouvrir deux fenêtres Snake en même temps sur une seule page. Les deux jeux peuvent être joués par deux personnes en même temps en configurant différentes touches de direction et opérations des boutons. Par conséquent, lors de la mise en œuvre du composant SnakeGame, le modèle de module mentionné par Douglas n'a pas été utilisé. Montrons comment permettre à deux personnes de jouer à des jeux en même temps sur une seule page. Le code est le suivant :
Exemple 4
Créez d'abord un fichier html
<!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 的模块化设计稍微了解了一下,但是,我也不知道上文所实现的贪吃蛇模块有哪些缺陷,希望有大神看到这篇文章,能给一些指导。当然了,该组件还可以进行进一步的扩展,比如将游戏的方块,替换成图片。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!