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

打造现象级H5答题游戏:《终极主题答题冒险》开源项目详解

🎮 打造现象级H5答题游戏:《终极主题答题冒险》开源项目详解

摘要: 本文将手把手带你解析并部署一个令人惊艳的开源HTML5答题游戏——《终极主题答题 Adventure》。它不仅仅是一个问答应用,更是一个融合了角色扮演、主题切换和精美动画的沉浸式学习体验。告别枯燥的题库,让每一次答题都成为一场视觉盛宴!

关键词: HTML5, JavaScript, CSS3, 前端游戏, 答题游戏, 主题切换, SVG动画, 游戏开发, 开源项目


🌟 项目亮点:为什么它如此特别?

在众多的在线题库和答题应用中,《终极主题答题冒险》凭借其独特的设计理念脱颖而出:

  1. 🎭 动态主题系统: 这是本项目的核心灵魂!每一道题目都关联一个独立的视觉主题(如“超级马里奥”、“森林守护者”、“太空探险”等)。当你切换题目时,整个游戏界面——从背景、地面、角色形象到选项方块和装饰物——都会进行一次彻底的、流畅的“换装”。这种设计极大地提升了游戏的趣味性和新鲜感,让玩家始终保持探索欲。

  2. 🕹️ 融合游戏玩法: 它不是简单的点击选择。玩家需要通过左右移动按钮控制一个可爱的角色在四个选项(A, B, C, D)之间移动,然后点击“跳跃”按钮来“踩”中答案。答对时,角色会欢快地跳跃;答错时,则会“壮烈牺牲”,代入感十足。

  3. 🎨 精致的视觉与动画: 项目大量使用了CSS3动画、SVG绘制角色和渐变背景。每个主题的细节都经过精心设计,配合音效(项目已集成公有领域音效),营造出极佳的视听体验。(目前音效部分有bug,应该是原来的资源在cdn上不存在了)

  4. 🧠 教育与娱乐结合: 通过游戏化的方式学习知识,寓教于乐。内置的题目是编程相关的,但你可以轻松替换为任何领域的题库(历史、地理、生物等),使其成为一个万能的学习工具。

  5. 📱 完美响应式设计: 项目对移动端进行了优化,无论是手机还是平板,都能获得流畅的操作体验。

在线Demo体验: 点击这里,立即开始你的冒险!


🛠️ 核心代码结构解析

整个项目是一个单HTML文件,结构清晰,主要分为以下几个部分:

1. HTML结构 (index.html)

  • 游戏容器 (#gameContainer): 包裹所有游戏元素。
  • HUD界面 (#hud): 显示分数、收集品和生命值。
  • 题目与选项区 (#questionArea, #optionsContainer): 展示当前题目和四个可选答案。
  • 角色与地面 (#character, #ground): 可移动的角色和游戏的“舞台”。
  • 控制按钮 (#controls): 左、跳、右三个操作按钮。
  • 反馈与弹窗 (#answerScreen, #startScreen): 用于显示答题结果和游戏开始/结束界面。
  • 音效元素 (<audio>): 预加载的跳跃、答对、答错等音效。

2. CSS样式

样式部分定义了所有元素的布局、动画和默认外观。其中最关键的是主题系统,它通过动态插入<style>标签来覆盖默认的CSS类,从而实现主题的彻底切换。

/* 示例:马里奥主题的选项块样式 */
.theme-block-style {.optionBlock {background: linear-gradient(to bottom, #FFB84D, #CC8E33);border: 2px solid #663300;border-radius: 5px 5px 0 0;}
}

3. JavaScript逻辑 (<script>)

这是游戏的大脑,主要包含以下几个模块:

  • themes 对象: 定义了所有可用主题的详细配置,包括背景、角色SVG、选项样式、奖励动画和装饰物HTML。

    const themes = {mario: {name: "超级马里奥",background: "linear-gradient(...)",character: `<svg>...</svg>`,// ... 其他配置},// ... 其他主题
    };
    
  • questions 数组: 存储题库。每道题都包含question(问题)、options(选项)、correct(正确答案)和theme(关联主题)四个关键字段。

    const questions = [{question: "JavaScript中,以下哪个不是原始数据类型?",options: ["Number", "Array", "String", "Boolean"],correct: "B",theme: "mario" // 关键!指定本题主题},// ... 更多题目
    ];
    
  • applyTheme(themeKey) 函数: 主题切换的核心。它会根据传入的主题名,动态修改body背景、ground样式、角色SVG、装饰物,并插入新的CSS样式表来覆盖选项的外观。

    function applyTheme(themeKey) {const theme = themes[themeKey];document.body.style.background = theme.background;ground.style.cssText = theme.groundStyle;character.innerHTML = theme.character; // 直接替换SVG// ... 处理装饰物和样式表
    }
    
  • 游戏状态管理 (gameState): 一个对象,用于跟踪当前分数、生命值、题目索引、角色位置等。

  • 核心游戏循环: 包括loadQuestion()(加载题目并切换主题)、moveToBlock()(移动角色)、jump()(跳跃并触发答题)和checkAnswer()(判断对错并播放反馈)。


🚀 如何自定义你的专属题库?

这个项目的最大魅力在于其高度可定制性。你只需修改questions数组,就能轻松创建属于你自己的知识冒险!

步骤如下:

  1. 找到questions数组: 在HTML文件的<script>标签内,定位到const questions = [...]部分。
  2. 添加或修改题目对象: 每个题目对象必须包含以下四个属性:
    • question: 问题的文本。
    • options: 一个包含四个选项文本的数组。
    • correct: 正确答案的字母(“A”, “B”, “C”, 或 “D”)。
    • theme: 该题目要使用的主题名(必须是themes对象中已定义的键,如"mario", "space"等)。
  3. 保存并刷新: 修改完成后,保存文件并在浏览器中刷新即可看到效果。

示例:添加一道历史题

{question: "中国历史上第一个皇帝是谁?",options: ["刘邦", "项羽", "秦始皇", "汉武帝"],correct: "C",theme: "goldMiner" // 使用“黄金矿工”主题,寓意挖掘历史宝藏
}

通过这种方式,你可以为不同学科、不同难度的题目分配不同的主题,让学习过程充满惊喜。


📌 总结与展望

《终极主题答题冒险》是一个将前端技术(HTML5, CSS3, JavaScript)与游戏设计理念完美结合的典范。它证明了学习工具也可以做得非常有趣和吸引人。

项目价值:

  • 对学习者: 提供了一种全新的、沉浸式的学习方式。
  • 对开发者: 是一个绝佳的学习项目,涵盖了动态样式、SVG动画、状态管理和音效处理等多个前端知识点。
  • 对教育者: 可以作为教学辅助工具,激发学生的学习兴趣。

未来可以拓展的方向:

  • 增加更多主题(如“埃及法老”、“未来都市”)。
  • 引入道具系统(如“复活卡”、“提示卡”)。
  • 增加本地存储,记录玩家最高分。
  • 实现题目难度分级。

立即获取源码,开启你的创作之旅吧!


**项目源码:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"><title>终极主题答题冒险</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: "Helvetica Neue", "Arial", sans-serif;height: 100vh;overflow: hidden;position: relative;transition: background 0.8s ease;}#gameContainer {width: 100%;height: 100vh;position: relative;overflow: hidden;}/* HUD */#hud {position: absolute;top: 15px;left: 15px;color: white;font-size: 16px;font-weight: bold;text-shadow: 2px 2px 3px rgba(0,0,0,0.6);z-index: 100;}#hud div {margin-bottom: 5px;}/* 题目区域 */#questionArea {position: absolute;top: 70px;left: 50%;transform: translateX(-50%);background: rgba(0, 0, 0, 0.7);color: white;padding: 20px;border-radius: 10px;max-width: 90%;text-align: center;font-size: 18px;line-height: 1.6;box-shadow: 0 4px 8px rgba(0,0,0,0.3);z-index: 20;transition: all 0.5s ease;}/* 选项容器 */.optionsContainer {position: absolute;top: 200px;left: 50%;transform: translateX(-50%);display: flex;gap: 20px;width: fit-content;z-index: 15;}/* 默认选项样式(每个主题会彻底覆盖) */.optionBlock {width: 100px;height: 80px;display: flex;flex-direction: column;justify-content: center;align-items: center;font-family: "Helvetica Neue", Arial, sans-serif;cursor: default;position: relative;transition: transform 0.2s;border-radius: 5px;color: #333;}.optionBlock .label {font-size: 20px;font-weight: bold;}.optionBlock .text {font-size: 12px;margin-top: 4px;text-align: center;padding: 0 5px;}/* 反馈动画 */.optionBlock.correct { animation: correctAnim 0.6s ease-out forwards; }.optionBlock.wrong { animation: wrongAnim 0.5s ease-out forwards; opacity: 0.7; }@keyframes correctAnim {0% { transform: scale(1); }50% { transform: scale(1.2) rotate(15deg); }100% { transform: scale(1); }}@keyframes wrongAnim {0% { transform: rotate(0deg); }100% { transform: rotate(15deg) translateY(50px); opacity: 0.2; }}/* 角色容器 */#character {position: absolute;bottom: 160px;width: 40px;height: 40px;z-index: 10;transition: left 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s ease;filter: drop-shadow(2px 4px 3px rgba(0,0,0,0.4));}/* 角色动画 */#character.jump { animation: jump 0.8s ease-out; }#character.die { animation: die 1s ease-out forwards; }@keyframes jump {0%, 100% { transform: translateY(0); }50% { transform: translateY(-120px); }}@keyframes die {0% { transform: translateY(0) rotate(0deg); }50% { transform: translateY(-80px) rotate(180deg); }100% { transform: translateY(200px) rotate(360deg); opacity: 0; }}/* 地面 */#ground {position: absolute;bottom: 0;width: 100%;height: 100px;transition: all 0.5s ease;}/* 控制按钮 */#controls {position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);display: flex;gap: 15px;z-index: 100;}.controlBtn {width: 70px;height: 70px;background: rgba(255,255,255,0.3);border: 3px solid white;border-radius: 50%;display: flex;align-items: center;justify-content: center;font-size: 28px;color: white;cursor: pointer;user-select: none;font-weight: bold;box-shadow: 0 4px 8px rgba(0,0,0,0.3);transition: all 0.2s;}.controlBtn:active {background: rgba(255,255,255,0.5);transform: scale(0.95);}/* 奖励动画容器 */.reward {position: absolute;z-index: 50;animation: floatUp 1.5s ease-out forwards;}@keyframes floatUp {0% { transform: translateY(0) scale(1); opacity: 1; }100% { transform: translateY(-150px) scale(0.3); opacity: 0; }}/* 反馈弹窗 */.feedback {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);padding: 20px 30px;border-radius: 10px;font-size: 18px;font-weight: bold;text-align: center;z-index: 200;animation: fadeInOut 1.5s ease-out forwards;color: white;text-shadow: 1px 1px 2px rgba(0,0,0,0.8);}@keyframes fadeInOut {0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }50% { opacity: 1; transform: translate(-50%, -50%) scale(1.05); }100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }}/* 答案反馈层(新增) */#answerScreen {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.85);display: flex;flex-direction: column;align-items: center;justify-content: center;z-index: 300;color: white;padding: 20px;text-align: center;display: none;}#answerScreen h2 {font-size: 24px;margin-bottom: 15px;color: #FFD700;}#answerScreen p {font-size: 18px;margin-bottom: 25px;line-height: 1.5;}#answerScreen .btn {padding: 12px 30px;margin: 0 10px;background: #FF6B35;border: none;border-radius: 8px;color: white;font-size: 18px;font-weight: bold;cursor: pointer;transition: background 0.2s, transform 0.2s;}#answerScreen .btn:hover {background: #FF8552;transform: scale(1.05);}/* 开始界面 */#startScreen {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.9);display: flex;flex-direction: column;align-items: center;justify-content: center;z-index: 400;color: white;}#startScreen h1 {font-size: 28px;margin-bottom: 20px;text-align: center;line-height: 1.4;}.startBtn {padding: 15px 40px;background: #FF6B35;border: none;border-radius: 8px;color: white;font-size: 18px;font-weight: bold;cursor: pointer;transition: transform 0.2s, background 0.2s;box-shadow: 0 5px 15px rgba(0,0,0,0.3);}.startBtn:hover {background: #FF8552;transform: scale(1.05);}/* 结束界面 */.endScreen {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.9);display: flex;flex-direction: column;align-items: center;justify-content: center;z-index: 500;color: white;}.endScreen h1 {font-size: 32px;margin-bottom: 20px;}.endScreen .stats {font-size: 20px;margin-bottom: 30px;text-align: center;line-height: 1.6;}/* 装饰元素容器 */#decorationContainer {position: absolute;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none;z-index: 1;}/* 响应式 */@media (max-width: 600px) {#questionArea { font-size: 16px; padding: 15px; }.controlBtn { width: 60px; height: 60px; font-size: 24px; }.optionBlock { width: 80px; height: 70px; }.optionBlock .label { font-size: 18px; }.optionBlock .text { font-size: 11px; }}</style>
</head>
<body><div id="gameContainer"><!-- 装饰元素 --><div id="decorationContainer"></div><!-- HUD --><div id="hud"><div>分数: <span id="score">0</span></div><div>收集: <span id="rewards">0</span></div><div>生命: <span id="lives">❤️❤️❤️</span></div></div><!-- 题目区 --><div id="questionArea"><div id="questionText">点击开始游戏</div></div><!-- 选项区 --><div class="optionsContainer" id="optionsContainer"></div><!-- 角色 --><div id="character"></div><!-- 地面 --><div id="ground"></div><!-- 控制按钮 --><div id="controls"><div class="controlBtn" id="leftBtn"></div><div class="controlBtn" id="jumpBtn"></div><div class="controlBtn" id="rightBtn"></div></div><!-- 答案反馈层 --><div id="answerScreen"><h2 id="answerTitle">✓ 正确!</h2><p id="answerDetail">答案:A - Number</p><div><button class="btn" id="nextBtn">下一题</button><button class="btn" id="retryBtn" style="display:none;">再试一次</button></div></div><!-- 开始界面 --><div id="startScreen"><h1>🎭 终极主题答题冒险 🎮</h1><p style="color:#ccc;margin-bottom:30px;">每道题都是全新世界!</p><button class="startBtn" id="startBtn">开始冒险</button></div><!-- 音效元素(使用公有领域 MP3 + jsDelivr CDN) --><audio id="jumpSound" src="https://cdn.jsdelivr.net/gh/KenneyNL/kenney-sounds@master/sounds/retro/retro-game04.mp3" preload="auto"></audio><audio id="correctSound" src="https://cdn.jsdelivr.net/gh/KenneyNL/kenney-sounds@master/sounds/interface/interface_01.mp3" preload="auto"></audio><audio id="wrongSound" src="https://cdn.jsdelivr.net/gh/KenneyNL/kenney-sounds@master/sounds/interface/interface_03.mp3" preload="auto"></audio><audio id="coinSound" src="https://cdn.jsdelivr.net/gh/KenneyNL/kenney-sounds@master/sounds/coins/coins_01.mp3" preload="auto"></audio><audio id="successSound" src="https://cdn.jsdelivr.net/gh/KenneyNL/kenney-sounds@master/sounds/interface/interface_05.mp3" preload="auto"></audio><audio id="failSound" src="https://cdn.jsdelivr.net/gh/KenneyNL/kenney-sounds@master/sounds/interface/interface_04.mp3" preload="auto"></audio></div><script>// =====================// 🎭 主题配置系统(彻底不同的视觉系统)// =====================const themes = {mario: {name: "超级马里奥",background: "linear-gradient(to bottom, #5C94FC 0%, #5C94FC 80%, #C84C0C 80%)",groundStyle: "linear-gradient(to bottom, #8B7355 0%, #8B7355 10%, #5C4033 10%); border-top: 5px solid #3A2A1A;",questionBg: "rgba(0, 0, 0, 0.7)",character: `<svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><circle cx="20" cy="15" r="12" fill="#FF6B35"/> <!-- 帽子 --><rect x="10" y="20" width="20" height="15" fill="red" rx="2"/> <!-- 身体 --><rect x="12" y="35" width="6" height="5" fill="#333" rx="1"/> <!-- 左脚 --><rect x="22" y="35" width="6" height="5" fill="#333" rx="1"/> <!-- 右脚 --><circle cx="16" cy="12" r="2" fill="#fff"/> <!-- 左眼 --><circle cx="24" cy="12" r="2" fill="#fff"/> <!-- 右眼 --><circle cx="17" cy="12" r="1" fill="#000"/> <!-- 左瞳孔 --><circle cx="25" cy="12" r="1" fill="#000"/> <!-- 右瞳孔 --><rect x="18" y="18" width="4" height="2" fill="#000" rx="1"/> <!-- 嘴 --></svg>`,blockStyle: `.optionBlock {background: linear-gradient(to bottom, #FFB84D, #CC8E33);border: 2px solid #663300;border-radius: 5px 5px 0 0;}`,reward: {html: `<div style="width:30px;height:30px;background:radial-gradient(circle,#FFD700,#FFA500);border:2px solid #FFB84D;border-radius:50%;"></div>`,animation: "floatUp"},decorations: `<!-- 云朵 --><div style="position:absolute;width:120px;height:50px;top:15%;left:15%;background:white;border-radius:50px;opacity:0.8;animation:floatCloud 25s infinite ease-in-out;"></div><div style="position:absolute;width:90px;height:40px;top:10%;right:20%;background:white;border-radius:50px;opacity:0.8;animation:floatCloud 30s infinite ease-in-out;"></div><!-- 管道 --><div style="position:absolute;width:60px;height:100px;bottom:100px;left:80px;background:linear-gradient(to right,#00A800,#00D800,#008400);border:2px solid #003600;border-radius:5px 5px 0 0;"></div><div style="position:absolute;width:60px;height:100px;bottom:100px;right:80px;background:linear-gradient(to right,#00A800,#00D800,#008400);border:2px solid #003600;border-radius:5px 5px 0 0;"></div>`,animations: `@keyframes floatCloud {0%, 100% { transform: translateX(0); }50% { transform: translateX(40px); }}`,correctAnim: "scale(1.2) rotate(15deg)",wrongAnim: "rotate(15deg) translateY(50px)"},eco: {name: "森林守护者",background: "linear-gradient(to bottom, #87CEEB 0%, #87CEEB 70%, #228B22 70%)",groundStyle: "linear-gradient(to bottom, #3A5F0B 0%, #013220 100%); border-top: 5px solid #006400;",questionBg: "rgba(0, 80, 0, 0.7)",character: `<svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><circle cx="20" cy="15" r="12" fill="#4169E1"/> <!-- 头盔 --><rect x="10" y="20" width="20" height="15" fill="#32CD32" rx="2"/> <!-- 环保服 --><rect x="12" y="35" width="6" height="5" fill="#8B4513" rx="1"/> <!-- 左靴 --><rect x="22" y="35" width="6" height="5" fill="#8B4513" rx="1"/> <!-- 右靴 --><circle cx="16" cy="12" r="2" fill="#fff"/> <!-- 左眼 --><circle cx="24" cy="12" r="2" fill="#fff"/> <!-- 右眼 --><circle cx="17" cy="12" r="1" fill="#000"/> <!-- 左瞳孔 --><circle cx="25" cy="12" r="1" fill="#000"/> <!-- 右瞳孔 --><path d="M18 18 Q20 20 22 18" stroke="#000" stroke-width="1" fill="none"/> <!-- 微笑 --><circle cx="30" cy="10" r="3" fill="#FFD700"/> <!-- 徽章 --></svg>`,blockStyle: `.optionBlock {background: linear-gradient(to bottom, #90EE90, #228B22);border: 2px solid #006400;border-radius: 8px;box-shadow: 0 4px 8px rgba(0,100,0,0.3);}`,reward: {html: `<div style="width:25px;height:25px;background:linear-gradient(135deg,#7CFC00,#32CD32);border:2px solid #006400;border-radius:50%;box-shadow:0 0 10px #7CFC00;"></div>`,animation: "floatUpSpin"},decorations: `<!-- 树木 --><div style="position:absolute;width:40px;height:60px;bottom:100px;left:100px;background:linear-gradient(to right,#006400 50%,#228B22 50%);border-radius:20px 20px 0 0;box-shadow:5px 5px 10px rgba(0,0,0,0.3);"></div><div style="position:absolute;width:50px;height:70px;bottom:100px;right:120px;background:linear-gradient(to right,#006400 50%,#228B22 50%);border-radius:25px 25px 0 0;box-shadow:5px 5px 10px rgba(0,0,0,0.3);"></div><!-- 太阳 --><div style="position:absolute;width:60px;height:60px;top:15%;right:15%;background:radial-gradient(circle,#FFD700,#FF8C00);border-radius:50%;box-shadow:0 0 30px #FFD700;animation:pulseSun 3s infinite;"></div>`,animations: `@keyframes pulseSun {0%, 100% { box-shadow: 0 0 30px #FFD700; }50% { box-shadow: 0 0 50px #FFD700; }}@keyframes floatUpSpin {0% { transform: translateY(0) rotate(0deg); opacity: 1; }100% { transform: translateY(-150px) rotate(360deg) scale(0.3); opacity: 0; }}`,correctAnim: "scale(1.2) rotate(10deg) translateY(-10px)",wrongAnim: "shake 0.5s ease-out forwards"},goldMiner: {name: "黄金矿工",background: "linear-gradient(to bottom, #8B4513 0%, #A0522D 50%, #654321 100%)",groundStyle: "linear-gradient(to bottom, #5C4033 0%, #2F1C0F 100%); border-top: 5px solid #000;",questionBg: "rgba(139, 69, 19, 0.8)",character: `<svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><circle cx="20" cy="15" r="11" fill="#8B4513"/> <!-- 头盔 --><rect x="12" y="20" width="16" height="14" fill="#A0522D" rx="2"/> <!-- 工作服 --><rect x="14" y="34" width="5" height="4" fill="#000"/> <!-- 左靴 --><rect x="21" y="34" width="5" height="4" fill="#000"/> <!-- 右靴 --><circle cx="17" cy="12" r="1.5" fill="#fff"/> <!-- 左眼 --><circle cx="23" cy="12" r="1.5" fill="#fff"/> <!-- 右眼 --><circle cx="17.5" cy="12" r="0.8" fill="#000"/> <!-- 左瞳孔 --><circle cx="23.5" cy="12" r="0.8" fill="#000"/> <!-- 右瞳孔 --><path d="M18 17 Q20 19 22 17" stroke="#000" stroke-width="1" fill="none"/> <!-- 严肃表情 --><rect x="18" y="8" width="4" height="3" fill="#FFD700"/> <!-- 头灯 --></svg>`,blockStyle: `.optionBlock {background: linear-gradient(to bottom right, #DAA520, #8B4513);border: 2px solid #696969;border-radius: 3px;box-shadow: inset 2px 2px 5px rgba(255,255,255,0.3), 3px 3px 8px rgba(0,0,0,0.5);}`,reward: {html: `<div style="width:30px;height:30px;background:radial-gradient(circle,#FFD700,#B8860B);border:2px solid #DAA520;border-radius:50%;box-shadow:0 0 15px rgba(255,215,0,0.7);animation:glow 1.5s infinite alternate;"></div>`,animation: "floatUp"},decorations: `<!-- 岩石 --><div style="position:absolute;width:50px;height:40px;bottom:120px;left:150px;background:#696969;border-radius:10px;transform:rotate(10deg);box-shadow:5px 5px 15px rgba(0,0,0,0.5);"></div><div style="position:absolute;width:40px;height:50px;bottom:130px;right:160px;background:#696969;border-radius:15px;transform:rotate(-15deg);box-shadow:5px 5px 15px rgba(0,0,0,0.5);"></div><!-- 矿车 --><div style="position:absolute;width:60px;height:30px;bottom:100px;left:50%;transform:translateX(-50%);background:#8B4513;border:2px solid #000;border-radius:5px;animation:shakeCart 2s infinite;box-shadow:0 5px 15px rgba(0,0,0,0.5);"><div style="position:absolute;bottom:-10px;left:10px;width:15px;height:10px;background:#000;border-radius:50%;"></div><div style="position:absolute;bottom:-10px;right:10px;width:15px;height:10px;background:#000;border-radius:50%;"></div></div>`,animations: `@keyframes shakeCart {0%, 100% { transform: translateX(-50%) rotate(0deg); }25% { transform: translateX(-55%) rotate(2deg); }75% { transform: translateX(-45%) rotate(-2deg); }}@keyframes glow {from { box-shadow: 0 0 15px rgba(255,215,0,0.7); }to { box-shadow: 0 0 25px rgba(255,215,0,1); }}`,correctAnim: "scale(1.2) rotate(5deg) translateY(-15px)",wrongAnim: "fallRock 0.5s ease-out forwards"},space: {name: "太空探险",background: "linear-gradient(to bottom, #000033 0%, #000066 100%)",groundStyle: "linear-gradient(to bottom, #4B0082 0%, #2E0854 100%); border-top: 5px solid #000;",questionBg: "rgba(0, 0, 50, 0.8)",character: `<svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><circle cx="20" cy="15" r="12" fill="#C0C0C0"/> <!-- 头盔 --><rect x="10" y="20" width="20" height="15" fill="#696969" rx="2"/> <!-- 太空服 --><rect x="12" y="35" width="6" height="5" fill="#444" rx="1"/> <!-- 左靴 --><rect x="22" y="35" width="6" height="5" fill="#444" rx="1"/> <!-- 右靴 --><circle cx="16" cy="12" r="2" fill="#00BFFF"/> <!-- 左眼罩 --><circle cx="24" cy="12" r="2" fill="#00BFFF"/> <!-- 右眼罩 --><circle cx="16" cy="12" r="1" fill="#fff"/> <!-- 左眼 --><circle cx="24" cy="12" r="1" fill="#fff"/> <!-- 右眼 --><rect x="18" y="18" width="4" height="2" fill="#FF4500" rx="1"/> <!-- 通讯器 --><circle cx="20" cy="5" r="3" fill="#FFD700"/> <!-- 天线 --></svg>`,blockStyle: `.optionBlock {background: linear-gradient(to bottom, #4682B4, #000080);border: 2px solid #0000CD;border-radius: 5px;box-shadow: 0 0 15px rgba(70,130,180,0.5);}`,reward: {html: `<div style="width:25px;height:25px;background:radial-gradient(circle,#00BFFF,#0000CD);border:2px solid #00008B;border-radius:50%;box-shadow:0 0 20px #00BFFF;animation:twinkle 1s infinite;"></div>`,animation: "floatUpBlink"},decorations: `<!-- 星星 --><div style="position:absolute;width:4px;height:4px;top:20%;left:30%;background:white;border-radius:50%;box-shadow:0 0 10px white;animation:twinkleStar 1s infinite;"></div><div style="position:absolute;width:3px;height:3px;top:15%;right:25%;background:white;border-radius:50%;box-shadow:0 0 10px white;animation:twinkleStar 1.5s infinite;"></div><!-- 行星 --><div style="position:absolute;width:50px;height:50px;bottom:150px;left:200px;background:radial-gradient(circle,#FF6347,#8B0000);border-radius:50%;box-shadow:0 0 30px #FF6347;animation:rotatePlanet 10s linear infinite;"></div>`,animations: `@keyframes twinkleStar {0%, 100% { opacity: 0.3; box-shadow: 0 0 5px white; }50% { opacity: 1; box-shadow: 0 0 15px white; }}@keyframes rotatePlanet {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }}@keyframes floatUpBlink {0% { transform: translateY(0); opacity: 0.5; }25% { opacity: 1; }75% { opacity: 1; }100% { transform: translateY(-150px) scale(0.3); opacity: 0; }}`,correctAnim: "scale(1.2) rotate(360deg)",wrongAnim: "explode 0.5s ease-out forwards"},ocean: {name: "深海寻宝",background: "linear-gradient(to bottom, #1E90FF 0%, #00008B 100%)",groundStyle: "linear-gradient(to bottom, #2F4F4F 0%, #000000 100%); border-top: 5px solid #000;",questionBg: "rgba(0, 0, 100, 0.8)",character: `<svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"><circle cx="20" cy="15" r="12" fill="#4169E1"/> <!-- 潜水头盔 --><rect x="10" y="20" width="20" height="15" fill="#1E90FF" rx="2"/> <!-- 潜水服 --><rect x="12" y="35" width="6" height="5" fill="#4B0082" rx="1"/> <!-- 左脚蹼 --><rect x="22" y="35" width="6" height="5" fill="#4B0082" rx="1"/> <!-- 右脚蹼 --><circle cx="16" cy="12" r="2" fill="#fff"/> <!-- 左眼 --><circle cx="24" cy="12" r="2" fill="#fff"/> <!-- 右眼 --><circle cx="17" cy="12" r="1" fill="#000"/> <!-- 左瞳孔 --><circle cx="25" cy="12" r="1" fill="#000"/> <!-- 右瞳孔 --><path d="M18 18 Q20 20 22 18" stroke="#000" stroke-width="1" fill="none"/> <!-- 微笑 --><ellipse cx="30" cy="10" rx="4" ry="2" fill="#FFD700"/> <!-- 氧气表 --></svg>`,blockStyle: `.optionBlock {background: linear-gradient(to bottom, #20B2AA, #008080);border: 2px solid #006400;border-radius: 0 0 10px 10px;box-shadow: 0 5px 15px rgba(0,128,128,0.3);}`,reward: {html: `<div style="width:25px;height:25px;background:radial-gradient(circle,#F0FFFF,#E0FFFF);border:2px solid #AFEEEE;border-radius:50%;box-shadow:0 0 15px #00FFFF;animation:floatBubble 3s infinite;"></div>`,animation: "floatUpBubble"},decorations: `<!-- 珊瑚 --><div style="position:absolute;width:30px;height:50px;bottom:100px;left:120px;background:linear-gradient(to top,#FF6347,#FF4500);border-radius:15px 15px 0 0;box-shadow:0 5px 15px rgba(255,99,71,0.3);"></div><div style="position:absolute;width:40px;height:60px;bottom:100px;right:140px;background:linear-gradient(to top,#FF6347,#FF4500);border-radius:20px 20px 0 0;box-shadow:0 5px 15px rgba(255,99,71,0.3);"></div><!-- 气泡 --><div style="position:absolute;width:20px;height:20px;top:30%;left:40%;background:rgba(255,255,255,0.3);border-radius:50%;animation:riseBubble 3s infinite;"></div><div style="position:absolute;width:15px;height:15px;top:25%;right:35%;background:rgba(255,255,255,0.3);border-radius:50%;animation:riseBubble 2.5s infinite;"></div>`,animations: `@keyframes riseBubble {0% { transform: translateY(0); opacity: 0.3; }50% { transform: translateY(-30px); opacity: 0.8; }100% { transform: translateY(-60px); opacity: 0; }}@keyframes floatUpBubble {0% { transform: translateY(0); opacity: 0.8; }50% { transform: translateY(-80px) scale(1.2); }100% { transform: translateY(-150px) scale(0.3); opacity: 0; }}`,correctAnim: "scale(1.2) translateY(-20px) rotate(10deg)",wrongAnim: "sink 0.5s ease-out forwards"}};// =====================// 📚 题目数据(每题带 theme 字段)// =====================const questions = [{question: "JavaScript中,以下哪个不是原始数据类型?",options: ["Number", "Array", "String", "Boolean"],correct: "B",theme: "mario"},{question: "HTML5中,哪个标签用于定义导航链接?",options: ["nav", "navigation", "navigate", "menu"],correct: "A",theme: "eco"},{question: "CSS中,哪个属性用于设置元素的透明度?",options: ["transparency", "opacity", "visible", "alpha"],correct: "B",theme: "goldMiner"},{question: "在Git中,哪个命令用于查看提交历史?",options: ["git status", "git log", "git history", "git show"],correct: "B",theme: "space"},{question: "React中,哪个Hook用于处理副作用?",options: ["useState", "useReducer", "useEffect", "useContext"],correct: "C",theme: "ocean"},{question: "HTTP状态码404表示什么?",options: ["服务器错误", "未找到", "禁止访问", "请求超时"],correct: "B",theme: "mario"},{question: "Python中,哪个关键字用于定义函数?",options: ["function", "def", "func", "define"],correct: "B",theme: "goldMiner"},{question: "数据库中,SQL的全称是什么?",options: ["Structured Query Language", "Simple Query Language", "Standard Query Language", "System Query Language"],correct: "A",theme: "space"}];// =====================// 🎮 游戏状态// =====================let gameState = {score: 0,rewards: 0,lives: 3,currentQuestion: 0,currentBlockIndex: 0,isJumping: false,isAnswering: false,gameStarted: false,currentTheme: null,awaitingAction: false // 新增:等待用户点击按钮};// 常量const BLOCK_WIDTH = 100;const BLOCK_SPACING = 20;// DOM 元素const character = document.getElementById('character');const questionArea = document.getElementById('questionArea');const questionText = document.getElementById('questionText');const optionsContainer = document.getElementById('optionsContainer');const scoreElement = document.getElementById('score');const rewardsElement = document.getElementById('rewards');const livesElement = document.getElementById('lives');const startScreen = document.getElementById('startScreen');const startBtn = document.getElementById('startBtn');const leftBtn = document.getElementById('leftBtn');const rightBtn = document.getElementById('rightBtn');const jumpBtn = document.getElementById('jumpBtn');const decorationContainer = document.getElementById('decorationContainer');const ground = document.getElementById('ground');// 音效元素const jumpSound = document.getElementById('jumpSound');const correctSound = document.getElementById('correctSound');const wrongSound = document.getElementById('wrongSound');const coinSound = document.getElementById('coinSound');const successSound = document.getElementById('successSound');const failSound = document.getElementById('failSound');// 答案反馈层元素const answerScreen = document.getElementById('answerScreen');const answerTitle = document.getElementById('answerTitle');const answerDetail = document.getElementById('answerDetail');const nextBtn = document.getElementById('nextBtn');const retryBtn = document.getElementById('retryBtn');// =====================// 🔊 音效系统(终极修复版)// =====================function playSound(sound) {if (!sound || !sound.src) {console.warn("音效未加载或无效:", sound);return;}sound.currentTime = 0;const playPromise = sound.play();if (playPromise !== undefined) {playPromise.catch(error => {console.warn("音效播放被浏览器阻止,等待用户交互后重试:", error);const unlockHandler = () => {sound.play().catch(() => {});document.removeEventListener('click', unlockHandler);document.removeEventListener('touchstart', unlockHandler);};document.addEventListener('click', unlockHandler, { once: true });document.addEventListener('touchstart', unlockHandler, { once: true });});}}// 预加载并解锁音频上下文function unlockAudioContext() {const audioContext = new (window.AudioContext || window.webkitAudioContext)();audioContext.resume().then(() => {console.log("🎮 音频上下文已解锁");}).catch(e => {console.warn("音频上下文解锁失败:", e);});const sounds = [jumpSound, correctSound, wrongSound, coinSound, successSound, failSound];sounds.forEach(sound => {if (sound) {sound.volume = 0;sound.play().then(() => {sound.pause();sound.currentTime = 0;sound.volume = 1;}).catch(() => {});}});}document.addEventListener('DOMContentLoaded', () => {document.addEventListener('click', unlockAudioContext, { once: true });document.addEventListener('touchstart', unlockAudioContext, { once: true });});// =====================// 🎨 主题应用函数(彻底换装)// =====================function applyTheme(themeKey) {const theme = themes[themeKey];if (!theme) return;document.body.style.background = theme.background;ground.style.cssText = theme.groundStyle;questionArea.style.background = theme.questionBg;character.innerHTML = theme.character;decorationContainer.innerHTML = theme.decorations || '';const existingStyle = document.getElementById('theme-block-style');if (existingStyle) existingStyle.remove();const blockStyle = document.createElement('style');blockStyle.id = 'theme-block-style';blockStyle.textContent = theme.blockStyle;document.head.appendChild(blockStyle);const existingAnimations = document.getElementById('theme-animations');if (existingAnimations) existingAnimations.remove();if (theme.animations) {const animStyle = document.createElement('style');animStyle.id = 'theme-animations';animStyle.textContent = theme.animations;document.head.appendChild(animStyle);}gameState.currentTheme = themeKey;character.style.transform = 'translateY(0)';character.classList.remove('die');}// =====================// 🎮 游戏逻辑// =====================function initGame() {startScreen.style.display = 'none';gameState = {score: 0,rewards: 0,lives: 3,currentQuestion: 0,currentBlockIndex: 0,isJumping: false,isAnswering: false,gameStarted: true,currentTheme: null,awaitingAction: false};updateHUD();loadQuestion();moveToBlock(0);playSound(jumpSound); // 播放开始音效}function loadQuestion() {if (gameState.currentQuestion >= questions.length) {playSound(successSound);endGame(true);return;}const q = questions[gameState.currentQuestion];if (q.theme) {applyTheme(q.theme);}questionText.textContent = q.question;optionsContainer.innerHTML = '';q.options.forEach((opt, i) => {const block = document.createElement('div');block.className = 'optionBlock';block.innerHTML = `<div class="label">${String.fromCharCode(65 + i)}</div><div class="text">${opt}</div>`;optionsContainer.appendChild(block);});gameState.isAnswering = true;answerScreen.style.display = 'none'; // 隐藏答案层}function moveToBlock(index) {if (index < 0 || index > 3 || gameState.isJumping || gameState.awaitingAction) return;gameState.currentBlockIndex = index;const centerX = getBlockCenterX(index);character.style.left = (centerX - 20) + 'px';}function getBlockCenterX(index) {const containerWidth = 4 * BLOCK_WIDTH + 3 * BLOCK_SPACING;const startX = (window.innerWidth - containerWidth) / 2;return startX + index * (BLOCK_WIDTH + BLOCK_SPACING) + BLOCK_WIDTH / 2;}function jump() {if (!gameState.gameStarted || gameState.isJumping || !gameState.isAnswering || gameState.awaitingAction) return;gameState.isJumping = true;character.classList.add('jump');playSound(jumpSound);setTimeout(() => {checkAnswer();}, 400);setTimeout(() => {character.classList.remove('jump');gameState.isJumping = false;}, 800);}function checkAnswer() {const currentIndex = gameState.currentBlockIndex;const selectedOption = String.fromCharCode(65 + currentIndex);const currentQ = questions[gameState.currentQuestion];const blocks = document.querySelectorAll('.optionBlock');const selectedBlock = blocks[currentIndex];if (selectedOption === currentQ.correct) {const theme = themes[gameState.currentTheme];selectedBlock.style.animation = `0.6s ease-out forwards`;selectedBlock.style.transform = theme.correctAnim;gameState.score += 100;gameState.rewards += 1;updateHUD();const rect = selectedBlock.getBoundingClientRect();spawnThemeReward(rect.left + rect.width/2, rect.top);playSound(correctSound);playSound(coinSound);showAnswerScreen(true,`✓ 正确!`,`${selectedOption} - ${currentQ.options[currentIndex]}`);} else {const theme = themes[gameState.currentTheme];selectedBlock.style.animation = `0.5s ease-out forwards`;selectedBlock.style.transform = theme.wrongAnim;selectedBlock.style.opacity = '0.2';gameState.lives -= 1;updateHUD();playSound(wrongSound);showAnswerScreen(false,`✗ 答错了!`,`正确答案:${currentQ.correct} - ${currentQ.options[getCorrectIndex(currentQ)]}`);character.classList.add('die');if (gameState.lives <= 0) {setTimeout(() => {playSound(failSound);endGame(false);}, 1000);return;}retryBtn.style.display = 'inline-block';}gameState.awaitingAction = true;gameState.isAnswering = false;}// 显示答案反馈层function showAnswerScreen(isCorrect, title, detail) {answerTitle.textContent = title;answerTitle.style.color = isCorrect ? '#00FF00' : '#FF0000';answerDetail.textContent = detail;retryBtn.style.display = isCorrect ? 'none' : 'inline-block';answerScreen.style.display = 'flex';}function spawnThemeReward(x, y) {const theme = themes[gameState.currentTheme];const reward = document.createElement('div');reward.className = 'reward';reward.style.left = (x - 15) + 'px';reward.style.top = (y - 15) + 'px';reward.innerHTML = theme.reward.html;reward.style.animationName = theme.reward.animation;document.getElementById('gameContainer').appendChild(reward);setTimeout(() => {if (reward.parentNode) {reward.remove();}}, 1500);}function getCorrectIndex(q) {return q.correct.charCodeAt(0) - 65;}// 下一题function nextQuestion() {if (gameState.lives <= 0) {playSound(failSound);endGame(false);return;}gameState.awaitingAction = false;character.classList.remove('die');gameState.currentQuestion++;loadQuestion();moveToBlock(0);}// 重试当前题function retryQuestion() {gameState.awaitingAction = false;character.classList.remove('die');loadQuestion();moveToBlock(0);}function updateHUD() {scoreElement.textContent = gameState.score;rewardsElement.textContent = gameState.rewards;livesElement.textContent = '❤️'.repeat(gameState.lives);}function endGame(isWin) {gameState.gameStarted = false;const existing = document.querySelector('.endScreen');if (existing) existing.remove();const endScreen = document.createElement('div');endScreen.className = 'endScreen';endScreen.innerHTML = `<h1>${isWin ? '🎉 终极冒险大师!' : '💀 冒险结束'}</h1><div class="stats">最终得分: ${gameState.score}<br>收集物品: ${gameState.rewards}<br>${isWin ? '你征服了所有世界!' : `你坚持到了第 ${gameState.currentQuestion + 1} 题!`}</div><button class="startBtn" onclick="location.reload()">重新开始</button>`;document.body.appendChild(endScreen);}// =====================// 🖱️ 事件绑定// =====================startBtn.addEventListener('click', initGame);leftBtn.addEventListener('click', () => {moveToBlock(gameState.currentBlockIndex - 1);});rightBtn.addEventListener('click', () => {moveToBlock(gameState.currentBlockIndex + 1);});jumpBtn.addEventListener('click', jump);// 绑定答案层按钮nextBtn.addEventListener('click', nextQuestion);retryBtn.addEventListener('click', retryQuestion);document.addEventListener('keydown', (e) => {if (!gameState.gameStarted) return;if (gameState.awaitingAction) {if (e.key === 'Enter' || e.key === ' ') {if (gameState.lives > 0 && retryBtn.style.display !== 'none') {retryQuestion();} else {nextQuestion();}}return;}switch(e.key) {case 'ArrowLeft':case 'a':case 'A':moveToBlock(gameState.currentBlockIndex - 1);break;case 'ArrowRight':case 'd':case 'D':moveToBlock(gameState.currentBlockIndex + 1);break;case 'ArrowUp':case ' ':case 'w':case 'W':jump();break;}});// 初始化 HUDupdateHUD();// 控制台署名console.log(`
🎮 终极主题答题冒险 - 开源项目
音效来源: Kenney.nl (公有领域)
许可证: MIT
`);</script>
</body>
</html>

在线体验: https://share.htmlput.com/p/73mhzve0a0?lang=zh

快去修改题库,打造属于你自己的知识冒险世界吧!

http://www.dtcms.com/a/393290.html

相关文章:

  • 实验1.2呼吸灯实验指导书
  • 实验1.3通过for循环精确定时呼吸灯
  • 【c++】多态(一)
  • 01、Python从入门到癫狂:基础
  • uniapp 弹窗
  • 17.2 《16小时→2.3小时!多模态AI颠覆PPT制作:跨国企业实战验证》
  • MyBatis 从入门到实战:环境搭建与核心原理详解
  • 深入剖析陌讯AIGC检测算法:Transformer架构在AIGC识别中的技术创新
  • 【Ai智能客服上篇】
  • 《C++程序设计》笔记p3
  • 华为数字化转型战略框架:从“1套方法+4类场景+3个平台”的全景设计
  • Redis:主从复制与哨兵模式解析
  • 【中压选型篇】中压电源进线与变压器选型全指南:从拓扑设计到并联运行
  • 【精品资料鉴赏】数据治理咨询项目实施方案
  • 基于陌讯AIGC检测算法的局限性探讨:最大512Token输入下的长文本处理方案
  • 应用随机过程(三)
  • A/B测试:随机化与观察单位不一致,如何处理更科学
  • 树拍易购商业模式解析:创新与合规并行的数实融合样本
  • 使用递归求阶乘的和
  • HTML 结构与常用标签
  • AI 智能体开发工作流从哪些方面入手?
  • USBL与DVL数据融合的实时定位系统,MATLAB仿真
  • 端到端与世界模型(1):自动驾驶的基础模型从 VLM 到 VLA
  • Let’s Encrypt 免费SSL证书一键获取 - 网页版极简教程
  • IDEA指定配置文件启动
  • Python实现基于教学的优化器 (Teaching-Learning-Based Optimization, TLBO) (附完整代码)
  • 视频图像数据档案管理
  • 灰狼优化算法GWO
  • 2025csp入门组真题和解析
  • Keil-MDK程序运行和下载过程