小游戏项目实战:手把手教你做一个摸鱼小游戏
最近午休时间我用原生 JavaScript 写了一个摸鱼小游戏——屏幕上随机出现小图标点中加分点错扣血考验反应速度。同事们玩得不亦乐乎甚至有人拿来 PK 手速。做这个小游戏的时候我在花猫导航huamaodh.com的设计资源分类里找到了免费的图标素材库省去了自己画的麻烦。今天就把这个项目的完整代码和实现思路分享出来前端新手也能跟着一步步做出来。一、游戏设计思路我们要做的是一个“打地鼠”风格的点击小游戏核心规则很简单游戏区域内有 9 个格子3×3 排列随机一个小鱼 emoji 在某个格子里冒出来玩家点击小鱼加分点空了扣生命值每过一段时间速度加快越来越难生命值归零游戏结束显示最终得分技术选型纯 HTML CSS JavaScript不需要任何框架复制代码到记事本保存成.html文件就能玩。二、HTML 结构搭建html!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title摸鱼大作战/title style * { margin: 0; padding: 0; box-sizing: border-box; } body { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); min-height: 100vh; display: flex; justify-content: center; align-items: center; font-family: PingFang SC, Microsoft YaHei, sans-serif; } .game-container { background: rgba(255, 255, 255, 0.05); border-radius: 20px; padding: 30px; backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1); text-align: center; } .game-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; color: #fff; } .score-area { text-align: left; } .score-label { font-size: 12px; color: #8892b0; letter-spacing: 2px; } .score-value { font-size: 36px; font-weight: 700; color: #64ffda; } .lives-area { display: flex; gap: 6px; } .heart { font-size: 24px; transition: all 0.3s; } .heart.lost { opacity: 0.2; transform: scale(0.8); } .grid { display: grid; grid-template-columns: repeat(3, 120px); grid-template-rows: repeat(3, 120px); gap: 12px; margin-bottom: 20px; } .cell { background: rgba(255, 255, 255, 0.08); border-radius: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 56px; transition: all 0.15s; position: relative; user-select: none; } .cell:hover { background: rgba(255, 255, 255, 0.15); transform: scale(1.03); } .cell.active { background: rgba(100, 255, 218, 0.15); animation: pulse 0.6s ease-in-out; } .cell.miss { background: rgba(255, 107, 107, 0.3); animation: shake 0.4s ease-in-out; } keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } } keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } } .game-status { color: #8892b0; font-size: 14px; margin-bottom: 16px; min-height: 20px; } .start-btn { background: linear-gradient(135deg, #64ffda 0%, #48c9b0 100%); color: #1a1a2e; border: none; padding: 14px 48px; border-radius: 30px; font-size: 16px; font-weight: 600; cursor: pointer; letter-spacing: 1px; transition: all 0.3s; } .start-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(100, 255, 218, 0.3); } .start-btn:active { transform: translateY(0); } .start-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; } .game-over-overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.7); justify-content: center; align-items: center; z-index: 100; } .game-over-overlay.show { display: flex; } .game-over-card { background: #1a1a2e; border-radius: 20px; padding: 40px; text-align: center; border: 1px solid rgba(255, 255, 255, 0.1); } .game-over-card h2 { color: #ff6b6b; font-size: 28px; margin-bottom: 12px; } .game-over-card .final-score { color: #64ffda; font-size: 48px; font-weight: 700; margin-bottom: 20px; } .game-over-card button { background: #64ffda; color: #1a1a2e; border: none; padding: 12px 36px; border-radius: 24px; font-size: 15px; font-weight: 600; cursor: pointer; } /style /head body div classgame-container !-- 顶部信息栏 -- div classgame-header div classscore-area div classscore-label当前得分/div div classscore-value idscore0/div /div div classlives-area idlives span classheart❤️/span span classheart❤️/span span classheart❤️/span span classheart❤️/span span classheart❤️/span /div /div !-- 游戏网格 -- div classgrid idgrid div classcell>// 游戏状态 const state { score: 0, lives: 5, isRunning: false, currentFishIndex: -1, timer: null, speed: 1000, // 小鱼出现的间隔毫秒 minSpeed: 350, // 最快速度 speedStep: 30 // 每得10分加速的幅度 }; // DOM 元素 const grid document.getElementById(grid); const cells document.querySelectorAll(.cell); const scoreEl document.getElementById(score); const livesEl document.getElementById(lives); const statusEl document.getElementById(status); const startBtn document.getElementById(startBtn); const gameOverlay document.getElementById(gameOverlay); const finalScoreEl document.getElementById(finalScore); // 随机生成小鱼位置保证和上次不一样 function randomFishIndex() { if (state.currentFishIndex -1) { return Math.floor(Math.random() * 9); } let newIndex; do { newIndex Math.floor(Math.random() * 9); } while (newIndex state.currentFishIndex); return newIndex; } // 在指定格子显示小鱼 function showFish(index) { // 清除所有格子的内容 cells.forEach(cell { cell.textContent ; cell.classList.remove(active); }); // 在目标格子放小鱼 state.currentFishIndex index; cells[index].textContent ; cells[index].classList.add(active); } // 隐藏小鱼 function hideFish() { if (state.currentFishIndex 0) { cells[state.currentFishIndex].textContent ; cells[state.currentFishIndex].classList.remove(active); } state.currentFishIndex -1; } // 扣血 function loseLife() { state.lives--; updateLivesDisplay(); if (state.lives 0) { endGame(); } } // 更新生命值显示 function updateLivesDisplay() { const hearts livesEl.querySelectorAll(.heart); hearts.forEach((heart, index) { if (index state.lives) { heart.classList.add(lost); } else { heart.classList.remove(lost); } }); } // 更新分数 function updateScore(points 1) { state.score points; scoreEl.textContent state.score; // 每得 10 分加速 if (state.score % 10 0 state.speed state.minSpeed) { state.speed Math.max(state.minSpeed, state.speed - state.speedStep); // 重新设置定时器 clearInterval(state.timer); state.timer setInterval(gameLoop, state.speed); statusEl.textContent ⚡ 速度加快了; setTimeout(() { if (state.isRunning) { statusEl.textContent 快点击小鱼; } }, 800); } } // 游戏主循环 function gameLoop() { if (!state.isRunning) return; // 如果上一条小鱼没被点中扣血 if (state.currentFishIndex 0) { // 标记为未命中 cells[state.currentFishIndex].classList.add(miss); setTimeout(() { cells[state.currentFishIndex].classList.remove(miss); }, 400); loseLife(); } // 如果游戏还在继续显示下一条鱼 if (state.isRunning) { const newIndex randomFishIndex(); showFish(newIndex); } } // 处理格子点击 function handleCellClick(event) { if (!state.isRunning) return; const cell event.currentTarget; const index parseInt(cell.dataset.index); if (index state.currentFishIndex) { // 点中了 updateScore(); hideFish(); // 立即显示下一条不等定时器 if (state.isRunning) { clearInterval(state.timer); const newIndex randomFishIndex(); showFish(newIndex); state.timer setInterval(gameLoop, state.speed); } } else { // 点空了 cell.classList.add(miss); setTimeout(() cell.classList.remove(miss), 400); loseLife(); } } // 开始游戏 function startGame() { // 重置状态 state.score 0; state.lives 5; state.isRunning true; state.speed 1000; state.currentFishIndex -1; // 更新界面 scoreEl.textContent 0; updateLivesDisplay(); statusEl.textContent 快点击小鱼; startBtn.disabled true; startBtn.textContent 游戏中...; gameOverlay.classList.remove(show); // 清空格子 cells.forEach(cell { cell.textContent ; cell.classList.remove(active, miss); }); // 立刻显示第一条鱼 const firstIndex randomFishIndex(); showFish(firstIndex); // 启动定时器 state.timer setInterval(gameLoop, state.speed); } // 结束游戏 function endGame() { state.isRunning false; clearInterval(state.timer); hideFish(); // 更新界面 statusEl.textContent 游戏结束 ; startBtn.disabled false; startBtn.textContent 再来一局; // 显示弹窗 finalScoreEl.textContent state.score; gameOverlay.classList.add(show); // 清空格子 cells.forEach(cell { cell.textContent ; cell.classList.remove(active, miss); }); } // 重新开始 function restartGame() { startGame(); } // 绑定事件 cells.forEach(cell { cell.addEventListener(click, handleCellClick); }); startBtn.addEventListener(click, startGame); // 初始化状态 statusEl.textContent 准备好摸鱼了吗;四、游戏玩法与体验优化把上面两段代码合在一起保存成.html文件双击打开就能玩。核心玩法就是眼疾手快小鱼冒出来立刻点。几个设计上的小细节惩罚机制上一条鱼没被点击就消失会扣一条命。这样玩家不敢走神增加紧张感。渐进难度每得 10 分小鱼出现速度加快 30 毫秒越来越难最高到 350 毫秒间隔。老手能撑到 100 分以上就已经很强了。即时反馈点中格子有绿色脉冲动画点错有红色抖动手感清晰。游戏结束弹窗用半屏遮罩展示最终得分增加仪式感同事围观时更有表演效果。五、扩展思路怎么让它更好玩如果这个基础版本已经满足不了你了可以从这几个方向继续打磨1. 加音效用 Web Audio API 或简单的audio标签点中播“叮”一声点错播“咚”一声游戏氛围瞬间拉满。2. 引入道具系统随机出现炸弹点了扣分、金鱼点了加 3 分、乌龟点了减速让策略性更强。3. 排行榜用localStorage把最高分存到浏览器里每次打完显示“新纪录”。甚至可以接入后端做全公司排行榜。4. 美化图标代码里用的是 emoji你也可以换成自己喜欢的图标素材。六、写在最后这个摸鱼小游戏代码量不大前后端一共不到 200 行但涵盖了 DOM 操作、定时器管理、状态机、CSS 动画等前端核心知识点。对于正在学 JavaScript 的新手来说比写 Todo List 有趣多了而且做完就能玩成就感满满。偶尔写点这种“无用但快乐”的代码就当是给大脑做一次按摩。下次午休不如把这篇教程打开花半小时敲出来然后跟同事比一比谁的摸鱼手速更快。祝你玩得开心也祝你摸鱼不被发现。

相关新闻

NocoBase 2024 开源资产管理:零代码搭建 7 大核心模块,3 天完成原型开发

NocoBase 2024 开源资产管理:零代码搭建 7 大核心模块,3 天完成原型开发

NocoBase 2024 开源资产管理:零代码搭建 7 大核心模块实战指南在数字化转型浪潮中,固定资产管理正成为企业降本增效的关键环节。传统开发模式面临周期长、成本高、迭代慢等痛点,而低代码技术的成熟为这一问题提供了全新解法。NocoBase 作为国…

2026/7/10 8:06:15阅读更多 →
大模型微调实战指南:从LoRA到RAG,打造专属AI专家

大模型微调实战指南:从LoRA到RAG,打造专属AI专家

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 你有没有遇到过这样的场景:一个通用的大语言模型,比如 ChatGPT 或 Claude,在回答你专业领域的问题…

2026/7/10 8:06:15阅读更多 →
西门子S7-1500运动控制实战:3轴联动位置控制详解

西门子S7-1500运动控制实战:3轴联动位置控制详解

S7-1500是西门子中高端PLC的旗舰产品,其运动控制功能强大。本文通过一个3轴联动的位置控制案例,详解S7-1500运动控制的配置和编程要点。一、项目场景需求:控制一个XYZ三轴运动平台,实现以下功能:X轴和Y轴联动实现平面定…

2026/7/10 8:06:15阅读更多 →
AD5593R与TM4C1294KCPDT的硬件设计与应用解析

AD5593R与TM4C1294KCPDT的硬件设计与应用解析

1. AD5593R与TM4C1294KCPDT的硬件组合解析AD5593R是ADI公司推出的一款12位可配置ADC/DAC芯片,具有8个可独立配置的I/O引脚。这些引脚可以灵活设置为DAC输出、ADC输入、数字输出或数字输入。这种高度可配置性使其成为嵌入式系统中模拟信号处理的理想选择。TM4C1294KC…

2026/7/10 9:11:20阅读更多 →
Windows苹果触控板终极指南:mac-precision-touchpad驱动全面解析

Windows苹果触控板终极指南:mac-precision-touchpad驱动全面解析

Windows苹果触控板终极指南:mac-precision-touchpad驱动全面解析 【免费下载链接】mac-precision-touchpad Windows Precision Touchpad Driver Implementation for Apple MacBook / Magic Trackpad 项目地址: https://gitcode.com/gh_mirrors/ma/mac-precision-t…

2026/7/10 9:11:20阅读更多 →
基于大模型与自动化工作流实现AI Agent自构建的工程实践

基于大模型与自动化工作流实现AI Agent自构建的工程实践

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 在探索AI Agent开发的路上,你是否曾想过,能否让一个AI Agent去自动构建另一个AI Agent?这听起来像…

2026/7/10 9:11:20阅读更多 →
Python手机号查QQ号终极指南:3分钟掌握高效查询技术

Python手机号查QQ号终极指南:3分钟掌握高效查询技术

Python手机号查QQ号终极指南:3分钟掌握高效查询技术 【免费下载链接】phone2qq 项目地址: https://gitcode.com/gh_mirrors/ph/phone2qq 在数字身份管理日益重要的今天,快速查询手机号关联的QQ号成为许多开发者和技术爱好者的实际需求。phone2qq…

2026/7/10 9:11:20阅读更多 →
Dify实战指南:从零构建智能客服工单处理自动化工作流

Dify实战指南:从零构建智能客服工单处理自动化工作流

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 如果你是一名开发者,最近一定被“AI应用开发”和“智能体”这两个词频繁刷屏。从ChatGPT的爆火到各类AI Agent平台的涌现&…

2026/7/10 9:11:20阅读更多 →
广州吟颂调研:职称评审的“可控性”博弈:实力之外,拼的是信息与细节

广州吟颂调研:职称评审的“可控性”博弈:实力之外,拼的是信息与细节

职称评审是许多职场人职业生涯中的一道“硬门槛”。每到申报季,总有人感叹“明明条件都够,为什么没过”,也有人看似“擦边”却顺利通过。抛开运气成分,评审本质上是一场**“材料合规性价值证明力”**的比拼。下面这5个策略&#x…

2026/7/10 9:06:19阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/9 5:56:19阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/9 9:45:20阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/10 4:59:05阅读更多 →
浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比

浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比

浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比当你在浏览器地址栏敲入一个网址时,背后可能隐藏着一场关于"要不要重新下载资源"的精密博弈。这场博弈的裁判是HTTP缓存机制,而304状态码则是这场博弈…

2026/7/10 0:00:01阅读更多 →
RoboWits:面向创造性问题求解的双臂机器人认知推理基准

RoboWits:面向创造性问题求解的双臂机器人认知推理基准

1. 项目概述:这不是又一个机器人抓取数据集,而是一次对“思考力”的压力测试 RoboWits——这个名字里藏着两个关键信号:“Robo”直指物理世界中的具身智能体,“Wits”则毫不掩饰地指向人类最核心的认知能力:机敏、判断…

2026/7/10 0:00:01阅读更多 →
5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能

5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能

5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能 【免费下载链接】TegraRcmGUI C GUI for TegraRcmSmash (Fuse Gele exploit for Nintendo Switch) 项目地址: https://gitcode.com/gh_mirrors/te/TegraRcmGUI TegraRcmGUI是一款专为Windows…

2026/7/10 0:00:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/9 9:45:20阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/9 15:50:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/9 14:14:17阅读更多 →