当前位置: 首页 > news >正文

HTML5+JavaScript实现消消乐游戏

HTML5+JavaScript实现消消乐游戏

点击两个相邻的方块来交换它们位置。

如果交换后形成三个或更多相同图案的方块连成一线,这些方块会被消除。

消除后,上方的方块会下落填补空缺,顶部会生成新的方块。

每消除一个方块得10分。例如,如果一次消除了4个方块,玩家将得到40分。

运行效果如下图:

源码如下:


<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>基础消消乐游戏 - Emoji版</title><style>body {display: flex;flex-direction: column;justify-content: center;align-items: center;height: 100vh;margin: 0;background-color: #f0f0f0;font-family: Arial, sans-serif;}#gameContainer {display: flex;flex-direction: column;align-items: center;}canvas {border: 2px solid #000;margin-bottom: 10px;}#scoreDisplay {font-size: 24px;margin-bottom: 10px;}</style>
</head>
<body><div id="gameContainer"><div id="scoreDisplay">分数: 0</div><canvas id="gameCanvas" width="400" height="400"></canvas></div><script>const canvas = document.getElementById('gameCanvas');const ctx = canvas.getContext('2d');const scoreDisplay = document.getElementById('scoreDisplay');const GRID_SIZE = 8;const CELL_SIZE = canvas.width / GRID_SIZE;const EMOJIS = ['☮', '⚜', '♾ ', '☯', '⚛', '✳'];let grid = [];let selectedCell = null;let score = 0;function initGrid() {for (let i = 0; i < GRID_SIZE; i++) {grid[i] = [];for (let j = 0; j < GRID_SIZE; j++) {grid[i][j] = EMOJIS[Math.floor(Math.random() * EMOJIS.length)];}}}function drawGrid() {ctx.clearRect(0, 0, canvas.width, canvas.height);ctx.font = `${CELL_SIZE * 0.8}px Arial`;ctx.textAlign = 'center';ctx.textBaseline = 'middle';for (let i = 0; i < GRID_SIZE; i++) {for (let j = 0; j < GRID_SIZE; j++) {ctx.fillText(grid[i][j], i * CELL_SIZE + CELL_SIZE / 2, j * CELL_SIZE + CELL_SIZE / 2);}}if (selectedCell) {ctx.strokeStyle = 'black';ctx.lineWidth = 2;ctx.strokeRect(selectedCell.x * CELL_SIZE, selectedCell.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);}}function checkMatches() {let matched = [];// 检查水平匹配for (let j = 0; j < GRID_SIZE; j++) {let streak = 1;for (let i = 1; i < GRID_SIZE; i++) {if (grid[i][j] === grid[i-1][j]) {streak++;} else {if (streak >= 3) {for (let k = i - streak; k < i; k++) {matched.push({x: k, y: j});}}streak = 1;}}if (streak >= 3) {for (let k = GRID_SIZE - streak; k < GRID_SIZE; k++) {matched.push({x: k, y: j});}}}// 检查垂直匹配for (let i = 0; i < GRID_SIZE; i++) {let streak = 1;for (let j = 1; j < GRID_SIZE; j++) {if (grid[i][j] === grid[i][j-1]) {streak++;} else {if (streak >= 3) {for (let k = j - streak; k < j; k++) {matched.push({x: i, y: k});}}streak = 1;}}if (streak >= 3) {for (let k = GRID_SIZE - streak; k < GRID_SIZE; k++) {matched.push({x: i, y: k});}}}return matched;}function removeMatches(matches) {matches.forEach(cell => {grid[cell.x][cell.y] = null;});//updateScore(matches.length);}function updateScore(matchCount) {score += matchCount * 10;scoreDisplay.textContent = `分数: ${score}`;}function fillBlanks() {for (let i = 0; i < GRID_SIZE; i++) {let blanks = 0;for (let j = GRID_SIZE - 1; j >= 0; j--) {if (!grid[i][j]) {blanks++;} else if (blanks > 0) {grid[i][j + blanks] = grid[i][j];grid[i][j] = null;}}for (let j = 0; j < blanks; j++) {grid[i][j] = EMOJIS[Math.floor(Math.random() * EMOJIS.length)];}}}function swapCells(cell1, cell2) {const temp = grid[cell1.x][cell1.y];grid[cell1.x][cell1.y] = grid[cell2.x][cell2.y];grid[cell2.x][cell2.y] = temp;}canvas.addEventListener('click', (event) => {const rect = canvas.getBoundingClientRect();const x = Math.floor((event.clientX - rect.left) / CELL_SIZE);const y = Math.floor((event.clientY - rect.top) / CELL_SIZE);if (selectedCell) {if ((Math.abs(selectedCell.x - x) === 1 && selectedCell.y === y) ||(Math.abs(selectedCell.y - y) === 1 && selectedCell.x === x)) {swapCells(selectedCell, {x, y});let matches = checkMatches();if (matches.length === 0) {swapCells(selectedCell, {x, y});} else {let totalMatches = 0;while (matches.length > 0) {totalMatches += matches.length;removeMatches(matches);fillBlanks();matches = checkMatches();}updateScore(totalMatches);  // 在所有匹配处理完后更新分数}}selectedCell = null;} else {selectedCell = {x, y};}drawGrid();});function gameLoop() {drawGrid();requestAnimationFrame(gameLoop);}initGrid();gameLoop();</script>
</body>
</html>

相关文章:

HTML5+JavaScript实现消消乐游戏

HTML5JavaScript实现消消乐游戏 点击两个相邻的方块来交换它们位置。 如果交换后形成三个或更多相同图案的方块连成一线&#xff0c;这些方块会被消除。 消除后&#xff0c;上方的方块会下落填补空缺&#xff0c;顶部会生成新的方块。 每消除一个方块得10分。例如&#xff0…...

sin函数拟合

目录 一、 目的... 1 二、 模型设计... 1 2.1 输入与输出.... 1 2.2 隐藏层设计.... 1 2.3 优化算法与损失函数.... 1 2.4 神经网络结构.... 1 三、 训练... 1 3.1 数据生成.... 2 3.2 训练过程.... 2 3.3 训练参数与设置.... 2 四、 测试与分析... 2 4.1 选取不同激活函数....…...

设置Mysql5.6允许外网访问

设置mysql用户支持外网访问步骤&#xff1a; 需要使用root权限登录mysql&#xff0c;更新mysql.user表&#xff0c;设置指定用户的Host字段为%&#xff0c;默认一般为127.0.0.1或者localhost。 1.登录数据库 1 mysql -u root -p 输入密码 1 mysql> use mysql; 2.查询hos…...

【随笔】一次JS和python中的MD5加密的记录

// 使用CryptoJS进行MD5加密和Base64编码 const sign CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(CryptoJS.MD5(sign2encrypt).toString()));上面这段JS和下面这个python等价 def hash_and_encode(input_string):sign2encrypt input_string# 使用 hashlib 进行 …...

力扣 二叉树的中序遍历

用了递归遍历&#xff0c;关于树的经典例题。 题目 递归 常规做法即递归了&#xff0c;不会写也得背下来。递归可以大致理解方法调用自身&#xff0c;先写中序遍历递归的方法&#xff0c;递归一定要有递归出口&#xff0c;当遍历到节点为空时返回&#xff0c;即已经找到了。…...

uniapp学习(010-3 实现H5和安卓打包上线)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战&#xff0c;开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第114p-116p的内容 文章目录 H5配置文件设置开始打包上传代码 安卓设置模拟器启动设置基础配置设置图标启动界面…...

基于DHCP,ACL的通信

该问题为华为的学习资料 1.首先把所有的PC机全部设置为DHCP 2.配置地址 3.ospf 4.dhcp 5.acl AR1 dhcp en interface GigabitEthernet0/0/0ip address 192.168.1.254 255.255.255.0 dhcp select global interface GigabitEthernet0/0/1ip address 10.1.12.1 255.255.255.…...

金融租赁系统助力企业升级与风险管理的新篇章

内容概要 在当今的商业环境中&#xff0c;“金融租赁系统”可谓是企业成功的秘密武器。简单来说&#xff0c;这个系统就像一位聪明的财务顾问&#xff0c;帮助企业在资金和资源的运用上达到最优化。从设备采购到项目融资&#xff0c;它提供了一种灵活的方式&#xff0c;让企业…...

linux安装部署mysql资料

安装虚拟机 等待检查完成 选择中文 软件选择 网络和主机名 开始安装 设置root密码 ADH-password 创建用户 等待安装完成 重启 接受许可证 Centos 7 64安装完成 安装mysql开始 Putty连接指定服务器 在 opt目录下新建download目录 将mysql文件传到该目录下 查看linux服务器的…...

深入理解 MongoDB:一款灵活高效的 NoSQL 数据库

在现代应用程序开发中&#xff0c;数据存储技术已经从传统的关系型数据库&#xff08;RDBMS&#xff09;扩展到多样化的 NoSQL 数据库。MongoDB 作为一款广泛使用的文档型数据库&#xff0c;以其灵活性、高性能和易用性成为开发者的首选之一。本篇博文将从 MongoDB 的核心概念、…...

爆改老旧笔记本---将笔记本改造为家用linux服务器

爆改老旧笔记本---将笔记本改造为家用linux服务器 linux启动盘制作镜像文件分区类型:MBR分区和GPT分区的定义MBR分区&#xff08;Master Boot Record&#xff09;GPT分区&#xff08;GUID Partition Table&#xff09;应用场景和优势MBR的应用场景和优势GPT的应用场景和优势 Li…...

RocketMQ MQTT Windows10 环境启动

RocketMQ MQTT Windows10 环境启动 参考环境和软件版本下载资源启动RocketMQ启动RocketMQ MQTT 参考 https://blog.csdn.net/weixin_43114058/article/details/140043257 https://blog.csdn.net/yangxiaovip/article/details/138355443 环境和软件版本 操作系统&#xff1a…...

sd webui整合包怎么安装comfyui

环境: sd webui整合包 comfyui 问题描述: sd webui整合包怎么安装comfyui 扩展安装不成功 解决方案: 1.直接下载 ,解压到SD文件夹里(或者git拉一下) 2.ComfyUI模型共享:如果本机部署过Webui,那么ComfyUI可以与WebUI公用一套模型,防止复制大量模型浪费空间 将…...

Edify 3D: Scalable High-Quality 3D Asset Generation

Deep Imagination Research | NVIDIA 目录 一、Abstract 二、核心内容 1、多视图扩散模型 3、重建模型&#xff1a; 4、数据处理模块&#xff1a; 三、结果 1、文本到 3D 生成结果 2、图像到 3D 生成结果 3、四边形网格拓扑结构 一、Abstract NVIDIA 开发的用于高质量…...

鸿蒙HarmonyOS学习笔记(6)

定义扩展组件样式&#xff1a;Extend装饰器 在前文的示例中&#xff0c;可以使用Styles用于样式的重用&#xff0c;在Styles的基础上&#xff0c;我们提供了Extend&#xff0c;用于扩展原生组件样式。 说明 从API version 9开始&#xff0c;该装饰器支持在ArkTS卡片中使用。 从…...

蓝桥杯备赛笔记(一)

这里的笔记是关于蓝桥杯关键知识点的记录&#xff0c;有别于基础语法&#xff0c;很多内容只要求会用就行&#xff0c;无需深入掌握。 文章目录 前言一、编程基础1.1 C基础格式和版本选择1.2 输入输出cin和cout&#xff1a; 1.3 string以下是字符串的一些简介&#xff1a;字符串…...

在Java中使用Apache POI导入导出Excel(二)

本文将继续介绍POI的使用&#xff0c;上接在Java中使用Apache POI导入导出Excel&#xff08;一&#xff09; 使用Apache POI组件操作Excel&#xff08;二&#xff09; 14、读取和重写工作簿 try (InputStream inp new FileInputStream("workbook.xls")) { //Inpu…...

linux 中后端jar包启动不起来怎么回事 -bash: java: 未找到命令

一、用以下命令检查jdk版本 输入&#xff1a;java -version&#xff0c;如果JDK 环境变量没有配置&#xff0c;你会看到如下提示 二、配置jdk环境 1.先找到/etc/profile文件&#xff0c;然后在该文件最后面加上以下配置 export JAVA_HOME/usr/local/jdk-21.0.1 export PATH$…...

六大排序算法:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序

本章讲述数据结构中的六大排序算法 欢迎大佬们踊跃讨论&#xff0c;感谢大家支持&#xff01; 我的博客主页链接 六大排序算法 一.插入排序1.1 直接插入排序1.2 希尔排序 二.选择排序2.1 单向选择排序2.2双向选择排序2.3 堆排序 三.交换排序3.1 冒泡排序3.2 快速排序3.2.1 Hoa…...

快速排序(C++实现)

基本思想 任取一个元素为中心&#xff0c;所有比它小的元素一律前放&#xff0c;比他大的元素一律后放&#xff0c;形成左右两个子表&#xff1b;对各子表重新选择中心元素并依此规则调整&#xff0c;直到每个子表的元素只剩一个。 通过一趟排序&#xff0c;将待排序记录分割成…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...