Maison > interface Web > js tutoriel > Exemple d'implémentation jQuery de la méthode de jeu Snake

Exemple d'implémentation jQuery de la méthode de jeu Snake

小云云
Libérer: 2018-01-23 14:16:05
original
2588 Les gens l'ont consulté

Il existe de nombreux articles sur l'implémentation de Snake dans JS. Dans cet article, nous utilisons principalement jQury pour implémenter le jeu Snake. L'article suivant présente principalement la méthode d'utilisation de jQuery pour implémenter le jeu Snake. Il s'agit d'absorber des idées et des exemples de code. Les amis qui en ont besoin peuvent s'y référer.

Avant-propos

Je crois que tout le monde a joué au jeu du Serpent. À cette époque où les machines à fruits n’étaient pas encore populaires et où tout le monde possédait un Nokia, Snake était un jeu incontournable sur les téléphones mobiles. Quand l'auteur s'ennuie, je sors mon téléphone portable pour jouer à quelques jeux et défier mon propre record.

Plus tard, je suis allé à l'université et j'ai créé un jeu de serpent en langage C, mais il était principalement contrôlé via des fonctions (PS : je ne comprends plus le code maintenant (⊙﹏⊙)) . Maintenant, après avoir appris le framework front-end, j'utilise jQuery pour implémenter un effet de jeu mangeur de serpents. Bien que l'interface du jeu soit relativement (bu) relativement (ren) simple (zhi)(shi), j'apprends principalement l'orientation objet. et les aspects locaux du jeu.

Idée de conception

Avant de commencer à écrire du code, concevons d'abord le processus de mise en œuvre du jeu global :

Obligatoire L'objet

Tout d'abord, puisqu'il s'agit d'un serpent gourmand, il doit y avoir deux objets impliqués dans le jeu, l'un est l'objet serpent et l'autre est l'objet nourriture. L'objet nourriture doit avoir un attribut qui est le point de coordonnées de la nourriture. L'objet serpent a un attribut qui est un tableau pour stocker tous les points de coordonnées du corps du serpent.

Comment bouger

De plus, il doit y avoir une minuterie globale pour déplacer périodiquement le corps du serpent. Étant donné que le corps du serpent est courbé et a des formes variées, nous ne traitons que la tête et la queue du serpent. Chaque fois que nous bougeons, nous ajoutons une nouvelle tête en fonction de la direction du mouvement, puis effaçons la queue. un serpent rampant en avant.

Contrôle de direction

Puisque le serpent a une direction de déplacement, nous devons également définir un objet de direction globalement, avec des valeurs représentées par haut, bas, gauche et droite dans l'objet. Dans le même temps, nous devons également définir un attribut de direction dans les propriétés de l'objet serpent pour indiquer la direction dans laquelle le serpent se déplace actuellement.

Détection de collision

Lorsque le serpent rampe vers l'avant, il rencontrera trois situations différentes, qui nécessitent une détection de jugement différente. La première situation est celle où la nourriture est mangée. À ce moment-là, les points de coordonnées de la nourriture doivent être ajoutés au tableau du serpent ; la deuxième situation est celle où l'on touche son propre corps, et la troisième situation est celle où l'on atteint la limite. Les deux situations mettent fin au jeu ; si ce n’est pas les trois situations ci-dessus, le serpent peut se déplacer normalement.

Commencer la programmation

Avec l'idée générale en tête, commençons à écrire du code.

Construire le rideau

Tout d'abord, le jeu entier a besoin d'une scène pour construire des activités. Nous utilisons une disposition de table comme arrière-plan de l'ensemble du jeu.

<style type="text/css">
#pannel table{
 border-collapse:collapse;
}
#pannel td{
 width: 10px;
 height: 10px;
 border: 1px solid #000;
}
#pannel td.food{
 background: green;
}
#pannel td.body{
 background: #f60;
}
</style>
<p id="pannel">
</p>
<select name="" id="palSize">
 <option value="10">10*10</option>
 <option value="20">20*20</option>
 <option value="40">30*30</option>
</select>
<select name="" id="palSpeed">
 <option value="500">速度-慢</option>
 <option value="250">速度-正常</option>
 <option value="100">速度-快</option>
</select>
<button id="startBtn">开始</button>
Copier après la connexion

Le panneau est notre rideau, dans lequel nous utilisons des balises td pour dessiner des "pixels" un par un. Nous utilisons deux styles pour représenter différents objets, .body représente le style du corps du serpent et .food représente le style de la nourriture.

var settings = {
 // pannel面板的长度
 pannelSize: 10,
 // 贪吃蛇移动的速度
 speed: 500,
 // 贪吃蛇工作线程
 workThread: null,
};
function setPannel(size){
 var content = [];
 content.push('<table>');
 for(let i=0;i<size;i++){
 content.push(&#39;<tr>');
 for(let j=0;j<size;j++){
 content.push(&#39;<td class="td_&#39;+i+&#39;_&#39;+j+&#39;"></td>');
 }
 content.push('</tr>');
 }
 content.push('</table>');
 $('#pannel').html(content.join(''));
}
setPannel(settings.pannelSize);
Copier après la connexion

Nous avons défini des paramètres globaux pour stocker des variables globales, telles que la taille du rideau, la vitesse de mouvement du serpent et le fil de travail. Ensuite le rideau est tiré grâce à une fonction, et l'effet final est comme ceci :

Direction et positionnement

Maintenant que notre "scène" a Une fois la construction terminée, comment définir la position et la direction du mouvement de notre "acteur". Définissez d’abord une variable de direction globale, la valeur correspondante est le keyCode représenté par nos touches de direction haut, bas, gauche et droite.

var Direction = {
 UP: 38,
 DOWN: 40,
 LEFT: 37,
 RIGHT: 39,
};
Copier après la connexion

Lorsque nous avons tiré le rideau ci-dessus, nous avons dessiné un système de coordonnées similaire à celui appris au collège à travers deux parcours, avec axe X et axe Y. S'il serait très (mei) gênant (bi) gênant (ge) d'utiliser {x:x,y:y} à chaque fois, nous pouvons définir un objet point de coordonnées.

function Position(x,y){
 // 距离X轴长度,取值范围0~pannelSize-1
 this.X = x || 0;
 // 距离Y轴长度,取值范围0~pannelSize-1
 this.Y = y || 0;
}
Copier après la connexion

Vista – Food

Maintenant que l'objet point de coordonnées a été défini, nous pouvons d'abord regarder un objet simple, qui est notre objet Food. Comme mentionné ci-dessus, un attribut important. il a son point de coordonnées.

function Food(){
 this.pos = null;
 // 随机产生Food坐标点,避开蛇身
 this.Create = function(){
 if(this.pos){
 this.handleDot(false, this.pos, 'food');
 }
 let isOk = true;
 while(isOk){
 let x = parseInt(Math.random()*settings.pannelSize),
 y = parseInt(Math.random()*settings.pannelSize);
 if(!$('.td_'+x+'_'+y).hasClass('body')){
 isOk = false;
 let pos = new Position(x, y);
 this.handleDot(true, pos, 'food');
 this.pos = pos;
 }
 }
 };
 // 画点
 this.handleDot = function(flag, dot, className){
 if(flag){
 $('.td_'+dot.X+'_'+dot.Y).addClass(className);
 } else {
 $('.td_'+dot.X+'_'+dot.Y).removeClass(className);
 }
 };
}
Copier après la connexion

Puisque la nourriture a l'attribut de points de coordonnées, quand lui attribue-t-on une valeur ? Nous savons que la nourriture est générée de manière aléatoire, nous définissons donc une fonction Create pour générer les points de coordonnées de la nourriture. Cependant, les points de coordonnées générés ne peuvent pas se trouver sur le corps du serpent, donc une boucle while est utilisée pour générer les points de coordonnées. Si les points de coordonnées sont corrects, la boucle est terminée. De plus, afin de faciliter notre traitement unifié des styles de points de coordonnées, une fonction handleDot est définie.

Café principal – Snake

Enfin, nous avons notre café principal, Snake. Définissez d'abord les attributs de base du serpent. Le plus important est certainement l'attribut corporel du serpent. Chaque fois qu'il bouge, certaines opérations doivent être effectuées sur ce tableau. Vient ensuite la direction du serpent, nous lui donnons une direction descendante par défaut. Ensuite, il y a la nourriture. Dans le constructeur du serpent, nous passons l'objet nourriture et nous devons déterminer si nous avons mangé de la nourriture lors des mouvements ultérieurs.

function Snake(myFood){
 // 蛇的身体
 this.body = [];
 // 蛇的方向
 this.dir = Direction.DOWN;
 // 蛇的食物
 this.food = myFood;
 // 创造蛇身
 this.Create = function(){
 let isOk = true;
 while(isOk){
 let x = parseInt(Math.random()*(settings.pannelSize-2))+1,
 y = parseInt(Math.random()*(settings.pannelSize-2))+1;
 console.log(x,y)
 if(!$('.td_'+x+'_'+y).hasClass('food')){
 isOk = false;
 let pos = new Position(x, y);
 this.handleDot(true, pos, 'body')
 this.body.push(pos);
 }
 }
 };
 this.handleDot = function(flag, dot, className){
 if(flag){
 $('.td_'+dot.X+'_'+dot.Y).addClass(className);
 } else {
 $('.td_'+dot.X+'_'+dot.Y).removeClass(className);
 }
 };
}
Copier après la connexion

Traitement de la fonction de déplacement

下面对蛇移动的过程进行处理,由于我们每次都采用添头去尾的方式移动,因此我们每次只需要关注蛇的头和尾。我们约定数组的第一个元素是头,最后一个元素是尾。

this.Move = function(){
 let oldHead = Object.assign(new Position(), this.body[0]),
 oldTail = Object.assign(new Position(), this.body[this.body.length - 1]),
 newHead = Object.assign(new Position(), oldHead);
 switch(this.dir){
 case Direction.UP:
 newHead.X = newHead.X - 1;
 break;
 case Direction.DOWN:
 newHead.X = newHead.X + 1;
 break;
 case Direction.LEFT:
 newHead.Y = newHead.Y - 1;
 break;
 case Direction.RIGHT:
 newHead.Y = newHead.Y + 1;
 break;
 default:
 break;
 }
 // 数组添头
 this.body.unshift(newHead);
 // 数组去尾
 this.body.pop();
};
Copier après la connexion

检测函数处理

这样我们对蛇身数组就处理完了。但是我们还需要对新的头(newHead)进行一些碰撞检测,判断新头部的位置上是否有其他东西(碰撞检测)。

// 食物检测
this.eatFood = function(){
 let newHead = this.body[0];
 if(newHead.X == this.food.pos.X&&newHead.Y == this.food.pos.Y){
 return true;
 } else {
 return false;
 }
};
// 边界检测
this.konckWall = function(){
 let newHead = this.body[0];
 if(newHead.X == -1 || 
 newHead.Y == -1 || 
 newHead.X == settings.pannelSize || 
 newHead.Y == settings.pannelSize ){
 return true;
 } else {
 return false;
 }
};
// 蛇身检测
this.konckBody = function(){
 let newHead = this.body[0],
 flag = false;
 this.body.map(function(elem, index){
 if(index == 0)
 return;
 if(elem.X == newHead.X && elem.Y == newHead.Y){
 flag = true;
 }
 });
 return flag;
};
Copier après la connexion

重新绘制

因此我们需要对Move函数进行一些扩充:

this.Move = function(){
 // ...数组操作
 if(this.eatFood()){
 this.body.push(oldTail);
 this.food.Create();
 this.rePaint(true, newHead, oldTail);
 } else if(this.konckWall() || this.konckBody()) {
 this.Over();
 } else {
 this.rePaint(false, newHead, oldTail);
 }
};
this.Over = function(){
 clearInterval(settings.workThread);
 console.log('Game Over');
};
this.rePaint = function(isEatFood, newHead, oldTail){
 if(isEatFood){
 // 加头
 this.handleDot(true, newHead, 'body');
 } else {
 // 加头
 this.handleDot(true, newHead, 'body');
 // 去尾
 this.handleDot(false, oldTail, 'body');
 }
};
Copier après la connexion

因为在Move函数处理数组的后我们的蛇身还没有重新绘制,因此我们很巧妙地判断如果是吃到食物的情况,在数组中就把原来的尾部添加上,这样就达到了吃食物的效果。同时我们定义一个rePaint函数进行页面的重绘。

游戏控制器

我们的“幕布”、“演员”和“动作指导”都已经到位,那么,我们现在就需要一个“摄影机”进行拍摄,让它们都开始“干活”。

function Control(){
 this.snake = null;
 // 按钮的事件绑定
 this.bindClick = function(){
 var that = this;
 $(document).on('keydown', function(e){
 if(!that.snake)
 return;
 var canChangrDir = true;
 switch(e.keyCode){
 case Direction.DOWN:
 if(that.snake.dir == Direction.UP){
 canChangrDir = false;
 }
 break;
 case Direction.UP:
 if(that.snake.dir == Direction.DOWN){
 canChangrDir = false;
 }
 break;
 case Direction.LEFT:
 if(that.snake.dir == Direction.RIGHT){
 canChangrDir = false;
 }
 break;
 case Direction.RIGHT:
 if(that.snake.dir == Direction.LEFT){
 canChangrDir = false;
 }
 break;
 default:
 canChangrDir = false;
 break;
 }
 if(canChangrDir){
 that.snake.dir = e.keyCode;
 }
 });
 $('#palSize').on('change',function(){
 settings.pannelSize = $(this).val();
 setPannel(settings.pannelSize);
 });
 $('#palSpeed').on('change',function(){
 settings.speed = $(this).val();
 });
 $('#startBtn').on('click',function(){
 $('.food').removeClass('food');
 $('.body').removeClass('body');
 that.startGame();
 });
 };
 // 初始化
 this.init = function(){
 this.bindClick();
 setPannel(settings.pannelSize);
 };
 // 开始游戏
 this.startGame = function(){
 var food = new Food();
 food.Create();
 var snake = new Snake(food);
 snake.Create();
 this.snake =snake;
 settings.workThread = setInterval(function(){
 snake.Move();
 },settings.speed);
 }
 this.init();
}
Copier après la connexion

我们给document绑定一个keydown事件,当触发按键时改变蛇的移动方向,但是如果和当前蛇移动方向相反时就直接return。最后的效果如下:


可以戳这里查看实现效果

点击这里下载源码

总结

实现了贪吃蛇的一些基本功能,比如移动、吃点、控制速度等,页面也比较的简单,就一个table、select和button。后期可以添加一些其他的功能,比如有计分、关卡等,也可以添加多个点,有的点吃完直接GameOver等等。

相关推荐;

js推箱子小游戏实现教程

php实现微信跳一跳小游戏

原生js实现html5打砖块小游戏的方法

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal