Es gibt viele Artikel über die Implementierung von Snake in JS. In diesem Artikel verwenden wir hauptsächlich jQury, um das Snake-Spiel zu implementieren Es dient dazu, Ideen und Beispielcode aufzunehmen. Freunde, die es benötigen, können darauf verweisen.
Vorwort
Ich glaube, jeder hat das Schlangenspiel gespielt. In der Zeit, als Spielautomaten noch nicht populär waren und jeder ein Nokia besaß, war Snake ein unverzichtbares Spiel auf Mobiltelefonen. Wenn der Autor gelangweilt ist, zücke ich mein Handy, um ein paar Spiele zu spielen und meinen eigenen Rekord herauszufordern.
Später ging ich aufs College und machte ein Schlangenspiel in C-Sprache, aber es wurde hauptsächlich durch Funktionen gesteuert (PS: Ich kann den Code jetzt nicht verstehen (⊙﹏⊙)). Nachdem ich das Front-End-Framework gelernt habe, verwende ich jQuery, um einen schlangenfressenden Spieleffekt zu implementieren. Obwohl die Spieloberfläche relativ (bu) relativ (ren) einfach (zhi) (shi) ist, lerne ich hauptsächlich etwas über die Objektorientierung und lokal-lokale Aspekte des Spiels.
Designidee
Bevor wir mit dem Schreiben von Code beginnen, konzipieren wir zunächst den Implementierungsprozess des Gesamtspiels:
Erforderlich Das Objekt
Da es sich um eine gierige Schlange handelt, müssen zunächst zwei Objekte am Spiel beteiligt sein, eines ist das Schlangenobjekt und das andere ist das Nahrungsobjekt. Das Futterobjekt muss ein Attribut haben, das den Koordinatenpunkt des Futters darstellt. Das Schlangenobjekt hat ein Attribut, das ein Array zum Speichern aller Koordinatenpunkte des Schlangenkörpers ist.
Wie man sich bewegt
Darüber hinaus muss es global einen Timer geben, um den Körper der Schlange regelmäßig zu bewegen. Da der Körper der Schlange gebogen ist und verschiedene Formen hat, kümmern wir uns nur um den Kopf und den Schwanz der Schlange. Bei jeder Bewegung fügen wir einen neuen Kopf entsprechend der Bewegungsrichtung hinzu und löschen dann den Schwanz eine Schlange, die vorwärts kriecht.
Richtungssteuerung
Da die Schlange eine Bewegungsrichtung hat, müssen wir auch global ein Richtungsobjekt definieren, dessen Werte durch oben, unten, links und rechts im Objekt dargestellt werden. Gleichzeitig müssen wir in den Eigenschaften des Schlangenobjekts auch ein Richtungsattribut definieren, um die Richtung anzugeben, in die sich die Schlange gerade bewegt.
Kollisionserkennung
Wenn die Schlange vorwärts kriecht, stößt sie auf drei verschiedene Situationen, die eine unterschiedliche Urteilserkennung erfordern. Die erste Situation ist, wenn Nahrung gegessen wird. Zu diesem Zeitpunkt müssen die Koordinatenpunkte der Nahrung zum Array der Schlange hinzugefügt werden; die zweite Situation ist, wenn man den eigenen Körper berührt, und die dritte Situation, wenn man die Grenze erreicht. Beide Situationen führen zum Ende des Spiels; wenn die oben genannten drei Situationen nicht vorliegen, kann sich die Schlange normal bewegen.
Beginnen Sie mit dem Programmieren
Mit der Gesamtidee im Hinterkopf beginnen wir mit dem Schreiben von Code.
Aufbau des Vorhangs
Zuallererst benötigt das gesamte Spiel eine Szene, um Aktivitäten aufzubauen. Wir verwenden ein Tischlayout als Hintergrund für das gesamte Spiel.
<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>
Panel ist unser Vorhang, in dem wir td-Tags verwenden, um „Pixel“ einzeln zu zeichnen. Wir verwenden zwei Stile, um verschiedene Objekte darzustellen. .body repräsentiert den Stil des Schlangenkörpers und .food repräsentiert den Stil des Essens.
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('<tr>'); for(let j=0;j<size;j++){ content.push('<td class="td_'+i+'_'+j+'"></td>'); } content.push('</tr>'); } content.push('</table>'); $('#pannel').html(content.join('')); } setPannel(settings.pannelSize);
Wir definieren globale Einstellungen, um globale Variablen zu speichern, wie z. B. die Größe des Vorhangs, die Geschwindigkeit der Schlangenbewegung und den Arbeitsfaden. Dann wird der Vorhang durch eine Funktion zugezogen, und der Endeffekt sieht so aus:
Richtung und Positionierung
Jetzt ist unsere „Bühne“ Nachdem die Konstruktion abgeschlossen ist, müssen wir die Position und Bewegungsrichtung unseres „Akteurs“ definieren. Definieren Sie zunächst eine globale Richtungsvariable. Der entsprechende Wert ist der Schlüsselcode, der durch unsere Richtungstasten nach oben, unten, links und rechts dargestellt wird.
var Direction = { UP: 38, DOWN: 40, LEFT: 37, RIGHT: 39, };
Als wir den Vorhang oben zogen, zeichneten wir durch zwei Durchläufe ein Koordinatensystem ähnlich dem, das wir in der Mittelschule gelernt hatten, mit einer X-Achse und einer Y-Achse. Wenn es sehr (mei) mühsam (bi) mühsam (ge) wäre, jedes Mal {x:x,y:y} zu verwenden, können wir ein Koordinatenpunktobjekt definieren.
function Position(x,y){ // 距离X轴长度,取值范围0~pannelSize-1 this.X = x || 0; // 距离Y轴长度,取值范围0~pannelSize-1 this.Y = y || 0; }
Vista – Essen
Nachdem das Koordinatenpunktobjekt definiert wurde, können wir uns zunächst ein einfaches Objekt ansehen, das wie oben erwähnt ein wichtiges Attribut ist Es hat seinen Koordinatenpunkt.
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); } }; }
Da Lebensmittel die Eigenschaft von Koordinatenpunkten haben, wann weisen wir ihnen einen Wert zu? Wir wissen, dass Lebensmittel zufällig generiert werden, daher definieren wir eine Create-Funktion, um die Koordinatenpunkte von Lebensmitteln zu generieren. Da die generierten Koordinatenpunkte jedoch nicht auf dem Körper der Schlange liegen können, wird eine while-Schleife zum Generieren der Koordinatenpunkte verwendet. Wenn die Koordinatenpunkte korrekt sind, wird die Schleife beendet. Um unsere einheitliche Verarbeitung von Koordinatenpunktstilen zu erleichtern, wird außerdem eine handleDot-Funktion definiert.
Hauptkaffee – Snake
Endlich haben wir unseren Hauptkaffee, Snake. Definieren Sie zunächst die Grundattribute der Schlange. Jedes Mal, wenn sie sich bewegt, müssen einige Operationen an diesem Array ausgeführt werden. Als nächstes kommt die Richtung der Schlange, wir geben ihr eine Standardrichtung nach unten. Dann gibt es Nahrung. Im Konstruktor der Schlange übergeben wir das Nahrungsobjekt und müssen bei nachfolgenden Bewegungen feststellen, ob wir Nahrung gegessen haben.
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); } }; }
Funktionsverarbeitung verschieben
下面对蛇移动的过程进行处理,由于我们每次都采用添头去尾的方式移动,因此我们每次只需要关注蛇的头和尾。我们约定数组的第一个元素是头,最后一个元素是尾。
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(); };
检测函数处理
这样我们对蛇身数组就处理完了。但是我们还需要对新的头(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; };
重新绘制
因此我们需要对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'); } };
因为在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(); }
我们给document绑定一个keydown事件,当触发按键时改变蛇的移动方向,但是如果和当前蛇移动方向相反时就直接return。最后的效果如下:
可以戳这里查看实现效果
点击这里下载源码
总结
实现了贪吃蛇的一些基本功能,比如移动、吃点、控制速度等,页面也比较的简单,就一个table、select和button。后期可以添加一些其他的功能,比如有计分、关卡等,也可以添加多个点,有的点吃完直接GameOver等等。
相关推荐;
Das obige ist der detaillierte Inhalt vonBeispiel einer jQuery-Implementierung der Snake-Spielmethode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!