JSでSnakeを実装する記事はたくさんありますが、この記事では主にjQueryを使ってSnakeゲームを実装する方法を紹介しています。必要な友人はアイデアやサンプルコードを参照できます。
はじめに
誰もがスネークゲームをプレイしたことがあると思います。フルーツマシンがまだ普及しておらず、誰もが Nokia を持っていた時代、Snake は携帯電話に欠かせないゲームでした。筆者は退屈すると、携帯電話を取り出していくつかのゲームをプレイし、自分の記録に挑戦します。
その後、大学に行ってC言語でヘビゲームを作りましたが、主に関数で制御していました(追記:今はコードすら理解できません(⊙﹏⊙))。フロントエンド フレームワークを学んだ後、jQuery を使用してヘビを食べるゲーム エフェクトを実装します。ゲーム インターフェイスは比較的 (ブ) 比較的 (レン) シンプルですが、主にオブジェクト指向について学びます。ゲームのローカルからローカルへの総合的な考え方。
デザインのアイデア
コードを書き始める前に、まずゲーム全体の実装プロセスを考えてみましょう:
必要なオブジェクト
まず第一に、これは貪欲なヘビであるため、2 つの関係がある必要がありますゲーム オブジェクトでは、1 つはヘビのオブジェクト、もう 1 つは食べ物のオブジェクトです。食べ物オブジェクトには、食べ物の座標点である属性が必要です。ヘビ オブジェクトには、ヘビの体のすべての座標点を格納する配列である属性が必要です。
移動方法
さらに、ヘビの体を定期的に移動するには、グローバルにタイマーが必要です。ヘビの体は湾曲しており、さまざまな形状をしているため、ヘビの頭と尻尾だけを処理し、移動するたびに、移動方向に応じて新しい頭を追加し、尻尾を消去するように見えます。前方に這う蛇。
方向制御
ヘビには移動方向があるため、オブジェクト内で上、下、左、右で表される値を使用して、方向オブジェクトをグローバルに定義する必要もあります。同時に、ヘビが現在移動している方向を示すために、ヘビ オブジェクトのプロパティで方向属性を定義する必要もあります。
衝突検出
ヘビが前方に這う過程で、異なる判断検出が必要となる 3 つの異なる状況に遭遇します。 1 つ目の状況は、食べ物を食べるときです。このとき、食べ物の座標点をヘビの配列に追加する必要があります。2 つ目は、自分の体に触れたときです。3 つ目は、境界に到達したときです。どちらの状況でもゲームは終了しますが、上記の 3 つの状況以外の場合、ヘビは通常どおりに移動できます。
プログラミングを始めましょう
全体的なアイデアが得られたので、コードを書き始めることができます。
カーテンの構築
まず第一に、ゲーム全体にはアクティビティを構築するためのシーンが必要です。ゲーム全体の背景としてテーブル レイアウトを使用します。
<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>
pannel はカーテンで、td タグを使用して「ピクセル」を 1 つずつ描画します。さまざまなオブジェクトを表すために 2 つのスタイルを使用します。 .body はヘビの体のスタイルを表し、 .food は食べ物のスタイルを表します。
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);
カーテンのサイズ、ヘビの移動速度、作業スレッドなどのグローバル変数を保存するためのグローバル設定を定義しました。次に、関数によってカーテンが引かれ、最終的な効果は次のようになります:
方向と位置
「ステージ」が構築されたので、「アクター」の位置と移動方向を定義する方法「毛糸の布です。まず、グローバル方向変数を定義します。対応する値は、上、下、左、右の方向キーで表される keyCode です。
var Direction = { UP: 38, DOWN: 40, LEFT: 37, RIGHT: 39, };
上にカーテンを引くとき、中学校で習う 2 回の横断を通して X 軸と Y 軸で習ったような座標系を描きました。毎回 {x:x,y:y} を使用するのがとても(め)めんどくさい(bi)めんどくさい(ge)場合は、座標点オブジェクトを定義できます。
function Position(x,y){ // 距离X轴长度,取值范围0~pannelSize-1 this.X = x || 0; // 距离Y轴长度,取值范围0~pannelSize-1 this.Y = y || 0; }
Vice Cafe – Food
座標点オブジェクトが定義されたので、最初に Food (Food) オブジェクトである単純なオブジェクトを見てみましょう。上で述べたように、このオブジェクトには座標という重要な属性があります。ポイント。
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); } }; }
食べ物には座標点の属性があるので、いつ値を代入するのでしょうか? Food はランダムに生成されることがわかっているので、Food の座標点を生成する Create 関数を定義します。ただし、生成された座標点はヘビの体上に存在することができないため、while ループを使用して座標点を生成します。座標点が正しい場合、ループは終了します。さらに、座標点スタイルの統一処理を容易にするために、handleDot 関数が定義されています。
メインシェフ – スネーク
ついにメインのコーヒーであるスネークに到着しました。まず、ヘビの基本属性を定義します。最も重要なことは、ヘビが移動するたびに、この配列に対していくつかの操作を実行する必要があることです。次はヘビの方向です。デフォルトの下方向を指定します。次に食べ物があります。ヘビのコンストラクターでは食べ物オブジェクトを渡し、その後の移動中に食べ物を食べたかどうかを判断する必要があります。
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); } }; }
移動関数の処理
下面对蛇移动的过程进行处理,由于我们每次都采用添头去尾的方式移动,因此我们每次只需要关注蛇的头和尾。我们约定数组的第一个元素是头,最后一个元素是尾。
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等等。
相关推荐;
以上がスネークゲームメソッドのjQuery実装例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。