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(); // 开始游戏

四、游戏画面展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/516688.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

韩顺平Java | C23 反射Reflection

需求&#xff1a;通过外部文件配置&#xff0c;在不修改源码情况下控制程序&#xff08;符合设计模式ocp开闭原则&#xff1a;不修改源码的情况下扩容功能&#xff09; ※反射机制 反射机制允许程序在执行期间借助于ReflectioAPI取得任何类的内部信息&#xff08;如成员变量&…

数据仓库的建立

实验 目的 熟悉Linux系统、MySQL、Hadoop、HBase、Hive、Sqoop、R、Eclipse等系统和软件的安装和使用&#xff1b; 了解大数据处理的基本流程&#xff1b; 熟悉数据预处理方法&#xff1b; 熟悉在不同类型数据库之间进行数据相互导入导出&#xff1b; 熟悉使用R语言进行可视化…

Windows虚拟主机如何创建数据库和导入数据库

看到有网友咨询想要知道Windows虚拟主机上如何使用数据库,由于是新手&#xff0c;对于主Plesk面板使用不是很了解,想要知道如何使用数据库&#xff0c;这边了解到他当前使用的是Hostease 的Windows 虚拟主机&#xff0c;首先&#xff0c;登录你的Plesk面板&#xff0c;这里有一…

【简单讲解下Tauri】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

QA测试开发工程师面试题满分问答5: 内存溢出和内存泄漏问题

概念阐述 内存溢出&#xff08;Memory Overflow&#xff09;和内存泄漏&#xff08;Memory Leak&#xff09;是与计算机程序中的内存管理相关的问题&#xff0c;它们描述了不同的情况。 内存溢出是指程序在申请内存时&#xff0c;要求的内存超出了系统所能提供的可用内存资源…

树(Tree) - 概念与基础

树的基本概念 树(Tree)是一种重要的数据结构&#xff0c;它在计算机科学中被广泛应用于各种算法和程序中。树是由节点(node)组成的层次结构&#xff0c;其中每个节点都有一个父节点&#xff0c;除了根节点外&#xff0c;每个节点都有零个或多个子节点。树的一个关键特点是没有…

Deep Unsupervised Learning using Nonequilibrium Thermodynamics

就直接从算法部分开始了&#xff1a; 2 算法 我们的目标是定义一个前向&#xff08;或者推理&#xff09;扩散过程&#xff0c;这个过程能够转换任意的复杂数据分部到一个简单、tractable、分布&#xff0c;并且学习有限时间扩散过程的反转 从而 定义我们的生成模型分布。我们…

SpringBoot整合Flowable/Activiti

SpringBoot版本: 2.0.1.RELEASE Flowable版本: 6.3.1 Activiti版本: 6.0.0 一.添加pom依赖 因为之前我整合的时候有报错关于sqlsession的错误,后面查询文章才发现flowable要排除掉mybatis,又没说具体排除哪一个,所以我这干脆全部排除了 <!-- Flowable dependencies -->…

【MATLAB源码-第32期】基于matlab的通信及雷达中常用伪随机码m序列的仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 M序列&#xff0c;也称为最大长度序列或者伪随机序列&#xff0c;是一种特殊的二进制序列。它的特点是在有限的长度内&#xff0c;尽管它是伪随机的&#xff0c;但它会在特定的周期内不重复地循环。 在数学上&#xff0c;M序…

应急响应实战笔记04Windows实战篇(5)

第5篇&#xff1a;挖矿病毒&#xff08;一&#xff09; 0x00 前言 ​ 随着虚拟货币的疯狂炒作&#xff0c;挖矿病毒已经成为不法分子利用最为频繁的攻击方式之一。病毒传播者可以利用个人电脑或服务器进行挖矿&#xff0c;具体现象为电脑CPU占用率高&#xff0c;C盘可使用空间…

CSS基础:语法、注释以及注释的3个注意事项

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。1枚程序媛&#xff0c;大专生&#xff0c;2年时间从1800到月入过万&#xff0c;工作5年买房。 分享成长心得。 259篇原创内容-公众号 后台回复“前端工具”可获取开发工具&#xff0c;持续更新…

Vulnhub:WESTWILD: 1.1

目录 信息收集 arp nmap nikto whatweb WEB web信息收集 dirmap enm4ulinux sumbclient get flag1 ssh登录 提权 横向移动 get root 信息收集 arp ┌──(root㉿ru)-[~/kali/vulnhub] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 0…

Python 一步一步教你用pyglet制作“彩色方块连连看”游戏(续)

“彩色方块连连看”游戏(续) 上期讲到相同的色块连接&#xff0c;链接见&#xff1a; Python 一步一步教你用pyglet制作“彩色方块连连看”游戏-CSDN博客 第八步 续上期&#xff0c;接下来要实现相邻方块的连线&#xff1a; 首先来进一步扩展 行列的类&#xff1a; class R…

Template Basic

本系列均参考https://github.com/bonfy/go-mega/blob/master/02-template-basic.md 只是为了监督自己写的博客 这里就不介绍什么是模板了&#xff0c;一般来说&#xff0c;我们使用html文件作为我们的模板文件 我们首先创建一个 类似于这样的模板 package mainimport (&quo…

《数字图像处理》-上机 5 图像阈值化处理、霍夫变换及形态学算法

一、上机目的 学习图像阈值化处理、霍夫变换、形态学算法及编程实现方法 二、相关知识及练习 1、图像阈值化处理 图像阈值化&#xff08;Binarization&#xff09;旨在剔除掉图像中一些低于或高于一定值的像素&#xff0c;从而提 取图像中的物体&#xff0c;将图像的背景和…

ComfyUI ClipSeg插件报错- resize_image出错应该怎么办

上一篇刚介绍了这个插件&#xff0c;结果emm..很快发现事情并不简单...结果又报错了。 后台报错信息&#xff1a; Unused or unrecognized kwargs: padding. !!! Exception during processing !!! Traceback (most recent call last): File "F:\ComfyUI-aki\execution.p…

4.2总结

了解了部分Api的使用并学习了接口的API API API包含了较多种类&#xff08;System,Runtime等&#xff09; System其实就是一个工具类&#xff0c;提供了一些与系统相关的方法 下面有一些常间的System方法 方法名说明public static void exit (int status)终止当前运行的ja…

配置code-server和texlive实现网页写tex

使用overleaf太卡了&#xff0c;有云服务器或者nas小主机&#xff0c;配置自己的code-servertexlive&#xff0c;来写论文。 之前用服务器配置过自己的overleaf&#xff0c;感觉不是很好用&#xff0c;缺少东西。 一、思路 使用docker先安装一个ubuntu&#xff0c;用dockerfil…

基于Python的微博舆论分析,微博评论情感分析可视化系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

c 语言 插值搜索(Interpolation Search)

给定一个由 n 个均匀分布值 arr[] 组成的排序数组&#xff0c;编写一个函数来搜索数组中的特定元素 x。 线性搜索需要 O(n) 时间找到元素&#xff0c;跳转搜索需要 O(? n) 时间&#xff0c;二分搜索需要 O(log n) 时间。 插值搜索是对实例二分搜索的改进&#xff0c;…