canvas+javascript 实现贪吃蛇游戏

引言

在当今数字化时代,编程已经成为一种极具创造力和趣味性的活动。通过编写代码,我们可以创造出各种各样的应用程序和游戏,其中包括经典的贪吃蛇游戏。本文将向您介绍如何使用 JavaScript 编程语言制作一个简单而有趣的贪吃蛇游戏,并通过代码分析和解释帮助您了解游戏的实现原理。

一、游戏背景

       贪吃蛇是一款经典的街机游戏,早在 Nokia 手机时代就备受欢迎。玩家控制一条蛇在一个有限的空间内移动,吃掉食物以增加长度,同时要避免撞到墙壁或自身。本文将使用 HTML5 的 Canvas 元素和 JavaScript 语言来实现这个经典游戏的简化版本。

二、游戏功能及实现

       首先,我们需要定义一些游戏所需的变量,如蛇的初始位置、食物的位置、移动速度等。接着,我们监听键盘事件,根据用户按键改变蛇的移动方向。蛇的移动是通过周期性地更新蛇头位置并移除蛇尾来实现的。当蛇吃到食物时,增加得分并重新生成食物位置;当蛇头碰到墙壁或自身时,游戏结束。

三、代码分析 

3.1 html代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>贪吃蛇游戏</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="container">
      <div class="header">
        <div>难度:<span id="speed"></span></div>
        <div>分数:<span id="score"></span></div>
      </div>
      <canvas id="gameCanvas" width="400" height="400"></canvas>
    </div>
    <script src="game.js"></script>
  </body>
</html>

3.2 css代码

body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #212121;
}

.header {
    background-color: #266e61;
    color: #f9f9f9;
    display: flex;
    justify-content: space-between;
    padding: 10px 40px;
    border-radius: 10px;
    margin-bottom: 10px;
}

span {
    font-size: 20px;
}

canvas {
    background-color: #353535;
    border: 1px solid black;
    border-radius: 10px;
    padding: 10px;
}

3.3 JavaScript核心代码

我们将代码分为几个主要功能函数:

  • changeDirection(event):监听键盘事件,根据按键改变蛇的移动方向。
function changeDirection(event) {
  const keyPressed = event.key; // 获取按下的键值
  // 根据按键改变蛇的移动方向,确保蛇不会向相反方向移动
  if (keyPressed === "ArrowUp" && dy === 0) {
    dx = 0;
    dy = -gridSize;
  } else if (keyPressed === "ArrowDown" && dy === 0) {
    dx = 0;
    dy = gridSize;
  } else if (keyPressed === "ArrowLeft" && dx === 0) {
    dx = -gridSize;
    dy = 0;
  } else if (keyPressed === "ArrowRight" && dx === 0) {
    dx = gridSize;
    dy = 0;
  }
}
  • moveSnake():更新蛇的位置,处理吃食物和碰撞检测逻辑。
function moveSnake() {
  const head = { x: snake[0].x + dx, y: snake[0].y + dy }; // 计算蛇头的新位置
  snake.unshift(head); // 将新的蛇头加入到蛇的数组中
  // 如果蛇吃到食物
  if (head.x === food.x && head.y === food.y) {
    food = getRandomPosition(); // 重新生成食物位置
    score += 10; // 增加得分
    document.getElementById("score").textContent = score; // 更新得分显示
    // 每吃到50分,增加游戏速度
    if (score % 50 === 0) {
      speed += 1; // 增加速度
      document.getElementById("speed").textContent = speed; // 更新速度显示
    }
  } else {
    snake.pop(); // 如果没有吃到食物,移除蛇尾,实现蛇的移动效果
  }
  // 如果蛇碰到墙壁或者自身,游戏结束
  if (
    head.x < 0 ||
    head.x >= canvas.width ||
    head.y < 0 ||
    head.y >= canvas.height ||
    collision()
  ) {
    gameOver = true; // 设置游戏结束标志为true
  }
}
  • drawSnake() 和 drawFood():绘制蛇和食物。   
function drawSnake() {
  // 绘制蛇身
  snake.forEach((segment) => {
    ctx.fillStyle = "#266e5f"; // 设置蛇的颜色
    ctx.fillRect(segment.x, segment.y, gridSize, gridSize); // 绘制蛇的每一段
  });
}
  • collision():检测蛇头是否与蛇身相撞。
function collision() {
  // 检测蛇头是否与蛇身相撞
  return snake
    .slice(1)
    .some((segment) => segment.x === snake[0].x && segment.y === snake[0].y);
}
  • drawGrid():绘制游戏网格。
function drawGrid() {
  // 绘制游戏网格
  for (let x = 0; x < canvas.width; x += gridSize) {
    for (let y = 0; y < canvas.height; y += gridSize) {
      ctx.strokeStyle = "black"; // 设置边框颜色
      ctx.lineWidth = gridBorderWidth; // 设置边框宽度
      ctx.strokeRect(x, y, gridSize, gridSize); // 绘制方格边框
    }
  }
}

3.4 整体代码

const canvas = document.getElementById("gameCanvas"); // 获取画布元素
const ctx = canvas.getContext("2d"); // 获取2D绘图上下文
const gridSize = 20; // 网格大小
const gridBorderWidth = 1; // 新增的边框宽度
let snake = [{ x: 200, y: 200 }]; // 蛇的初始位置
let food = getRandomPosition(); // 随机生成食物位置
let dx = gridSize; // 蛇的水平移动速度
let dy = 0; // 蛇的垂直移动速度
let gameOver = false; // 游戏结束标志
let speed = 1; // 游戏速度
let score = 0; // 得分

init(); //初始化
document.addEventListener("keydown", changeDirection); // 监听键盘按下事件,改变蛇的移动方向

function init() {
    document.getElementById("score").textContent = score;
    document.getElementById("speed").textContent = speed;
}

function changeDirection(event) {
  const keyPressed = event.key; // 获取按下的键值
  // 根据按键改变蛇的移动方向,确保蛇不会向相反方向移动
  if (keyPressed === "ArrowUp" && dy === 0) {
    dx = 0;
    dy = -gridSize;
  } else if (keyPressed === "ArrowDown" && dy === 0) {
    dx = 0;
    dy = gridSize;
  } else if (keyPressed === "ArrowLeft" && dx === 0) {
    dx = -gridSize;
    dy = 0;
  } else if (keyPressed === "ArrowRight" && dx === 0) {
    dx = gridSize;
    dy = 0;
  }
}

function drawSnake() {
  // 绘制蛇身
  snake.forEach((segment) => {
    ctx.fillStyle = "#266e5f"; // 设置蛇的颜色
    ctx.fillRect(segment.x, segment.y, gridSize, gridSize); // 绘制蛇的每一段
  });
}

function moveSnake() {
  const head = { x: snake[0].x + dx, y: snake[0].y + dy }; // 计算蛇头的新位置
  snake.unshift(head); // 将新的蛇头加入到蛇的数组中
  // 如果蛇吃到食物
  if (head.x === food.x && head.y === food.y) {
    food = getRandomPosition(); // 重新生成食物位置
    score += 10; // 增加得分
    document.getElementById("score").textContent = score; // 更新得分显示
    // 每吃到50分,增加游戏速度
    if (score % 50 === 0) {
      speed += 1; // 增加速度
      document.getElementById("speed").textContent = speed; // 更新速度显示
    }
  } else {
    snake.pop(); // 如果没有吃到食物,移除蛇尾,实现蛇的移动效果
  }
  // 如果蛇碰到墙壁或者自身,游戏结束
  if (
    head.x < 0 ||
    head.x >= canvas.width ||
    head.y < 0 ||
    head.y >= canvas.height ||
    collision()
  ) {
    gameOver = true; // 设置游戏结束标志为true
  }
}

function drawFood() {
  ctx.fillStyle = "#FFF"; // 设置食物的颜色
  ctx.fillRect(food.x, food.y, gridSize, gridSize); // 绘制食物
}

function getRandomPosition() {
  // 随机生成食物的位置,确保在网格内
  return {
    x: Math.floor(Math.random() * (canvas.width / gridSize)) * gridSize,
    y: Math.floor(Math.random() * (canvas.height / gridSize)) * gridSize,
  };
}

function collision() {
  // 检测蛇头是否与蛇身相撞
  return snake
    .slice(1)
    .some((segment) => segment.x === snake[0].x && segment.y === snake[0].y);
}

function drawGrid() {
  // 绘制游戏网格
  for (let x = 0; x < canvas.width; x += gridSize) {
    for (let y = 0; y < canvas.height; y += gridSize) {
      ctx.strokeStyle = "black"; // 设置边框颜色
      ctx.lineWidth = gridBorderWidth; // 设置边框宽度
      ctx.strokeRect(x, y, gridSize, gridSize); // 绘制方格边框
    }
  }
}

function draw() {
  // 主绘制函数
  ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
  drawGrid(); // 绘制游戏网格
  drawSnake(); // 绘制蛇身
  drawFood(); // 绘制食物
  moveSnake(); // 移动蛇
  // 如果游戏结束,显示游戏结束文字
  if (gameOver) {
    ctx.fillStyle = "#FFF";
    ctx.font = "35px Arial";
    ctx.fillText("游戏 结束", canvas.width / 2 - 65, canvas.height / 2);
    return;
  }
  setTimeout(draw, 1000 / speed); // 根据速度调整 setTimeout 的时间间隔,实现游戏速度控制
}

draw(); // 开始游戏

四、游戏画面展示

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香菜的开发日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值