好玩的小游戏系列 (一)基于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  等等

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

可以提出来

🙇‍

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

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

 👍+✏️+⭐️+🙇‍

相关文章
|
1月前
|
移动开发 编解码 前端开发
摸鱼必备-80款在线HTML小游戏
本文推荐了80款精彩的HTML5在线小游戏,涵盖益智、冒险、射击、体育等多种类型,适合各年龄段玩家。无需下载安装,随时随地畅玩。地址:[https://game.share888.top/](https://game.share888.top/)
200 7
摸鱼必备-80款在线HTML小游戏
|
18天前
|
Web App开发 移动开发 HTML5
html5 + Three.js 3D风雪封印在棱镜中的梅花鹿动效源码
html5 + Three.js 3D风雪封印在棱镜中的梅花鹿动效源码。画面中心是悬浮于空的梅花鹿,其四周由白色线段组成了一个6边形将中心的梅花鹿包裹其中。四周漂浮的白雪随着多边形的转动而同步旋转。建议使用支持HTML5与css3效果较好的火狐(Firefox)或谷歌(Chrome)等浏览器预览本源码。
59 2
|
28天前
|
JavaScript 前端开发
js+jquery实现贪吃蛇经典小游戏
本项目采用HTML、CSS、JavaScript和jQuery技术,无需游戏框架支持。通过下载项目文件至本地,双击index.html即可启动贪吃蛇游戏。游戏界面简洁,支持方向键控制蛇移动,空格键实现游戏暂停与恢复功能。
57 14
|
1月前
|
JavaScript
原生JS实现斗地主小游戏
这是一个原生的JS网页版斗地主小游戏,代码注释全。带有斗地主游戏基本的地主、选牌、提示、出牌、倒计时等功能。简单好玩,欢迎下载
33 7
|
1月前
|
前端开发 JavaScript
用HTML CSS JS打造企业级官网 —— 源码直接可用
必看!用HTML+CSS+JS打造企业级官网-源码直接可用,文章代码仅用于学习,禁止用于商业
140 1
|
1月前
|
移动开发 HTML5
HTML5熊猫弹跳手机小游戏源码
一款html5手机端小游戏源码,熊猫跳跃小游戏源码下载。熊猫脚底有弹簧,长按变化力度跳跃,计分游戏,html5手机熊猫也疯狂小游戏源代码。
49 5
|
1月前
|
前端开发 JavaScript 安全
HTML+CSS+JS密码灯登录表单
通过结合使用HTML、CSS和JavaScript,我们创建了一个带有密码强度指示器的登录表单。这不仅提高了用户体验,还帮助用户创建更安全的密码。希望本文的详细介绍和代码示例能帮助您在实际项目中实现类似功能,提升网站的安全性和用户友好性。
48 3
|
1月前
|
JavaScript
JS趣味打字金鱼小游戏特效源码
hi fish是一款打字趣味小游戏,捞出海里的鱼,捞的越多越好。这款游戏用于电脑初学者练习打字。初学者可以根据自己的水平设置游戏难度。本段代码可以在各个网页使用,有需要的朋友可以直接下载使用,本段代码兼容目前最新的各类主流浏览器,是一款非常优秀的特效源码!
35 3
|
1月前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
45 0
|
1月前
|
移动开发 HTML5
html5+three.js公路开车小游戏源码
html5公路开车小游戏是一款html5基于three.js制作的汽车开车小游戏源代码,在公路上开车网页小游戏源代码。
61 0
html5+three.js公路开车小游戏源码