在线小游戏

snake game the snake game snake games cool math games snake classic snake game google snake game snake game hacked snake game online snake game unblocked snake game javascript snake game apple snake game world record snake game code free snake game

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>贪吃蛇</title>
    <style>
      body {
        background-color: #eee;
      }
      .container {
        text-align: center;
      }
      .top {
        margin: 20px auto;
        width: 640px;
      }
      #score {
        float: left;
      }
      .main {
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        width: 642px;
        height: 402px;
      }
      #snake {
        border: 1px solid #000;
        width: 640px;
        height: 400px;
        display: inline-block;
        z-index: 99;
        background-color: rgba(0, 0, 0, 0.1);
      }
      #mask {
        background-color: rgba(0, 0, 0, 0.5);
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        z-index: 100;
        display: block;
        color: #fff;
        line-height: 400px;
        text-align: center;
        font-size: 30px;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="top">
        <span id="score">Score: 0</span>
        <button id="restart">重新开始</button>
        <button id="stop">暂停</button>
        <button id="continue">继续</button>
      </div>
      <div class="main">
        <canvas id="snake" width="640" height="400"></canvas>
        <div id="mask">开始</div>
      </div>
    </div>

    <script>
      let greedySnake = null;
      let score = document.querySelector("#score");
      let restart = document.querySelector("#restart");
      let stop = document.querySelector("#stop");
      let conti = document.querySelector("#continue");
      let mask = document.querySelector("#mask");

      restart.onclick = () => {
        if (!greedySnake.isStart) return;
        greedySnake.start();
      };
      stop.onclick = () => {
        if (greedySnake.isStop || !greedySnake.isStart) return;
        greedySnake.stop();
      };
      conti.onclick = () => {
        if (!greedySnake.isStop || !greedySnake.isStart) return;
        greedySnake.continue();
      };
      mask.onclick = () => {
        if (!greedySnake.isStart) {
          greedySnake.start();
        } else {
          greedySnake.continue();
        }
      };

      // 大小为64 * 40
      class GreedySnake {
        constructor() {
          this.canvas = document.querySelector("#snake");
          this.ctx = this.canvas.getContext("2d");
          this.maxX = 64; // 最大行
          this.maxY = 40; // 最大列
          this.itemWidth = 10; // 每个点的大小
          this.direction = "right"; // up down right left 方向
          this.speed = 150; // ms 速度
          this.isStop = false; // 是否暂停
          this.isOver = false; // 是否结束
          this.isStart = false; // 是否开始
          this.score = 0; // 分数
          this.timer = null; // 移动定时器
          this.j = 1;
          this.canChange = true;

          this.grid = new Array();

          for (let i = 0; i < this.maxX; i++) {
            for (let j = 0; j < this.maxY; j++) {
              this.grid.push([i, j]);
            }
          }

          this.drawGridLine();
          this.getDirection();
        }

        // 开始
        start() {
          if (this.timer) {
            clearTimeout(this.timer);
          }
          if (!this.isStart) {
            this.isStart = true;
          }
          this.score = 0;
          this.speed = 150;
          this.isStop = false;
          this.isOver = false;
          this.direction = "right";
          this.createSnake();
          this.createFood();
          this.draw();
          this.move();
          mask.style.display = "none";
        }

        // 创建蛇主体
        createSnake() {
          this.snake = [
            [4, 25],
            [3, 25],
            [2, 25],
            [1, 25],
            [0, 25],
          ];
        }

        // 移动
        move() {
          if (this.isStop) return;

          let [x, y] = this.snake[0];
          switch (this.direction) {
            case "left":
              x--;
              break;
            case "right":
              x++;
              break;
            case "up":
              y--;
              break;
            case "down":
              y++;
              break;
          }

          // 如果下一步不是食物的位置
          if (x !== this.food[0] || y !== this.food[1]) {
            this.snake.pop();
          } else {
            this.createFood();
          }

          if (this.over([x, y])) {
            this.isOver = true;
            mask.style.display = "block";
            mask.innerHTML = "结束";
            return;
          }
          if (this.completed()) {
            mask.style.display = "block";
            mask.innerHTML = "恭喜您,游戏通关";
            return;
          }

          this.snake.unshift([x, y]);

          this.draw();
          this.canChange = true;
          this.timer = setTimeout(() => this.move(), this.speed);
        }

        // 暂停游戏
        stop() {
          if (this.isOver) return;
          this.isStop = true;
          mask.style.display = "block";
          mask.innerHTML = "暂停";
        }

        // 继续游戏
        continue() {
          if (this.isOver) return;
          this.isStop = false;
          this.move();
          mask.style.display = "none";
        }

        getDirection() {
          // 上38 下40 左37 右39 不能往相反的方向走
          document.onkeydown = (e) => {
            // 在贪吃蛇移动的间隔内不能连续改变两次方向
            if (!this.canChange) return;
            switch (e.keyCode) {
              case 37:
                if (this.direction !== "right") {
                  this.direction = "left";
                  this.canChange = false;
                }
                break;
              case 38:
                if (this.direction !== "down") {
                  this.direction = "up";
                  this.canChange = false;
                }
                break;
              case 39:
                if (this.direction !== "left") {
                  this.direction = "right";
                  this.canChange = false;
                }
                break;
              case 40:
                if (this.direction !== "up") {
                  this.direction = "down";
                  this.canChange = false;
                }
                break;
              case 32:
                // 空格暂停与继续
                if (!this.isStop) {
                  this.stop();
                } else {
                  this.continue();
                }
                break;
            }
          };
        }
        createPos() {
          let [x, y] = this.grid[(Math.random() * this.grid.length) | 0];

          for (let i = 0; i < this.snake.length; i++) {
            if (this.snake[i][0] == x && this.snake[i][1] == y) {
              return this.createPos();
            }
          }

          return [x, y];
        }
        // 生成食物
        createFood() {
          this.food = this.createPos();

          // 更新分数
          score.innerHTML = "Score: " + this.score++;

          if (this.speed > 50) {
            this.speed--;
          }
        }

        // 结束
        over([x, y]) {
          if (x < 0 || x >= this.maxX || y < 0 || y >= this.maxY) {
            return true;
          }

          if (this.snake.some((v) => v[0] === x && v[1] === y)) {
            return true;
          }
        }

        // 完成
        completed() {
          if (this.snake.length == this.maxX * this.maxY) {
            return true;
          }
        }

        // 网格线
        drawGridLine() {
          for (let i = 1; i < this.maxY; i++) {
            this.ctx.moveTo(0, i * this.itemWidth);
            this.ctx.lineTo(this.canvas.width, i * this.itemWidth);
          }

          for (let i = 1; i < this.maxX; i++) {
            this.ctx.moveTo(i * this.itemWidth, 0);
            this.ctx.lineTo(i * this.itemWidth, this.canvas.height);
          }
          this.ctx.lineWidth = 1;
          this.ctx.strokeStyle = "#ddd";
          this.ctx.stroke();
        }

        // 绘制
        draw() {
          // 清空画布
          this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

          this.drawGridLine();

          this.ctx.fillStyle = "#000";
          this.ctx.fillRect(
            this.food[0] * this.itemWidth + this.j,
            this.food[1] * this.itemWidth + this.j,
            this.itemWidth - this.j * 2,
            this.itemWidth - +this.j * 2
          );
          this.j ^= 1;

          this.ctx.fillStyle = "green";
          this.ctx.fillRect(
            this.snake[0][0] * this.itemWidth + 0.5,
            this.snake[0][1] * this.itemWidth + 0.5,
            this.itemWidth - 1,
            this.itemWidth - 1
          );
          this.ctx.fillStyle = "red";
          for (let i = 1; i < this.snake.length; i++) {
            this.ctx.fillRect(
              this.snake[i][0] * this.itemWidth + 0.5,
              this.snake[i][1] * this.itemWidth + 0.5,
              this.itemWidth - 1,
              this.itemWidth - 1
            );
          }
        }
      }
      greedySnake = new GreedySnake();
    </script>
  </body>
</html>