検索
ホームページウェブフロントエンドjsチュートリアルスネーク ゲームの JavaScript 実装の共有例

この記事では、JavaScript を使用して Snake ゲームを実装する例を紹介します。

スネーク ゲームの JavaScript 実装の共有例

#JavaScript はスネーク ゲームを実現します

機能概要

このプログラムは次の機能を実装します。

    #Snake の基本機能
  1. #統計スコア
  2. #開始と一時停止

  3. 難易度の選択

  4. ショートカット キーの設定

  5. 5.1 ijkl を通じて、wsad は方向切り替えも実現できます
  6. 5.2 「P」は一時停止を意味します。 「C」は開始または続行を意味し、「R」は再起動を意味します

    実装プロセス

最初の実装原則は実際に基づいていますcsdn の巨匠のリファレンスです。彼は 20 行の JavaScript で Snake の基本機能を実装しました。賞賛に値するのは、バグがないことです。リンクはここですSnake を実装するには、大まかにそこにあります手順は次のとおりです。

#ヘビの動く領域を描く

  • ヘビを描く

  • drawfood

  • ヘビを動かしてみましょう

  • ゲームのルールを設定します

  • 難易度を設定します

  • 開始と一時停止の設定

  • ゲーム終了後のその後の動作の設定

  • 人間とコンピュータのインタラクションの実現ページ

  • 注: 次のプロセスの説明部分では、原理と実装の一部のみを説明しています。理解しやすくするために、以下の説明を読みながら最終的な完全なコードを読むことをお勧めします。原理と実装

ヘビのアクティブ領域の描画

まず、ヘビのアクティブ領域を描画します。 JavaScript キャンバスを使用して描画します ヘビの活動領域として 400×400 400\times 400400×400 の領域を使用します

<canvas></canvas>

同時に、CSS を通じて境界線を設定します

#canvas {
    border: 1px solid #000000; /* 设置边框线 */}

ヘビと食べ物を描きます

効果は次のとおりです:

ヘビを描く前に、次のことを行う必要があります。ヘビのデータ構造について考えてください。ここでは、ヘビを表すために最も単純なキューを使用します

スネーク ゲームの JavaScript 実装の共有例

チームの先頭はヘビの頭の位置を表し、チームの尾はチームの尾の位置を表しますはヘビの尻尾の位置を表します

  • を描きます ​​ ​​                                       400                                     ×                                     400                                                           400\×400 ​​

    #400##×##400エリアは 400# に分割されます ​​ ​​                                       20                                     ×                                     20                                                           20\×20 ​​ #20##× 20 正方形、これらの正方形を使用して蛇を形成し、次に正方形を使用します。ヘビが位置しています。位置の値の範囲は 0 ~ 399 例:

    var snake=[42,41,40];
    上記のコードは、ヘビの位置が 42、41、および 40 であることを示しています。ヘビの頭は 42、ヘビの尾は 40##食べ物の場合、変数 food を使用して食べ物の場所を保存できます。は 0 ~ 399 (ヘビを除く) ゲームでは食料をランダムに生成する必要があるため、ランダム関数は次のように実装されています:

    // 产生min~max的随机整数,用于随机产生食物的位置function random(min, max) {
        const num = Math.floor(Math.random() * (max - min)) + min;
        return num;}

    当食物被蛇吃掉后就需要重新刷新食物,由于食物不能出现在蛇所在的位置,我们用一个while循环,当食物的位置不在蛇的数组中则跳出循环

    while (snake.indexOf((food = random(0, 400))) >= 0); // 重新刷新食物,注意食物应不在蛇内部

    我们接下来通过canvas进行绘制

    首先在js中获取canvas组件

    const canvas = document.getElementById("canvas");const ctx = canvas.getContext("2d");

    然后写绘制函数用于绘制方格,绘制方格的时候注意我们预留1px作为边框,即我们所画的方格的边长为18,我们实际填充的是18 × 18 18\times 1818×18的方块,方块的x、y坐标(方块的左上角)的计算也需要注意加上1px

    注:canvas的原点坐标在左上角,往右为x轴正方向,往下为y轴正方向

    // 用于绘制蛇或者是食物代表的方块,seat为方块位置,取值为0~399,color为颜色function draw(seat, color) {
        ctx.fillStyle = color; // 填充颜色
        // fillRect的四个参数分别表示要绘制方块的x坐标,y坐标,长,宽,这里为了美观留了1px用于边框
        ctx.fillRect(
            (seat % 20) * 20 + 1,
            Math.floor(seat / 20) * 20 + 1,
            18,
            18
        );}

    让蛇动起来

    我们要想让蛇动起来,首先要规定蛇运动的方向,我们用一个变量direction来表示蛇运动的方向,其取值范围为{1,-1,20,-20},1 表示向右,-1 表示向左,20 表示向下,-20 表示向上,运动时只需要将蛇头的位置加上direction就可以表示新蛇头的位置,这样我们就可以表示蛇的运动了。

    那么如何让蛇动起来呢,对于蛇的每次移动,我们需要完成下面几个基本操作:

    1. 将蛇运动的下一个位置变成新蛇头
      • 将下一个位置加入蛇队列
      • 绘制下一个方块为浅蓝色
    2. 把旧蛇头变成蛇身
      • 绘制旧蛇头为浅灰色
    3. 删除旧蛇尾
      • 将旧蛇尾弹出蛇队列
      • 绘制旧蛇尾位置为白色

    当蛇吃掉食物时(蛇的下一个位置为食物所在位置)则需更新食物的位置,并绘制新食物为黄色,此时则不需要删除旧蛇尾,这样可以实现蛇吃完食物后长度的增加功能

    我们需要写一个函数实现上述操作,并且要不断地调用这个函数,从而实现页面的刷新,即我们所说的动态效果

    n = snake[0] + direction; // 找到新蛇头坐标snake.unshift(n); // 添加新蛇头draw(n, "#1a8dcc"); // 绘制新蛇头为浅蓝色draw(snake[1], "#cececc"); // 将原来的蛇头(浅蓝色)变成蛇身(浅灰色)if (n == food) {
        while (snake.indexOf((food = random(0, 400))) >= 0); // 重新刷新食物,注意食物应不在蛇内部
        draw(food, "Yellow"); // 绘制食物} else {
        draw(snake.pop(), "White"); // 将原来的蛇尾绘制成白色}

    接下来,我们需要实现通过键盘控制蛇的运动

    我们需要获取键盘的key值,然后通过一个监听函数去监听键盘按下的操作,我们这里通过上下左右键(还拓展了WSAD键和IJKL键控制上下左右方向),同时设置一个变量n表示下一步的方向

    // 用于绑定键盘上下左右事件,上下左右方向键,代表上下左右方向document.onkeydown = function (event) {
        const keycode = event.keyCode;
        if (keycode = 73) {
            // i 73 j 74 k 75 l 76
            n = [-20, -1, 20, 1][keycode - 73] || direction;
        } else {
            switch (keycode) {
                case 87: //w
                    n = -20;
                    break;
                case 83: //s
                    n = 20;
                    break;
                case 65: //a
                    n = -1;
                    break;
                case 68: //d
                    n = 1;
                    break;
                default:
                    n = direction;
            }
        }
        direction = snake[1] - snake[0] == n ? direction : n; // 若方向与原方向相反,则方向不变};

    设定游戏规则

    贪吃蛇的最基础的游戏规则如下:

    1. 蛇如果撞到墙或者蛇的身体或尾巴则游戏结束
    2. 蛇如果吃掉食物则蛇的长度会增加(上一步已经实现)且得分会增加

    先实现第一个,具体如下:

    注:下面的一段代码中的n即为新蛇头的位置

    // 判断蛇头是否撞到自己或者是否超出边界if (
        snake.indexOf(n, 1) > 0 ||
        n  399 ||
        (direction == 1 && n % 20 == 0) ||
        (direction == -1 && n % 20 == 19)) {
        game_over();}

    接下来我们实现得分统计,对于得分的计算我们只需要设置一个变量score,用于统计得分,然后每吃一个食物,该变量加一,然后将得分信息更新到网页相应位置

    score = score + 1;score_cal.innerText = "目前得分: " + score; // 更新得分

    设置难度等级

    我们在网页上设置一个单选框,用于设置难度等级

    
    
        难度等级:                               

    效果如下:

    スネーク ゲームの JavaScript 実装の共有例

    那么我们后台具体如何设置难度等级的功能呢?

    我们采取调用蛇运动的函数的时间间隔来代替难度,时间间隔越小则难度越大,我们分三级:简单、中级、困难

    我们创建一个时间间隔变量time_internal,然后用一个函数获取单选框的取值,并将相应模式的时间间隔赋值给time_internal

    // 用刷新间隔代表蛇的速度,刷新间隔越长,则蛇的速度越慢const simply_mode = 200;const middle_mode = 100;const hard_mode = 50;var time_internal = simply_mode; // 刷新时间间隔,用于调整蛇的速度,默认为简单模式// 同步难度等级function syncMode() {
        var mode_value = "";
        for (var i = 0; i <p>最后只需要在蛇每次移动前调用一次上述函数<code>syncMode()</code>就可以实现难度切换,至于蛇的速度的具体调节且看下面如何讲解</p><h4 id="strong-设置开始与暂停-strong"><strong>设置开始与暂停</strong></h4><p>如何实现蛇的移动动态效果,如何暂停,如何继续,速度如何调节,这就涉及到JavaScript的动画的部分了,建议看下《JavaScript高级程序设计(第4版)》第18章的部分,讲的很详细。</p><p>在最初的“20行JavaScript实现贪吃蛇”中并没有实现开始与暂停,其实现动态效果的方法为设置一个立即执行函数<code>!function() {}();</code>,然后在该函数中使用<code>setTimeout(arguments.callee, 150);</code>,每隔0.15秒调用此函数,从而实现了网页的不断刷新,也就是所谓的动态效果。</p><p>后来,我通过web课程老师的案例(弹球游戏)中了解到requestAnimationFrame方法可以实现动画效果,于是我便百度查询,最后在翻书《JavaScript高级程序设计(第4版)》第18章动画与Canvas图形中得到启发–如何实现开始与取消,如何自定义时间间隔(实现难度调节,蛇的速度)</p><p>书中给出的开始动画与取消动画的方法如下:</p><blockquote><p>注:为了便于理解,自己修改过原方法</p></blockquote><pre class="brush:php;toolbar:false">var requestID; // 用于标记请求ID与取消动画
    function updateProgress() { 
    	// do something...
        requestID = requestAnimationFrame(updateProgress); // 调用后在函数中反复调用该函数
    } 
    id = requestAnimationFrame(updateProgress); // 第一次调用(即开始动画)
    
    cancelAnimationFrame(requestID); // 取消动画

    书中讲述道:

    requestAnimationFrame()已经解决了浏览器不知道 JavaScript 动画何时开始的问题, 以及最佳间隔是多少的问题。······

    传给 requestAnimationFrame()的函数实际上可以接收一个参数,此参数是一个 DOMHighResTimeStamp 的实例(比如 performance.now()返回的值),表示下次重绘的时间。这一点非常重要: requestAnimationFrame()实际上把重绘任务安排在了未来一个已知的时间点上,而且通过这个参数 告诉了开发者。基于这个参数,就可以更好地决定如何调优动画了。

    requestAnimationFrame()返回一个请求 ID,可以用于通过另一个 方法 cancelAnimationFrame()来取消重绘任务

    书中同样给出了如何控制时间间隔的方法:

    书中讲述道:

    配合使用一个计时器来限制重绘操作执行的频率。这样,计时器可以限制实际的操作执行间隔,而 requestAnimationFrame 控制在浏览器的哪个渲染周期中执行。下面的例子可以将回调限制为不超过 50 毫秒执行一次

    具体方法如下:

    let enabled = true; function expensiveOperation() { 
    	console.log('Invoked at', Date.now()); } window.addEventListener('scroll', () => { 
     if (enabled) { 
         enabled = false; 
         requestAnimationFrame(expensiveOperation); 
         setTimeout(() => enabled = true, 50); 
     } });

    由上面的方法我得到启发,在此处我们可以设置一个控制函数,用于控制隔一定的时间调用一次蛇运动的函数,实现如下:

    // 控制游戏的刷新频率,每隔time_internal时间间隔刷新一次function game_control(){
        if(enabled){
            enabled = false;
            requestAnimationFrame(run_game);
            setTimeout(() => enabled = true, time_internal);
        }
        run_id = requestAnimationFrame(game_control);}// 启动或继续游戏function run_game() {
        syncMode(); // 同步难度等级
        n = snake[0] + direction; // 找到新蛇头坐标
        snake.unshift(n); // 添加新蛇头
        // 判断蛇头是否撞到自己或者是否超出边界
        if (
            snake.indexOf(n, 1) > 0 ||
            n  399 ||
            (direction == 1 && n % 20 == 0) ||
            (direction == -1 && n % 20 == 19)
        ) {
            game_over();
        }
        draw(n, "#1a8dcc"); // 绘制新蛇头为浅蓝色
        draw(snake[1], "#cececc"); // 将原来的蛇头(浅蓝色)变成蛇身(浅灰色)
        if (n == food) {
            score = score + 1;
            score_cal.innerText = "目前得分: " + score; // 更新得分
            while (snake.indexOf((food = random(0, 400))) >= 0); // 重新刷新食物,注意食物应不在蛇内部
            draw(food, "Yellow"); // 绘制食物
        } else {
            draw(snake.pop(), "White"); // 将原来的蛇尾绘制成白色
        }
        // setTimeout(arguments.callee, time_internal); //之前的方案,无法实现暂停和游戏的继续}

    至于暂停只需要在特定的位置调用cancelAnimationFrame(run_id);就可以了

    设置游戏结束后续操作

    我想的是在游戏结束后出现一个“弹窗”,显示最终得分和是否再来一把

    效果如下:

    スネーク ゲームの JavaScript 実装の共有例

    首先,我们实现网页的弹窗,通过调研发现JavaScript的弹窗可以通过alert()的方法实现,不过在网页上直接弹窗感觉不太美观,而且影响体验,于是我想了一下,可以采用一个p标签实现伪弹窗,在需要显示的时候设置其display属性为block,不需要显示的时候设置其display属性为none,就类似于Photoshop里面的图层概念,这样我们就可以在平常的时候设置其display属性为none触发game over时设置其display属性为block,实现如下:

    <p>
        </p><h3 id="游戏结束">游戏结束!</h3>
        <h3 id="您的最终得分为-分">您的最终得分为: 0分</h3>
        <button>再来一把</button>
        <button>取消</button>

    其CSS部分如下:

    #game_over {
        display: none; /* 设置game over 窗口不可见 */
        position: fixed;
        top: 190px;
        left: 65px;
        width: 280px;
        height: 160px;
        background-color: aliceblue;
        border-radius: 5px;
        border: 1px solid #000; /* 设置边框线 */}#once_again {
        position: relative;
        left: 20px;}#cancel {
        position: relative;
        left: 50px;}

    接下来,我们需要实现game over的后续操作:暂停动画,显示得分,显示“弹窗”

    function game_over(){
        cancelAnimationFrame(run_id);
        game_over_score.innerText = "您的最终得分为: " + score + "分";
        game_over_p.style.display = "block";}

    实现人机交互页面

    接下来的部分就是提高用户体验的部分,具体实现下列功能/操作

    1. 游戏说明
    2. 人机交互按钮:开始/继续,暂停,重新开始
    3. 快捷键
      • 由于在游戏过程中通过鼠标移动到暂停键暂停,时间上太慢,可能造成游戏终止,故应该设置开始/继续(C)、暂停(P)、重新开始(R)的快捷键
      • 有些电脑键盘的上下左右键较小,操作起来不太方便,可以添加WSAD或者IJKL扩展,用于控制上下左右方向

    效果如下:

    スネーク ゲームの JavaScript 実装の共有例

    至于写界面的代码,可以看文末的完整代码,这里就稍微讲解下绑定按键点击事件与绑定快捷键

    我们首先看下绑定按键点击事件,点击”开始/继续“只需要调用requestAnimationFrame(game_control);,点击”暂停“只需要调用cancelAnimationFrame(run_id);

    // 绑定开始按钮点击事件start_btn.onclick = function () {
        run_id = requestAnimationFrame(game_control);};// 绑定暂停按钮点击事件pause_btn.onclick = function () {
        cancelAnimationFrame(run_id);};

    点击“重新开始”的话,则需要先暂停动画,然后删除画面上的蛇和食物,初始化所有设置,然后再调用requestAnimationFrame(game_control);开始游戏

    注:初始化时需要初始化得分与难度等级,这里解释下为什么要将第一个食物设置为蛇头下一个位置,因为这样的话蛇会自动先吃一个食物,继而可以通过“开始 / 继续” 一个按钮实现开始和继续操作,同时run_game()函数中的食物绘制是在蛇吃到食物之后,保证第一个食物顺利绘制,这样的话score就需要初始化为-1

    // 用于初始化游戏各项参数function init_game() {
        snake = [41, 40]; 
        direction = 1; 
        food = 42;
        score = -1; 
        time_internal = simply_mode;
        enabled = true;
        score_cal.innerText = "目前得分: 0分"; // 更新得分
        mode_item[0].checked = true; // 重置难度等级为简单}// 绑定重新开始按钮点击事件restart_btn.onclick = function () {
        cancelAnimationFrame(run_id);
        // 将原有的食物和蛇的方块都绘制成白色
        for(var i = 0; i <p>接下来,我们绑定game over中的两个按键”再来一把“和”取消“</p><p>”再来一把“只需要完成“重新开始”里面的事件即可,”取消“只需要完成”重新开始“点击操作中除了开始游戏的部分,即除了<code>run_id = requestAnimationFrame(game_control);</code></p><p>这两个按钮都需要设置”弹窗“的<code>display</code>属性为<code>none</code></p><p>具体实现如下:</p><pre class="brush:php;toolbar:false">// 绑定游戏结束时的取消按钮点击事件cancel_btn.onclick = function () {
        for(var i = 0; i <p>最后,我们来讲解下如何设置快捷键,快捷键只需要用JavaScript模拟点击对应的按钮即可,实现如下:</p><pre class="brush:php;toolbar:false">// 同时绑定R 重启,P 暂停,C 继续document.onkeydown = function (event) {
        const keycode = event.keyCode;
        if(keycode == 82){
            // R 重启
            restart_btn.onclick();
        } else if(keycode == 80){
            // P 暂停
            pause_btn.onclick();
        } else if(keycode == 67){
            // C 继续
            start_btn.onclick();
        } };

    问题、调试与解决

    注: 此部分为本人在实现过程中出现的bug、调试过程以及解决方法,感兴趣的可以看看,不感兴趣的也可以跳过此部分,直接看文末的完整代码

    问题1:点击暂停和开始,游戏正常开始,按P也可以实现暂停,按C则画面出现蛇所在的方格乱跳,无法正常开始,但是按C的操作中只模拟了”开始 / 继续“按钮的点击?

    效果如下:

    スネーク ゲームの JavaScript 実装の共有例

    调试过程:因为蛇头的位置是由direction控制的,故想到设置断点,同时监测这个变量的值的变化,发现这个值在按完P和C时被更新成很大的数,进而去找direction在哪里被更新,发现点击P或C后还需要执行下面这一行代码,而实际上是不需要的

    direction = snake[1] - snake[0] == n ? direction : n; // 若方向与原方向相反,则方向不变

    解决方法:只需要执行完对应的模拟鼠标点击相应按钮事件之后就直接return就可以了

    原代码与修改后的代码如下:

    document.onkeydown = function (event) {
        const keycode = event.keyCode;
        if(keycode == 82){
            // R 重启
            restart_btn.onclick();
            return; // 后来加上的
        } else if(keycode == 80){
            // P 暂停
            pause_btn.onclick();
            return; // 后来加上的
        } else if(keycode == 67){
            // C 继续
            start_btn.onclick();
            return; // 后来加上的
        } else if (keycode = 73) {
            // i 73 j 74 k 75 l 76
            n = [-20, -1, 20, 1][keycode - 73] || direction;
        } else {
            switch (keycode) {
                case 87: //w
                    n = -20;
                    break;
                case 83: //s
                    n = 20;
                    break;
                case 65: //a
                    n = -1;
                    break;
                case 68: //d
                    n = 1;
                    break;
                default:
                    n = direction;
            }
        }
        direction = snake[1] - snake[0] == n ? direction : n; // 若方向与原方向相反,则方向不变};

    问题2:调整难度等级后,蛇的速度并没有发生改变,但是通过console.log()发现确实调用了同步难度模式的函数?

    调试过程:在同步难度等级的函数中设置console.log()方法,输出time_internal变量,同时设断点调试,发现time_internal变量不发生变化,mode_value变量始终为undefined,最后发现应该是值传递时的错误mode_value = mode_item.value;

    解决方法:修改值传递的方法,加上索引,改为mode_value = mode_item[i].value;

    原代码和修改后的代码如下:

    // 同步难度等级function syncMode() {
        var mode_value = "";
        for (var i = 0; i 

    完整代码

    nbsp;html>
      
        
        
        
        贪吃蛇小游戏
        
      
      
        

    贪吃蛇小游戏

        <canvas></canvas>

    游戏结束!

    您的最终得分为: 0分


    游戏说明:

    1. 用键盘上下左右键(或者IJKL键,或者WSAD键)控制蛇的方向,寻找吃的东西
    2. 每吃一口就能得到一定的积分,同时蛇的身子会越吃越长
    3. 不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴
    4. 在下方单选框中选择难度等级,点击"开始 / 继续"即开始游戏,点击"暂停"则暂停游戏,
        再点击"开始 / 继续"继续游戏,点击"重新开始"则重新开始游戏
    5快捷键: "C"表示开始或继续,"P"表示暂停,"R"表示重新开始

             

    目前得分: 0分

        
          难度等级:                                                
        
                       <script> const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); const start_btn = document.getElementById("startButton"); const pause_btn = document.getElementById("pauseButton"); const restart_btn = document.getElementById("restartButton"); const once_again_btn = document.getElementById("once_again"); const cancel_btn = document.getElementById("cancel"); const game_over_p = document.getElementById("game_over"); const game_over_score = document.getElementById("game_over_score"); const score_cal = document.getElementById("score"); const mode_item = document.getElementsByName("mode"); // 用刷新间隔代表蛇的速度,刷新间隔越长,则蛇的速度越慢 const simply_mode = 200; const middle_mode = 100; const hard_mode = 50; //注意要改为var const是不会修改的 var snake = [41, 40]; // 蛇身体队列 var direction = 1; // 方向:1为向右,-1为向左,20为向下,-20为向上 var food = 42; // 食物位置,取值为0~399 var n; // 蛇的下一步的方向(由键盘和蛇的原方向决定) var score = -1; // 得分 var time_internal = simply_mode; // 刷新时间间隔,用于调整蛇的速度,默认为简单模式 let enabled = true; // 用于控制是否刷新,实现通过一定频率刷新 let run_id; // 请求ID,用于暂停功能 // 产生min~max的随机整数,用于随机产生食物的位置 function random(min, max) { const num = Math.floor(Math.random() * (max - min)) + min; return num; } // 用于绘制蛇或者是食物代表的方块,seat为方块位置,取值为0~399,color为颜色 function draw(seat, color) { ctx.fillStyle = color; // 填充颜色 // fillRect的四个参数分别表示要绘制方块的x坐标,y坐标,长,宽,这里为了美观留了1px用于边框 ctx.fillRect( (seat % 20) * 20 + 1, Math.floor(seat / 20) * 20 + 1, 18, 18 ); } // 同步难度等级 function syncMode() { var mode_value = ""; for (var i = 0; i < mode_item.length; i++) { if (mode_item[i].checked) { mode_value = mode_item[i].value;//原来是mode_item.value } } switch (mode_value) { case "simply": time_internal = simply_mode; break; case "middle": time_internal = middle_mode; break; case "hard": time_internal = hard_mode; break; } } // 用于绑定键盘上下左右事件,我设置了wsad,或者ijkl,或者上下左右方向键,代表上下左右方向 // 同时绑定R 重启,P 暂停,C 继续,注意:若是这几个键则不需要更新direction的值,操作结束后直接返回即可 document.onkeydown = function (event) { const keycode = event.keyCode; if(keycode == 82){ // R 重启 restart_btn.onclick(); return; } else if(keycode == 80){ // P 暂停 pause_btn.onclick(); return; } else if(keycode == 67){ // C 继续 start_btn.onclick(); return; } else if (keycode <= 40) { // 上 38 下 40 左 37 右 39 n = [-1, -20, 1, 20][keycode - 37] || direction; // 若keycode为其他值,则方向不变 } else if (keycode <= 76 && keycode >= 73) { // i 73 j 74 k 75 l 76 n = [-20, -1, 20, 1][keycode - 73] || direction; } else { switch (keycode) { case 87: //w n = -20; break; case 83: //s n = 20; break; case 65: //a n = -1; break; case 68: //d n = 1; break; default: n = direction; } } direction = snake[1] - snake[0] == n ? direction : n; // 若方向与原方向相反,则方向不变 }; // 用于初始化游戏各项参数 function init_game() { snake = [41, 40]; direction = 1; food = 42; score = -1; time_internal = simply_mode; enabled = true; score_cal.innerText = "目前得分: 0分"; // 更新得分 mode_item[0].checked = true; // 重置难度等级为简单 } function game_over(){ cancelAnimationFrame(run_id); game_over_score.innerText = "您的最终得分为: " + score + "分"; game_over_p.style.display = "block"; } // 启动或继续游戏 function run_game() { syncMode(); // 同步难度等级 n = snake[0] + direction; // 找到新蛇头坐标 snake.unshift(n); // 添加新蛇头 // 判断蛇头是否撞到自己或者是否超出边界 if ( snake.indexOf(n, 1) > 0 || n < 0 || n > 399 || (direction == 1 && n % 20 == 0) || (direction == -1 && n % 20 == 19) ) { game_over(); } draw(n, "#1a8dcc"); // 绘制新蛇头为浅蓝色 draw(snake[1], "#cececc"); // 将原来的蛇头(浅蓝色)变成蛇身(浅灰色) if (n == food) { score = score + 1; score_cal.innerText = "目前得分: " + score; // 更新得分 while (snake.indexOf((food = random(0, 400))) >= 0); // 重新刷新食物,注意食物应不在蛇内部 draw(food, "Yellow"); // 绘制食物 } else { draw(snake.pop(), "White"); // 将原来的蛇尾绘制成白色 } // setTimeout(arguments.callee, time_internal); //之前的方案,无法实现暂停和游戏的继续 } // 控制游戏的刷新频率,每隔time_internal时间间隔刷新一次 function game_control(){ if(enabled){ enabled = false; requestAnimationFrame(run_game); setTimeout(() => enabled = true, time_internal); } run_id = requestAnimationFrame(game_control); } // 绑定开始按钮点击事件 start_btn.onclick = function () { run_id = requestAnimationFrame(game_control); }; // 绑定暂停按钮点击事件 pause_btn.onclick = function () { cancelAnimationFrame(run_id); }; // 绑定重新开始按钮点击事件 restart_btn.onclick = function () { cancelAnimationFrame(run_id); // 将原有的食物和蛇的方块都绘制成白色 for(var i = 0; i < snake.length; i++){ draw(snake[i], "White"); } draw(food, "White"); // 初始化游戏各项参数 init_game(); run_id = requestAnimationFrame(game_control); }; // 绑定游戏结束时的取消按钮点击事件 cancel_btn.onclick = function () { for(var i = 0; i < snake.length; i++){ draw(snake[i], "White"); } draw(food, "White"); init_game(); game_over_p.style.display = "none"; } // 绑定游戏结束时的再来一把按钮点击事件 once_again_btn.onclick = function () { for(var i = 0; i < snake.length; i++){ draw(snake[i], "White"); } draw(food, "White"); init_game(); game_over_p.style.display = "none"; run_id = requestAnimationFrame(game_control); } </script>   

    【相关推荐:javascript学习教程

以上がスネーク ゲームの JavaScript 実装の共有例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事はCSDNで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
Python vs. JavaScript:開発環境とツールPython vs. JavaScript:開発環境とツールApr 26, 2025 am 12:09 AM

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。

JavaScriptはCで書かれていますか?証拠を調べるJavaScriptはCで書かれていますか?証拠を調べるApr 25, 2025 am 12:15 AM

はい、JavaScriptのエンジンコアはCで記述されています。1)C言語は、JavaScriptエンジンの開発に適した効率的なパフォーマンスと基礎となる制御を提供します。 2)V8エンジンを例にとると、そのコアはCで記述され、Cの効率とオブジェクト指向の特性を組み合わせて書かれています。3)JavaScriptエンジンの作業原理には、解析、コンパイル、実行が含まれ、C言語はこれらのプロセスで重要な役割を果たします。

JavaScriptの役割:WebをインタラクティブでダイナミックにするJavaScriptの役割:WebをインタラクティブでダイナミックにするApr 24, 2025 am 12:12 AM

JavaScriptは、Webページのインタラクティブ性とダイナミズムを向上させるため、現代のWebサイトの中心にあります。 1)ページを更新せずにコンテンツを変更できます。2)Domapiを介してWebページを操作する、3)アニメーションやドラッグアンドドロップなどの複雑なインタラクティブ効果、4)ユーザーエクスペリエンスを改善するためのパフォーマンスとベストプラクティスを最適化します。

CおよびJavaScript:接続が説明しましたCおよびJavaScript:接続が説明しましたApr 23, 2025 am 12:07 AM

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

Webサイトからアプリまで:JavaScriptの多様なアプリケーションWebサイトからアプリまで:JavaScriptの多様なアプリケーションApr 22, 2025 am 12:02 AM

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Python vs. JavaScript:ユースケースとアプリケーションと比較されますPython vs. JavaScript:ユースケースとアプリケーションと比較されますApr 21, 2025 am 12:01 AM

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

JavaScript通訳者とコンパイラにおけるC/Cの役割JavaScript通訳者とコンパイラにおけるC/Cの役割Apr 20, 2025 am 12:01 AM

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

JavaScript in Action:実際の例とプロジェクトJavaScript in Action:実際の例とプロジェクトApr 19, 2025 am 12:13 AM

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール