用javaScript和canvas做一个贪吃蛇

在这里插入图片描述

基本思想

贪吃蛇的话比较容易,因为刚学习了canvas画布,用来练手。
整体步骤

  • 放一个canvas画布并画上几条线,生成格子。(当然 没格子也行)
  • 使用数组创建一条蛇,生成食物。
  • 监听键盘事件,监控方向。
  • 根据方向,计算蛇下一步移动的方向,并控制游戏结束或吃到食物事件的发生。
  • 借用计时器不断重绘蛇和食物。

虽然看起来简单,不过其中也有需要注意的地方

1. 食物的生成
食物生成时随机的,可以借助Math.Radom()函数生成。不过需要注意食物不能画在画布外,或者画在蛇的身上。

2. 蛇的移动
蛇移动一步其实就是将蛇的最后一节删除,然后在蛇头的下一步位置添加一节。也就是将存储蛇位置的数组最后一个元素删除,再计算蛇头下一帧的位置再插入到数组的第一位即可。
如果蛇吃到了食物,就不去删除最后一个元素,只在第一位增加元素。

3.蛇移动的方向
蛇是不可以向反方向移动的,同时每一帧只能执行一个转向命令。
所以我将右左方向以1和-1代替,下上方向以2和-2代替。移动时只需要判断当前方向和更改方向之和是否为0即可。

代码

snake.html

<!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>Document</title>
  <link rel="stylesheet" type="text/css" href="./snake.css">
</head>

<body>
  <div class="content">
    <canvas id="canvas"></canvas>
  </div>

  <div class="buttcont">
    <button class="beginer" onclick="beginer()">开始</button>
    <div id="scoreBox">0</div>
    <button class="beginer beginerS" onclick="stoper()">暂停</button>
  </div>
  
</body>

<script type="text/javascript" src="./snake.js.js"></script>
</html>

snake.css

* {
  border: 0;
  margin: 0;
  padding: 0;
}

#scoreBox {
  width: 60px;
  height: 40px;
  margin: 0 auto;
  border: 2px solid #f6e58d;
  background-color: #f9ca24;
  border-radius: 5px;
  color: aliceblue;
  font-size: 22px;
  font-weight: 600;
  line-height: 40px;
  text-align: center;
}

.content {
  margin: 0 auto;
  width: 800px;
  margin-top: 20px;
  border: 5px solid pink;
}

canvas {
  display: block;
  background-color: bisque;
}

.buttcont {
  display: flex;
  justify-content: space-around;
  width: 800px;
  margin: 0 auto;
  margin-top: 20px;
}

.beginer {
  width: 80px;
  height: 50px;
  background-color: #badc58;
  font-size: 14px;
  color: aliceblue;
  font-weight: 600;
  display: block;
  margin: 0 auto;

  cursor: pointer;
}
.beginerS{
  background-color :#ff7979
}

snake.js

/** @type {HTMLCanvasElement} */
let canvas = document.getElementById('canvas');
let cgn = canvas.getContext('2d');
let scoreBox = document.getElementById('scoreBox')
let isBegin = false;
let score = 0;

// 面板属性
let PANL_WIDTH = canvas.width = 800;
let PANL_HEIGHT = canvas.height = 500;
let CELL_WIDTH = 20;
let MOVE_SPEED = 100;
let GAMEOVER = {
  state: false,
  reaon: ""
};

// 方向控制 数字为基础 反方向 正负数
let RIGHT_CONTROL = 1;
let LEFT_CONTROL = -1;
let DOWN_CONTROL = 2;
let UP_CONTROL = -2;

let raf; //计时器
let directionNow = -1;  //当前方向
let directionRes = -1; //防止短时间内多次转向 出现问题

// 一个蛇的属性
let snakeMes = {
  headerColor: '#2ed573',
  bodyColor: '#7bed9f',
  snakeWidth: CELL_WIDTH,
  foodColor: '#ff6b81'
}

let FOOD_POINT = {}; //食物位置
let eatRood = false; //是否吃了一个食物了

// 创建一个蛇 并压入一个头 两个蛇身
let snake = []

reStart();
// 重新开始
function reStart() {
  directionNow = directionRes = -1;
  clearCanvase();
  initSnake();
  restDraw();
  getFood();
  drawFood();
  score = 0;
  scoreBox.innerText = score;
}

// 调用方法 重绘一些东西
function restDraw() {
  // gameMonitor();
  clearCanvase();
  drawLines();
  drawFood();
  directionNow = directionRes;
  stepMove();
  drawSnake();
  gameMonitor();
}

// 开始
function beginer() {
  if (!isBegin) {
    scoreBox.innerText = score;
    isBegin = true;
    raf = setInterval(restDraw, MOVE_SPEED);
  }
  if (GAMEOVER.state) {
    reStart();
    isBegin = true;
    raf = setInterval(restDraw, MOVE_SPEED);
    GAMEOVER.state = false;
  }
}

// 暂停
function stoper() {
  if (isBegin) {
    isBegin = false;
    clearInterval(raf);
  }
}

// 初始化蛇
function initSnake() {
  snake = [];
  for (let i = 0; i < 3; i++) {
    snake.push({
      x: Math.floor(PANL_WIDTH / 40) * 20 + i * 20,
      y: Math.floor(PANL_HEIGHT / 40) * 20
    })
  }
}

// 监听键盘事件
document.addEventListener('keydown', function (e) {
  var event = e || window.event // e:非IE浏览器使用,window.event是IE浏览器使用
  let moveDirection;
  switch (e.key) {
    case 'ArrowRight': {
      moveDirection = 1;
    } break;
    case 'ArrowLeft': {
      moveDirection = -1;
    } break;
    case 'ArrowDown': {
      moveDirection = 2;
    } break;
    case 'ArrowUp': {
      moveDirection = -2;
    } break;
    default:
      break;
  }
  // 判断方向是否是否重合
  if (directionNow + moveDirection != 0) {
    directionRes = moveDirection;
  }
})

// 画一些网格线
function drawLines() {
  // 画横线
  for (let i = 0; i <= PANL_HEIGHT; i = i + CELL_WIDTH) {
    cgn.save();
    cgn.beginPath();
    cgn.moveTo(0, i);
    cgn.lineWidth = 3;
    cgn.strokeStyle = '#fff';
    cgn.lineTo(PANL_WIDTH, i);
    cgn.stroke();
    cgn.restore();
  }

  for (let i = 0; i <= PANL_WIDTH; i = i + CELL_WIDTH) {
    cgn.save();
    cgn.beginPath();
    cgn.moveTo(i, 0);
    cgn.lineWidth = 3;
    cgn.strokeStyle = '#fff';
    cgn.lineTo(i, PANL_HEIGHT);
    cgn.stroke();
    cgn.restore();
  }
}

// 画这个蛇
function drawSnake() {
  // 画身体
  for (let i = 1; i < snake.length; i++) {
    drawSqwar(snake[i].x, snake[i].y, CELL_WIDTH, CELL_WIDTH, snakeMes.bodyColor);
  }
  // 画蛇头
  drawSqwar(snake[0].x, snake[0].y, CELL_WIDTH, CELL_WIDTH, snakeMes.headerColor);
}

// 获得一个食物
function getFood() {
  let x = Math.floor(Math.random() * PANL_WIDTH / 20) * 20
  let y = Math.floor(Math.random() * PANL_HEIGHT / 20) * 20
  let isFood = true;
  // 判断食物是不是出现在了蛇身上 出现就重画
  while (true) {
    snake.forEach(element => {
      if (element.x === x && element.y === y) {
        x = Math.floor(Math.random() * PANL_WIDTH / 20) * 20
        y = Math.floor(Math.random() * PANL_HEIGHT / 20) * 20
        isFood = false;
      }
    });
    if (isFood)
      break;
    else
      isFood = true;
  }
  FOOD_POINT = {
    x: x,
    y: y
  }
  // drawSqwar(x, y, CELL_WIDTH, CELL_WIDTH, snakeMes.foodColor);
}

// 画食物
function drawFood() {
  drawSqwar(FOOD_POINT.x, FOOD_POINT.y, CELL_WIDTH, CELL_WIDTH, snakeMes.foodColor);
}

// 画一个方块
function drawSqwar(sx, sy, swidth, sheight, scolor) {
  cgn.save();
  cgn.beginPath();
  cgn.fillStyle = scolor;
  cgn.fillRect(sx, sy, swidth, sheight);
  cgn.restore();
}

// 蛇的正常移动
function stepMove() {
  if (!eatRood) {
    snake.splice(snake.length - 1, 1);
  }
  eatRood = false;
  let head = snake[0];
  let newhead = {}
  // 正常
  if (directionNow == 1 || directionNow == -1) {
    newhead.x = head.x + directionNow / 1 * CELL_WIDTH;
    newhead.y = head.y;
  } else if (directionNow == 2 || directionNow == -2) {
    newhead.x = head.x;
    newhead.y = head.y + directionNow / 2 * CELL_WIDTH;
  } else { }
  // 穿墙
  if (newhead.x >= PANL_WIDTH)
    newhead.x = 0;
  if (newhead.x < 0)
    newhead.x = PANL_WIDTH - CELL_WIDTH;
  if (newhead.y >= PANL_HEIGHT)
    newhead.y = 0;
  if (newhead.y < 0)
    newhead.y = PANL_HEIGHT - CELL_WIDTH;
  snake.splice(0, 0, newhead);
}

// 游戏检测
function gameMonitor() {
  // 是否吃到食物
  if (snake[0].x == FOOD_POINT.x && snake[0].y == FOOD_POINT.y) {
    eatenFood();
  }

  // 是否吃到自己
  for (let i = 1; i < snake.length; i++) {
    if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
      gameOverState('you eaten yourself');
    }
  }
  // 是否吃完了所有的食物
  if (snake.length == PANL_HEIGHT / CELL_WIDTH * PANL_WIDTH / CELL_WIDTH) {
    gameOverState('you win');
  }
}

// 吃到了食物
function eatenFood() {
  eatRood = true;
  score++;
  scoreBox.innerText = score;
  getFood();
}

// 游戏结束
function gameOverState(gameStateReason) {
  GAMEOVER.state = true;
  GAMEOVER.reaon = gameStateReason;
  alert(GAMEOVER.reaon);
  clearInterval(raf);
}

// 清空画布
function clearCanvase() {
  cgn.clearRect(0, 0, PANL_WIDTH, PANL_HEIGHT);
}

欧克

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的 HTML CanvasJavaScript 贪吃蛇游戏,并添加记分功能: HTML 代码: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>贪吃蛇游戏</title> <style> canvas { border: 1px solid #000; } </style> </head> <body> <canvas id="canvas" width="400" height="400"></canvas> <p>得分:<span id="score">0</span></p> <script src="snake.js"></script> </body> </html> ``` JavaScript 代码: ```javascript // 获取 canvas 元素和上下文 const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); // 初始化贪吃蛇 let snake = { x: 10, y: 10, dx: 10, dy: 0, cells: [], maxCells: 4 }; // 初始化食物和得分 let food = { x: Math.floor(Math.random() * 39 + 1) * 10, y: Math.floor(Math.random() * 39 + 1) * 10 }; let score = 0; // 处理键盘事件,控制贪吃蛇移动 document.addEventListener('keydown', function(e) { if (e.keyCode === 37 && snake.dx === 0) { snake.dx = -10; snake.dy = 0; } else if (e.keyCode === 38 && snake.dy === 0) { snake.dy = -10; snake.dx = 0; } else if (e.keyCode === 39 && snake.dx === 0) { snake.dx = 10; snake.dy = 0; } else if (e.keyCode === 40 && snake.dy === 0) { snake.dy = 10; snake.dx = 0; } }); // 更新贪吃蛇和食物 function update() { snake.x += snake.dx; snake.y += snake.dy; // 如果贪吃蛇撞到边界,游戏结束 if (snake.x < 0 || snake.x > 390 || snake.y < 0 || snake.y > 390) { clearInterval(intervalId); alert('游戏结束!得分:' + score); return; } // 添加新的贪吃蛇头部 snake.cells.unshift({x: snake.x, y: snake.y}); // 如果贪吃蛇吃到食物,添加得分和新的食物 if (snake.x === food.x && snake.y === food.y) { score += 10; document.getElementById('score').innerHTML = score; snake.maxCells++; food.x = Math.floor(Math.random() * 39 + 1) * 10; food.y = Math.floor(Math.random() * 39 + 1) * 10; } // 删除贪吃蛇尾部 while (snake.cells.length > snake.maxCells) { snake.cells.pop(); } } // 绘制贪吃蛇和食物 function draw() { // 清空 canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制贪吃蛇 ctx.fillStyle = 'green'; snake.cells.forEach(function(cell, index) { ctx.fillRect(cell.x, cell.y, 10, 10); }); // 绘制食物 ctx.fillStyle = 'red'; ctx.fillRect(food.x, food.y, 10, 10); } // 每 100 毫秒更新一次,绘制一次 let intervalId = setInterval(function() { update(); draw(); }, 100); ``` 这段代码实现了一个简单的贪吃蛇游戏,并且添加了记分功能。每次贪吃蛇吃到食物时,得分加上 10 并显示在页面上。游戏结束时弹出得分提示框。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值