h5 canvas实现的超级简易版的贪吃蛇小游戏

新型冠状病毒疫情来袭,整天窝在家里面,闲来无聊,就突发奇想做个贪吃蛇小游戏。

思路已写在代码中

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>贪吃蛇</title>
    <style>
      .container {
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        text-align: center;
      }
      #canvas {
        background: pink;
        border: 3px solid deeppink;
      }

      button {
        background: #3998f7;
        width: 80px;
        height: 35px;
        color: white;
        font-size: 15px;
        font-weight: bold;
        outline: none;
        border: none;
        cursor: pointer;
        border-radius: 5px;
        margin-bottom: 20px;
      }
	  span {
		margin-left: 30px;
	  }
    </style>
  </head>
  <body>
    <div class="container">
      <div>
        <button id="start">开始</button>
        <button id="pause">暂停</button>
		<button id="restart">重新开始</button>
		<span id="score">得分: 0</span>
      </div>
      <canvas id="canvas" width="500" height="300"></canvas>
    </div>

    <script>
      const canvas = document.querySelector("#canvas");
      const startBtn = document.getElementById("start");
      const pauseBtn = document.getElementById("pause");
      const reStartBtn = document.getElementById("restart");
      const ctx = canvas.getContext("2d");
      const canvasWidth = canvas.width;
      const canvasHeight = canvas.height;
      let food;
      let snake;
      let score = 0; // 得分

      class Snake {
        constructor(info) {
          /**
         	head: 蛇头偏移量
         	direction: 运动方向
         	speed: 运动速度
         	size: 蛇头和蛇身一个单位的大小
          */
          const {
            head = [1, 1],
            direction = "right",
            speed = 300,
            size = 10
          } = info;
          this.body = [head]; // 存放 蛇头和蛇身的偏移量
          this.direction = direction;
          this.speed = speed;
          this.size = size;
          this.moving = false; // 是否正在运动
          this.timer = null;
        }

        move() {
          this.moving = true;
          this.timer = setInterval(() => {
		  const { speed, direction, size, body } = this;
            //移动的时候从尾部依次向前移动
            for (let i = body.length - 1; i >= 0; i--) {
              if (i !== 0) {
                this.body[i][0] = body[i - 1][0];
                this.body[i][1] = body[i - 1][1];
              } else {
                // 蛇头
                switch (direction) {
                  case "right":
                    this.body[0][0] += size;
                    break;
                  case "left":
                    this.body[0][0] -= size;
                    break;
                  case "top":
                    this.body[0][1] -= size;
                    break;
                  case "bottom":
                    this.body[0][1] += size;
                    break;
                }
              }
            }
            // 判断是否撞墙
            if (
              body[0][0] > canvasWidth - size ||
              body[0][0] < 0 ||
              body[0][1] > canvasHeight - size ||
              body[0][1] < 0
            ) {
              this.stop();
              alert("游戏结束!");
            }
            // 判断是否撞到自身
            const index = body.findIndex((ret, i, self) => {
              return i !== 0 && ret[0] === self[0][0] && ret[1] === self[0][1];
            });
            if (index !== -1) {
              this.stop();
              alert("游戏结束!");
            }
            //判断是否遇到食物
            if (body[0][0] === food[0] && body[0][1] === food[1]) {
              this.eat();
            }
          }, this.speed);
        }

        //吃掉食物,蛇身尾部加上当前吃掉的食物
        eat() {
          this.body.push(food);
          score += 1;
		  // 速度变快
		  this.speed -= 0.05 * this.speed
		  this.stop()
		  this.move()
          food = getFoodPosition();
        }

        stop() {
          this.moving = false;
          clearInterval(this.timer);
        }
      }

      function draw() {
        // 每次绘制前都重新清空画布
		ctx.clearRect(0, 0, canvasWidth, canvasHeight);
        const { body, size } = snake;
        body.forEach((ret, i) => {
          ctx.save();
          if (i === 0) {
            // 蛇头
            ctx.fillStyle = "blue";
          } else {
            // 蛇身
            ctx.fillStyle = "green";
          }
          ctx.fillRect(ret[0], ret[1], size, size);
          ctx.restore();
        });
        ctx.save();
        ctx.fillStyle = "OrangeRed";
        ctx.fillRect(food[0], food[1], size, size);
        ctx.restore();
		document.getElementById('score').innerHTML = `得分: ${score}`;
        requestAnimationFrame(draw);
      }

      // 随机生成食物所在的位置
      function getFoodPosition() {
        const { size, body } = snake;
        let flag = false;
        // 生成的必须是size的倍数
        let x = Math.floor(Math.random() * (canvasWidth - size));
        let y = Math.floor(Math.random() * (canvasHeight - size));
        const foodX = Math.floor(x / size) * size;
        const foodY = Math.floor(y / size) * size;
        const food = [foodX, foodY];
        // 判断食物是否与蛇身重合
        for (let i = 0; i < body.length; i++) {
          if (body[i][0] === food[0] && body[i][1] === food[1]) {
            flag = true;
            break;
          }
        }
        return flag ? getFoodPosition() : food;
      }

      function bindKeyDown() {
        document.onkeydown = e => {
          switch (
            e.keyCode // 不能直接反向移动
          ) {
            case 37: // 左
              if (snake && snake.direction !== "right") {
                snake.direction = "left";
              }
              break;
            case 38: // 上
              if (snake && snake.direction !== "bottom") {
                snake.direction = "top";
              }
              break;
            case 39: // 右
              if (snake && snake.direction !== "left") {
                snake.direction = "right";
              }
              break;
            case 40: // 下
              if (snake && snake.direction !== "top") {
                snake.direction = "bottom";
              }
              break;
          }
        };
      }

      function init() {
        const info = {
          direction: "right",
          head: [100, 50]
        };
        snake = new Snake(info);
        food = getFoodPosition();
        bindKeyDown();
        draw();
        startBtn.onclick = () => {
					snake.stop()
          snake.move();
        };
        pauseBtn.onclick = () => {
          pauseBtn.innerHTML = snake.moving ? "开始" : "暂停";
          snake.moving ? snake.stop() : snake.move();
        };

        reStartBtn.onclick = () => {
          snake.stop();
					pauseBtn.innerHTML = "暂停";
          ctx.clearRect(0, 0, canvasWidth, canvasHeight);
          snake = new Snake(info);
          food = getFoodPosition();
          score = 0;
          snake.move();
        };
      }

      init();
    </script>
  </body>
</html>

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值