【前端】使用 Canvas 实现贪吃蛇小游戏

使用 Canvas 实现贪吃蛇小游戏

在这篇博客中,我们将介绍如何使用 HTML5 Canvas 和 JavaScript 实现一个简单的贪吃蛇(Snake)小游戏。这个项目是一个基础的游戏开发练习,它可以帮助你理解如何在 Canvas 上绘图、如何处理用户输入以及如何管理游戏状态。
在这里插入图片描述

项目结构

在开始之前,确保你的项目文件结构如下:

  • index.html
  • index.css
  • index.js

HTML 部分

首先,我们在 index.html 中定义 Canvas 和一个重新开始按钮。

<!DOCTYPE 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="index.css">
</head>
<body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <button id="restartButton" style="display: none;" onclick="restartGame()">重新开始</button>
    <script src="index.js"></script>
</body>
</html>

CSS 部分

index.css 中,我们可以设置 Canvas 和按钮的样式。

/* styles.css */
body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
}

canvas {
    border: 1px solid #000;
    background-color: #fff;
}

button {
    display: none;
    margin-top: 20px;
    padding: 10px 20px;
    font-size: 16px;
    cursor: pointer;
    position: absolute;
}

JavaScript 部分

接下来,我们在 script.js 中编写游戏的主要逻辑。

1. 初始化 Canvas 和变量

我们首先获取 Canvas 元素及其上下文,并定义游戏所需的一些变量。

const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const restartButton = document.getElementById("restartButton");

const gridSize = 20; // 格子大小
const rows = canvas.height / gridSize;
const cols = canvas.width / gridSize;

2. 初始化游戏

创建 initGame 函数来初始化游戏状态:

function initGame() {
  snake = [{ x: cols / 2, y: rows / 2 }, { x: cols / 2 + 1, y: rows / 2 }];
  food = {
    x: Math.floor(Math.random() * cols),
    y: Math.floor(Math.random() * rows),
  };
  direction = { x: 1, y: 0 };
  lastDirection = { x: 1, y: 0 };
  gameOver = false;
  restartButton.style.display = "none";
  gameLoop();
}

3. 绘制游戏元素

我们需要两个函数来绘制蛇和食物:

function drawCell(x, y, color) {
  ctx.fillStyle = color;
  ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize);
  ctx.strokeStyle = "#000";
  ctx.lineWidth = 2; // 可以根据需要调整
  ctx.strokeRect(x * gridSize, y * gridSize, gridSize, gridSize);
}

function drawSnake() {
  snake.forEach((part) => drawCell(part.x, part.y, "#409EFF"));
}

function drawFood() {
  drawCell(food.x, food.y, "#E6A23C");
}

4. 更新蛇的位置

创建 updateSnake 函数来更新蛇的位置,并检查它是否吃到食物或撞到墙及自身:

function updateSnake() {
  const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };

  if (head.x === food.x && head.y === food.y) {
    food = {
      x: Math.floor(Math.random() * cols),
      y: Math.floor(Math.random() * rows),
    };
  } else {
    snake.pop();
  }

  snake.unshift(head);

  // 撞墙或撞到自己
  if (
    head.x < 0 ||
    head.x >= cols ||
    head.y < 0 ||
    head.y >= rows ||
    snake.slice(1).some((part) => part.x === head.x && part.y === head.y)
  ) {
    gameOver = true;
  }

  lastDirection = direction;
}

5. 游戏循环

创建 gameLoop 函数来处理游戏的绘制和更新:

function gameLoop() {
  if (!gameOver) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawFood();
    updateSnake();
    drawSnake();
    setTimeout(gameLoop, 100);
  } else {
    ctx.font = "100px Arial";
    ctx.fillStyle = "#F56C6C";
    ctx.fillText("Game Over", canvas.width / 4, canvas.height / 2);
    restartButton.style.display = "block"; // 显示重新开始按钮
  }
}

6. 处理用户输入

添加键盘事件监听来控制蛇的移动方向:

window.addEventListener("keydown", (event) => {
  switch (event.key) {
    case "ArrowUp":
      if (lastDirection.y === 0) direction = { x: 0, y: -1 };
      break;
    case "ArrowDown":
      if (lastDirection.y === 0) direction = { x: 0, y: 1 };
      break;
    case "ArrowLeft":
      if (lastDirection.x === 0) direction = { x: -1, y: 0 };
      break;
    case "ArrowRight":
      if (lastDirection.x === 0) direction = { x: 1, y: 0 };
      break;
  }
});

7. 重新开始游戏

最后,创建一个函数用于重新启动游戏:

function restartGame() {
  initGame();  // 重新启动游戏
}

initGame();  // 启动游戏

总结

通过这篇博客,你学习了如何使用 HTML5 Canvas 和 JavaScript 来实现一个简单的贪吃蛇小游戏。我们展示了如何绘制游戏元素,处理用户输入,并管理游戏状态。希望这个项目能帮助你对游戏开发有更深入的理解,并激发你进行更多有趣的项目开发!

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

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

相关文章

【九十三】【算法分析与设计】719. 找出第 K 小的数对距离,N 台电脑的最长时间,二分答案法

719. 找出第 K 小的数对距离 - 力扣&#xff08;LeetCode&#xff09; 数对 (a,b) 由整数 a 和 b 组成&#xff0c;其数对距离定义为 a 和 b 的绝对差值。 给你一个整数数组 nums 和一个整数 k &#xff0c;数对由 nums[i] 和 nums[j] 组成且满足 0 < i < j < nums.le…

校园网拨号上网环境下多开虚拟机,实现宿主机与虚拟机互通,并访问外部网络

校园网某些登录客户端只允许同一时间一台设备登录&#xff0c;因此必须使用NAT模式共享宿主机的真实IP&#xff0c;相当于访问外网时只使用宿主机IP&#xff0c;此方式通过虚拟网卡与物理网卡之间的数据转发实现访问外网及互通 经验证&#xff0c;将centos的物理地址与主机物理…

UMPNet: Universal Manipulation Policy Network for Articulated Objects

1. 摘要 UMPNet是一个基于图像的策略网络&#xff0c;能够推理用于操纵铰接物体的闭环动作序列。该策略支持6DoF动作表示和可变长度轨迹。 为处理多种类的物体&#xff0c;该策略从不同的铰接结构中学习&#xff0c;并泛化到未见过的物体或类别上。该策略是以自监督探索的方式…

利用Python队列生产者消费者模式构建高效爬虫

目录 一、引言 二、生产者消费者模式概述 三、Python中的队列实现 四、生产者消费者模式在爬虫中的应用 五、实例分析 生产者类&#xff08;Producer&#xff09; 消费者类&#xff08;Consumer&#xff09; 主程序 六、总结 一、引言 随着互联网的发展&#xff0c;信…

css使用clip-path裁剪出不规则图形并绑定点击事件

点击图片的红色区域触发事件 点击图片黑色不触发点击事件&#xff0c;代码演示效果如下&#xff1a; 代码演示效果 1.png&#xff08;尺寸 200*470&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><…

2025第十届美陈展

展位又遭疯抢&#xff01;2025第十届美陈展释放“无界之美” 美是全球通用的语言&#xff0c;人类对美的追求始终如一&#xff0c;大众审美在经历了时代的变迁后开始趋同&#xff0c;东方文明深处的美学经济开始崛起。 在如今商业迈入存量阶段&#xff0c;以品牌为突破口打造…

抽象工厂模式(AbstractFactoryPattern)

文章目录 1.抽象工厂模式定义2.UML类图3.抽象工厂模式具体实现工厂模式实现单一产品族抽象工厂实现多产品族产品类工厂类使用 4.抽象工厂模式优缺点 1.抽象工厂模式定义 提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。 工厂方法模式是单一产…

JavaScript-运算符

算术运算符 返回结果为数字型的运算符 加法运算符 加法运算符&#xff08;&#xff09;是一个二元运算符&#xff0c;可以对两个数字型的操作数进行相加运算&#xff0c;返回值是两个操作数的和 减法运算符 减法运算符&#xff08;-&#xff09;是一个二元运算符&#xff0c;可…

banner2.0自定义轮播布局

说明&#xff1a;最近碰到一个需求&#xff0c;让新闻列表实现轮播图的效果&#xff0c;也就是轮播新闻&#xff0c;然后样式必须按照ui设计的样式来弄&#xff0c;之前传统的banner&#xff0c;都是只轮播图片&#xff0c;没想到&#xff0c;这次居然要轮播新闻&#xff0c; 网…

【深度学习】YOLOv8训练,交通灯目标检测

文章目录 一、数据处理二、环境三、训练 一、数据处理 import traceback import xml.etree.ElementTree as ET import os import shutil import random import cv2 import numpy as np from tqdm import tqdmdef convert_annotation_to_list(xml_filepath, size_width, size_he…

java+ vue.js+uniapp一款基于云计算技术的企业级生产管理系统,云MES源码 MES系统如何与ERP系统集成?

java vue.jsuniapp一款基于云计算技术的企业级生产管理系统&#xff0c;云MES源码&#xff0c;MES系统如何与ERP系统集成&#xff1f; MES系统&#xff08;制造执行系统&#xff09;与ERP系统&#xff08;企业资源规划系统&#xff09;的集成可以通过多种方式实现&#xff0c;这…

【git】开发提交规范(feat、fix、perf)

这段时间收到的需求很多&#xff0c;可能是临近两周一次的大版本灰度上线&#xff0c;这次产生了一个关于git的思考&#xff0c;就是各个版本之间怎么管理的问题&#xff0c;这里做出我自己的一些方法。 首先&#xff0c;既然已经明确了remote分支中的release分支为主分支&…

Java中transient关键字

transient介绍 在Java中&#xff0c;transient是一个关键字&#xff0c;用于声明一个字段在序列化过程中应该被忽略。当一个对象被序列化时&#xff0c;它的状态&#xff08;即其字段的值&#xff09;通常会被保存到字节流中&#xff0c;以便稍后可以反序列化恢复对象的状态。…

如何使用Matlab进行三角剖分(自定义函数实现delaunayTriangulation 使用Bowyer-Watson 算法)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、Delaunay三角形 二、使用步骤 1.Bowyer-Watson算法 2.算法步骤 三、动画演示 四、核心代码 五、对比matlab自带函数和我们的算法&#xff1a; 总结 前…

巨某量引擎后台登录实战笔记 | Playwright自动化框架

前言 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; 入正题看看滑块是怎么个事…

CasaOS系统玩客云安装内网穿透工具实现无公网IP远程访问

文章目录 前言1. CasaOS系统介绍2. 内网穿透安装3. 创建远程连接公网地址4. 创建固定公网地址远程访问 前言 2月底&#xff0c;玩客云APP正式停止运营&#xff0c;不再提供上传、云添加功能。3月初&#xff0c;有用户进行了测试&#xff0c;局域网内的各种服务还能继续使用&am…

Ai自动贴图直播项目的趋势,智享自动直播GMV增加工具

在当今社会&#xff0c;直播行业正在悄然地改变着人们的生活方式。无论是在闲暇时光中放松身心&#xff0c;还是在临睡前享受休闲娱乐&#xff0c;观众们越来越习惯于通过刷短视频或者观看直播来消遣自己。根据统计数据显示&#xff0c;到2023年全球将有超过10.74亿网民&#x…

Android 12系统源码_多窗口模式(二)系统实现分屏的功能原理

前言 上一篇我们具体分析了系统处于多窗口模式下&#xff0c;Android应用和多窗口模式相关方法的调用顺序&#xff0c;对于应用如何适配多窗口模式有了一个初步的认识&#xff0c;本篇文章我们将会结合Android12系统源码&#xff0c;具体来梳理一下系统是如何触发多窗口分屏模…

2024全新爆款好物推荐,618必买数码好物清单吐血整理!

​距离618购物狂欢节越来越近了&#xff0c;有很多日常价格不菲的产品在这次活动期间都会进行促销活动&#xff0c;尤其是数码类产品&#xff0c;加上618的优惠活动更有吸引力了。不过面对大促的热潮我们消费者在选购商品的同时还是要擦亮眼睛&#xff0c;避免买到质量不好的商…

[Redis]基本全局命令

Redis存储方式介绍 在 Redis 中数据是以键值对的凡事存储的&#xff0c;键&#xff08;Key&#xff09;和值&#xff08;Value&#xff09;是基本的数据存储单元。以下是对 Redis 键值对的详细讲解&#xff1a; 键&#xff08;Key&#xff09;&#xff1a; 类型&#xff1a;…