好玩的小游戏系列 (一)基于html+js 原生贪吃蛇

简介: 好玩的小游戏系列 (一)基于html+js 原生贪吃蛇

一朵花如果只被用来观赏那只呈现出它的外在意义只是它生命的一部分若是不能够将其内在更实质的美发挥出来充其量也不过就是一朵死的花而已。

目录

一、前言

二、代码介绍

三、效果显示

四、编码实现

index.html

jquery-1.10.2.js

五、获取源码

       获取源码?私信?关注?点赞?收藏?

一、前言

贪吃蛇是一款经典的小游戏。初始是像素版本,后来又衍生出3D版本、多人对战版本等。

贪食蛇游戏操作简单,可玩性比较高。这个游戏难度最大的不是蛇长得很长的时候,而是开始。那个时候蛇身很短,看上去难度不大,却最容易死掉,因为把玩一条小短蛇让人容易走神,失去耐心。由于难度小,你会不知不觉加快调整方向的速度,在游走自如的时候蛇身逐渐加长了,而玩家却没有意识到危险。

贪食蛇的另一个危险期在于游戏开始几十秒之后。由于玩家的注意力高度集中,精神紧张,此时局面稍好,就会不由自主地想放松一下,结果手指一松劲,贪食蛇就死了。所以贪食蛇可以算作一个敏捷型的小游戏。

二、代码介绍

一款简单的 HTML+JS 原生贪吃蛇小游戏

1、HTML

2、JS

3、舒适的画面感

4、流畅的游戏体验

三、效果显示  

我们一起回味一下好玩的贪吃蛇吧!!!

A.

B.

舒适美观的画面,灵动的体验!!!

是否想体验一下呢?

四、编码实现

由于文章篇幅限制,部分代码将不予展示,但会将完整代码文件放在下方

注意路径(⊙o⊙)?

o(* ̄▽ ̄*)ブ

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>JS贪吃蛇</title>
    <script src="static/js/jquery-1.10.2.js"></script>
    <style>
      @font-face {
        font-family: "game";
        src: url("https://fonts.googleapis.com/css2?family=Poppins:wght@500;800&display=swap");
      }
      * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
      }
      button:focus {
        outline: 0;
      }
      html,
      body {
        height: 100%;
        font-family: "Poppins", sans-serif;
        color: #6e7888;
      }
      body {
        background-color: #222738;
        display: flex;
        justify-content: center;
        align-items: center;
        color: #6e7888;
      }
      canvas {
        background-color: #181825;
      }
      .container {
        display: flex;
        width: 100%;
        height: 100%;
        flex-flow: column wrap;
        justify-content: center;
        align-items: center;
      }
      #ui {
        display: flex;
        align-items: center;
        font-size: 10px;
        flex-flow: column;
        margin-left: 10px;
      }
      h2 {
        font-weight: 200;
        transform: rotate(270deg);
      }
      #score {
        margin-top: 20px;
        font-size: 30px;
        font-weight: 800;
      }
      .noselect {
        user-select: none;
      }
      #replay {
        font-size: 10px;
        padding: 10px 20px;
        background: #6e7888;
        border: none;
        color: #222738;
        border-radius: 20px;
        font-weight: 800;
        transform: rotate(270deg);
        cursor: pointer;
        transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
      }
      #replay:hover {
        background: #a6aab5;
        background: #4cffd7;
        transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
      }
      #replay svg {
        margin-right: 8px;
      }
      @media (max-width: 600px) {
        #replay {
          margin-bottom: 20px;
        }
        #replay,
        h2 {
          transform: rotate(0deg);
        }
        #ui {
          flex-flow: row wrap;
          margin-bottom: 20px;
        }
        #score {
          margin-top: 0;
          margin-left: 20px;
        }
        .container {
          flex-flow: column wrap;
        }
      }
      #author {
        width: 100%;
        bottom: 40px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        font-weight: 600;
        color: inherit;
        text-transform: uppercase;
        padding-left: 35px;
      }
      #author span {
        font-size: 10px;
        margin-left: 20px;
        color: inherit;
        letter-spacing: 4px;
      }
      #author h1 {
        font-size: 25px;
      }
      .wrapper {
        display: flex;
        flex-flow: row wrap;
        justify-content: center;
        align-items: center;
        margin-bottom: 20px;
      }
    </style>
  </head>
  <body>
    <div class="container noselect">
      <div class="wrapper">
        <button id="replay">
          <i class="fas fa-play"></i>
          RESTART
        </button>
        <div id="canvas"></div>
        <div id="ui">
          <h2>SCORE</h2>
          <span id="score">00</span>
        </div>
      </div>
      <div id="author">
        <h1>SNAKE</h1>
        <span><p>小键盘方向键控制</p></span>
      </div>
    </div>
    <script>
      /** 
This is a snake game I made with Vanilla Javascript.
Follow me on twitter @fariatondo
**/
      let dom_replay = document.querySelector("#replay");
      let dom_score = document.querySelector("#score");
      let dom_canvas = document.createElement("canvas");
      document.querySelector("#canvas").appendChild(dom_canvas);
      let CTX = dom_canvas.getContext("2d");
      const W = (dom_canvas.width = 400);
      const H = (dom_canvas.height = 400);
      let snake,
        food,
        currentHue,
        cells = 20,
        cellSize,
        isGameOver = false,
        tails = [],
        score = 00,
        maxScore = window.localStorage.getItem("maxScore") || undefined,
        particles = [],
        splashingParticleCount = 20,
        cellsCount,
        requestID;
      let helpers = {
        Vec: class {
          constructor(x, y) {
            this.x = x;
            this.y = y;
          }
          add(v) {
            this.x += v.x;
            this.y += v.y;
            return this;
          }
          mult(v) {
            if (v instanceof helpers.Vec) {
              this.x *= v.x;
              this.y *= v.y;
              return this;
            } else {
              this.x *= v;
              this.y *= v;
              return this;
            }
          }
        },
        isCollision(v1, v2) {
          return v1.x == v2.x && v1.y == v2.y;
        },
        garbageCollector() {
          for (let i = 0; i < particles.length; i++) {
            if (particles[i].size <= 0) {
              particles.splice(i, 1);
            }
          }
        },
        drawGrid() {
          CTX.lineWidth = 1.1;
          CTX.strokeStyle = "#232332";
          CTX.shadowBlur = 0;
          for (let i = 1; i < cells; i++) {
            let f = (W / cells) * i;
            CTX.beginPath();
            CTX.moveTo(f, 0);
            CTX.lineTo(f, H);
            CTX.stroke();
            CTX.beginPath();
            CTX.moveTo(0, f);
            CTX.lineTo(W, f);
            CTX.stroke();
            CTX.closePath();
          }
        },
        randHue() {
          return ~~(Math.random() * 360);
        },
        hsl2rgb(hue, saturation, lightness) {
          if (hue == undefined) {
            return [0, 0, 0];
          }
          var chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;
          var huePrime = hue / 60;
          var secondComponent = chroma * (1 - Math.abs((huePrime % 2) - 1));
          huePrime = ~~huePrime;
          var red;
          var green;
          var blue;
          if (huePrime === 0) {
            red = chroma;
            green = secondComponent;
            blue = 0;
          } else if (huePrime === 1) {
            red = secondComponent;
            green = chroma;
            blue = 0;
          } else if (huePrime === 2) {
            red = 0;
            green = chroma;
            blue = secondComponent;
          } else if (huePrime === 3) {
            red = 0;
            green = secondComponent;
            blue = chroma;
          } else if (huePrime === 4) {
            red = secondComponent;
            green = 0;
            blue = chroma;
          } else if (huePrime === 5) {
            red = chroma;
            green = 0;
            blue = secondComponent;
          }
          var lightnessAdjustment = lightness - chroma / 2;
          red += lightnessAdjustment;
          green += lightnessAdjustment;
          blue += lightnessAdjustment;
          return [
            Math.round(red * 255),
            Math.round(green * 255),
            Math.round(blue * 255),
          ];
        },
        lerp(start, end, t) {
          return start * (1 - t) + end * t;
        },
      };
      let KEY = {
        ArrowUp: false,
        ArrowRight: false,
        ArrowDown: false,
        ArrowLeft: false,
        resetState() {
          this.ArrowUp = false;
          this.ArrowRight = false;
          this.ArrowDown = false;
          this.ArrowLeft = false;
        },
        listen() {
          addEventListener(
            "keydown",
            (e) => {
              if (e.key === "ArrowUp" && this.ArrowDown) return;
              if (e.key === "ArrowDown" && this.ArrowUp) return;
              if (e.key === "ArrowLeft" && this.ArrowRight) return;
              if (e.key === "ArrowRight" && this.ArrowLeft) return;
              this[e.key] = true;
              Object.keys(this)
                .filter(
                  (f) => f !== e.key && f !== "listen" && f !== "resetState"
                )
                .forEach((k) => {
                  this[k] = false;
                });
            },
            false
          );
        },
      };
      class Snake {
        constructor(i, type) {
          this.pos = new helpers.Vec(W / 2, H / 2);
          this.dir = new helpers.Vec(0, 0);
          this.type = type;
          this.index = i;
          this.delay = 5;
          this.size = W / cells;
          this.color = "white";
          this.history = [];
          this.total = 1;
        }
        draw() {
          let { x, y } = this.pos;
          CTX.fillStyle = this.color;
          CTX.shadowBlur = 20;
          CTX.shadowColor = "rgba(255,255,255,.3 )";
          CTX.fillRect(x, y, this.size, this.size);
          CTX.shadowBlur = 0;
          if (this.total >= 2) {
            for (let i = 0; i < this.history.length - 1; i++) {
              let { x, y } = this.history[i];
              CTX.lineWidth = 1;
              CTX.fillStyle = "rgba(225,225,225,1)";
              CTX.fillRect(x, y, this.size, this.size);
            }
          }
        }
        walls() {
          let { x, y } = this.pos;
          if (x + cellSize > W) {
            this.pos.x = 0;
          }
          if (y + cellSize > W) {
            this.pos.y = 0;
          }
          if (y < 0) {
            this.pos.y = H - cellSize;
          }
          if (x < 0) {
            this.pos.x = W - cellSize;
          }
        }
        controlls() {
          let dir = this.size;
          if (KEY.ArrowUp) {
            this.dir = new helpers.Vec(0, -dir);
          }
          if (KEY.ArrowDown) {
            this.dir = new helpers.Vec(0, dir);
          }
          if (KEY.ArrowLeft) {
            this.dir = new helpers.Vec(-dir, 0);
          }
          if (KEY.ArrowRight) {
            this.dir = new helpers.Vec(dir, 0);
          }
        }
        selfCollision() {
          for (let i = 0; i < this.history.length; i++) {
            let p = this.history[i];
            if (helpers.isCollision(this.pos, p)) {
              isGameOver = true;
            }
          }
        }
        update() {
          this.walls();
          this.draw();
          this.controlls();
          if (!this.delay--) {
            if (helpers.isCollision(this.pos, food.pos)) {
              incrementScore();
              particleSplash();
              food.spawn();
              this.total++;
            }
            this.history[this.total - 1] = new helpers.Vec(
              this.pos.x,
              this.pos.y
            );
            for (let i = 0; i < this.total - 1; i++) {
              this.history[i] = this.history[i + 1];
            }
            this.pos.add(this.dir);
            this.delay = 5;
            this.total > 3 ? this.selfCollision() : null;
          }
        }
      }
      class Food {
        constructor() {
          this.pos = new helpers.Vec(
            ~~(Math.random() * cells) * cellSize,
            ~~(Math.random() * cells) * cellSize
          );
          this.color = currentHue = `hsl(${~~(Math.random() * 360)},100%,50%)`;
          this.size = cellSize;
        }
        draw() {
          let { x, y } = this.pos;
          CTX.globalCompositeOperation = "lighter";
          CTX.shadowBlur = 20;
          CTX.shadowColor = this.color;
          CTX.fillStyle = this.color;
          CTX.fillRect(x, y, this.size, this.size);
          CTX.globalCompositeOperation = "source-over";
          CTX.shadowBlur = 0;
        }
        spawn() {
          let randX = ~~(Math.random() * cells) * this.size;
          let randY = ~~(Math.random() * cells) * this.size;
          for (let path of snake.history) {
            if (helpers.isCollision(new helpers.Vec(randX, randY), path)) {
              return this.spawn();
            }
          }
          this.color = currentHue = `hsl(${helpers.randHue()}, 100%, 50%)`;
          this.pos = new helpers.Vec(randX, randY);
        }
      }
      class Particle {
        constructor(pos, color, size, vel) {
          this.pos = pos;
          this.color = color;
          this.size = Math.abs(size / 2);
          this.ttl = 0;
          this.gravity = -0.2;
          this.vel = vel;
        }
        draw() {
          let { x, y } = this.pos;
          let hsl = this.color
            .split("")
            .filter((l) => l.match(/[^hsl()$% ]/g))
            .join("")
            .split(",")
            .map((n) => +n);
          let [r, g, b] = helpers.hsl2rgb(hsl[0], hsl[1] / 100, hsl[2] / 100);
          CTX.shadowColor = `rgb(${r},${g},${b},${1})`;
          CTX.shadowBlur = 0;
          CTX.globalCompositeOperation = "lighter";
          CTX.fillStyle = `rgb(${r},${g},${b},${1})`;
          CTX.fillRect(x, y, this.size, this.size);
          CTX.globalCompositeOperation = "source-over";
        }
        update() {
          this.draw();
          this.size -= 0.3;
          this.ttl += 1;
          this.pos.add(this.vel);
          this.vel.y -= this.gravity;
        }
      }
      function incrementScore() {
        score++;
        dom_score.innerText = score.toString().padStart(2, "0");
      }
      function particleSplash() {
        for (let i = 0; i < splashingParticleCount; i++) {
          let vel = new helpers.Vec(
            Math.random() * 6 - 3,
            Math.random() * 6 - 3
          );
          let position = new helpers.Vec(food.pos.x, food.pos.y);
          particles.push(new Particle(position, currentHue, food.size, vel));
        }
      }
      function clear() {
        CTX.clearRect(0, 0, W, H);
      }
      function initialize() {
        CTX.imageSmoothingEnabled = false;
        KEY.listen();
        cellsCount = cells * cells;
        cellSize = W / cells;
        snake = new Snake();
        food = new Food();
        dom_replay.addEventListener("click", reset, false);
        loop();
      }
      function loop() {
        clear();
        if (!isGameOver) {
          requestID = setTimeout(loop, 1000 / 60);
          helpers.drawGrid();
          snake.update();
          food.draw();
          for (let p of particles) {
            p.update();
          }
          helpers.garbageCollector();
        } else {
          clear();
          gameOver();
        }
      }
      function gameOver() {
        maxScore ? null : (maxScore = score);
        score > maxScore ? (maxScore = score) : null;
        window.localStorage.setItem("maxScore", maxScore);
        CTX.fillStyle = "#4cffd7";
        CTX.textAlign = "center";
        CTX.font = "bold 30px Poppins, sans-serif";
        CTX.fillText("GAME OVER", W / 2, H / 2);
        CTX.font = "15px Poppins, sans-serif";
        CTX.fillText(`SCORE   ${score}`, W / 2, H / 2 + 60);
        CTX.fillText(`MAXSCORE   ${maxScore}`, W / 2, H / 2 + 80);
      }
      function reset() {
        dom_score.innerText = "00";
        score = "00";
        snake = new Snake();
        food.spawn();
        KEY.resetState();
        isGameOver = false;
        clearTimeout(requestID);
        loop();
      }
      initialize();
    </script>
    <script>
      console.log("微信公众号搜索 Enovo开发工厂");
      console.log("CSDN搜索 Enovo_飞鱼");
    </script>
  </body>
</html>

jquery-1.10.2.js

document.write("<script src='https://s1.pstatp.com/cdn/expire-1-M/jquery/1.10.2/jquery.min.js'><\/script>");

五、获取源码

老规矩,先给朋友们看一下完整文件夹

正确的文件如下图

第一步,通过微信公众号下载源码压缩包,解压并打开文件夹,即为上图样式(复制源码请注意路径及文件名)

第二步,点击 html 文件打开即可

作为新年第三辑,希望得到大家的喜欢🙇‍

新的一年,又是一个崭新的开始,充满信心,充满希望,充满阳光,走向明天,走向理想!

在后面的日子里,我也会继续更新一些简单的小游戏内容

不仅仅包括的是 HTML ,会增加 C语言 、Python  等等

如果大家有好的意见或者建议

可以提出来

🙇‍

以上就是本篇文章的全部内容了

获取源码?私信?关注?点赞?收藏?

 👍+✏️+⭐️+🙇‍

相关文章
|
3天前
|
JavaScript
JS实现简单的打地鼠小游戏源码
这是一款基于JS实现简单的打地鼠小游戏源码。画面中的九宫格中随机出现一个地鼠,玩家移动并点击鼠标控制画面中的锤子打地鼠。打中地鼠会出现卡通爆破效果。同时左上角统计打地鼠获得的分数
13 1
|
2天前
|
JavaScript
JS鼠标框选并删除HTML源码
这是一个js鼠标框选效果,可实现鼠标右击出现框选效果的功能。右击鼠标可拖拽框选元素,向下拖拽可实现删除效果,简单实用,欢迎下载
11 4
|
1天前
|
移动开发 HTML5
html5+three.js公路开车小游戏源码
html5公路开车小游戏是一款html5基于three.js制作的汽车开车小游戏源代码,在公路上开车网页小游戏源代码。
10 0
html5+three.js公路开车小游戏源码
|
1天前
|
JavaScript
JS趣味打字金鱼小游戏特效源码
hi fish是一款打字趣味小游戏,捞出海里的鱼,捞的越多越好。这款游戏用于电脑初学者练习打字。初学者可以根据自己的水平设置游戏难度。本段代码可以在各个网页使用,有需要的朋友可以直接下载使用,本段代码兼容目前最新的各类主流浏览器,是一款非常优秀的特效源码!
8 0
JS趣味打字金鱼小游戏特效源码
|
10天前
|
JSON 移动开发 数据格式
html5+css3+js移动端带歌词音乐播放器代码
音乐播放器特效是一款html5+css3+js制作的手机移动端音乐播放器代码,带歌词显示。包括支持单曲循环,歌词显示,歌曲搜索,音量控制,列表循环等功能。利用json获取音乐歌单和歌词,基于html5 audio属性手机音乐播放器代码。
53 6
|
24天前
|
XML 前端开发 JavaScript
前端开发进阶:从HTML到React.js
【10月更文挑战第9天】前端开发进阶:从HTML到React.js
|
1月前
|
JavaScript 前端开发
电话号码正则表达式 代码 javascript+html,JS正则表达式判断11位手机号码
电话号码正则表达式 代码 javascript+html,JS正则表达式判断11位手机号码
77 1
|
25天前
|
JavaScript 前端开发
JavaScript 与 HTML 的结合
JavaScript 与 HTML 的结合
15 0
|
1月前
|
机器学习/深度学习 JSON JavaScript
LangChain-21 Text Splitters 内容切分器 支持多种格式 HTML JSON md Code(JS/Py/TS/etc) 进行切分并输出 方便将数据进行结构化后检索
LangChain-21 Text Splitters 内容切分器 支持多种格式 HTML JSON md Code(JS/Py/TS/etc) 进行切分并输出 方便将数据进行结构化后检索
22 0
|
移动开发 监控 前端开发
【phaser】快速实现HTML5 2d小游戏
使用 js 的 游戏框架 phaser 实现 html 小游戏
364 0
【phaser】快速实现HTML5 2d小游戏