JavaScript案例(乘法答题游戏)

项目概述

使用原生JavaScript实现一个乘法答题游戏,随机生成乘法题目,判断答案正误并记录分数,通过localStorage实现分数持久化存储。

核心功能需求

  1. 随机题目生成:动态生成1-10之间的乘法题
  2. 答题交互:输入答案并提交,支持回车提交
  3. 正误判定:判断答案正确性并给出视觉反馈
  4. 积分系统:答对加分,记录当前分数和历史最高分
  5. 分数持久化:使用localStorage保存分数数据
  6. 游戏控制:支持重新开始游戏

技术栈

  • HTML5:页面结构
  • CSS3:样式设计,包括答题状态反馈
  • JavaScript:题目生成、答案验证、分数管理、本地存储
  • 本地存储:localStorage API

项目结构

复制代码
multiplication-game/
├── index.html      # 游戏主页面
├── css/
│   └── style.css   # 样式文件
├── js/
    └── game.js     # 游戏核心逻辑

实现思路

1. 数据结构设计

javascript 复制代码
// 游戏状态对象
const gameState = {
  currentScore: 0,       // 当前分数
  highScore: 0,          // 历史最高分
  num1: 0,               // 第一个乘数
  num2: 0,               // 第二个乘数
  currentAnswer: 0,      // 当前题目正确答案
  streak: 0,             // 连续答对次数
  maxStreak: 0           // 最大连续答对次数
};

2. 核心功能模块

  • 题目生成模块:使用Math.random()生成随机乘数
  • 答案验证模块:比较用户输入与正确答案
  • 分数管理模块:更新分数、记录最高分
  • 本地存储模块:保存和读取分数数据
  • UI交互模块:更新界面、反馈答题结果

3. 关键技术点实现

  • 随机数生成Math.floor(Math.random() * 10) + 1生成1-10的随机数
  • 本地存储localStorage.setItem()localStorage.getItem()实现数据持久化
  • 事件处理:监听表单提交和键盘事件
  • 状态反馈:通过CSS类切换实现正确/错误状态样式

代码:

  • index.html
html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>乘法答题游戏 | Math Multiplication Game</title>
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
    <div class="game-container">
        <header>
            <h1>乘法答题挑战 <i class="fas fa-calculator"></i></h1>
            <p>测试你的乘法计算能力,挑战最高分!</p>
        </header>
        
        <div class="score-board">
            <div class="score-item">
                <span class="label">当前分数</span>
                <span id="currentScore" class="score">0</span>
            </div>
            <div class="score-item">
                <span class="label">历史最高分</span>
                <span id="highScore" class="score">0</span>
            </div>
        </div>
        
        <div class="game-card">
            <div class="problem">
                <span id="num1">?</span>
                <span class="operator">×</span>
                <span id="num2">?</span>
                <span class="equal">=</span>
                <form id="answerForm">
                    <input type="number" id="answerInput" placeholder="输入答案" autocomplete="off" required>
                    <button type="submit" id="submitBtn">提交 <i class="fas fa-paper-plane"></i></button>
                </form>
            </div>
            
            <div id="feedback" class="feedback hidden"></div>
            
            <div class="controls">
                <button id="restartBtn"><i class="fas fa-sync-alt"></i> 重新开始</button>
            </div>
        </div>
        
        <div class="game-stats">
            <div class="stat-item">
                <i class="fas fa-fire"></i>
                <span>当前连击: <span id="currentStreak">0</span></span>
            </div>
            <div class="stat-item">
                <i class="fas fa-trophy"></i>
                <span>最大连击: <span id="maxStreak">0</span></span>
            </div>
        </div>
    </div>

    <script src="js/game.js"></script>
</body>
</html>
  • style.css
css 复制代码
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

body {
    background-color: #f0f4f8;
    color: #333;
    line-height: 1.6;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
}

.game-container {
    width: 100%;
    max-width: 600px;
    margin: 0 auto;
}

header {
    text-align: center;
    margin-bottom: 30px;
}

header h1 {
    font-size: 2.2rem;
    color: #2c3e50;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 15px;
}

header p {
    color: #7f8c8d;
    font-size: 1.1rem;
}

/* 分数面板 */
.score-board {
    display: flex;
    justify-content: space-around;
    margin-bottom: 25px;
    background-color: white;
    border-radius: 12px;
    padding: 15px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}

.score-item {
    text-align: center;
}

.label {
    display: block;
    font-size: 0.9rem;
    color: #7f8c8d;
    margin-bottom: 5px;
}

.score {
    font-size: 1.8rem;
    font-weight: bold;
    color: #2c3e50;
}

/* 游戏卡片 */
.game-card {
    background-color: white;
    border-radius: 15px;
    padding: 30px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.08);
    margin-bottom: 25px;
}

/* 题目区域 */
.problem {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 15px;
    margin-bottom: 25px;
}

.problem span {
    font-size: 2.5rem;
    font-weight: bold;
    color: #2c3e50;
}

.operator, .equal {
    color: #7f8c8d;
}

#answerForm {
    display: flex;
    gap: 10px;
    flex: 0 0 180px;
}

#answerInput {
    width: 100%;
    padding: 12px 15px;
    border: 2px solid #ddd;
    border-radius: 8px;
    font-size: 1.2rem;
    text-align: center;
    transition: all 0.3s ease;
}

#answerInput:focus {
    outline: none;
    border-color: #3498db;
    box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}

#submitBtn {
    padding: 12px 20px;
    background-color: #3498db;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 1rem;
    transition: background-color 0.3s ease;
    display: flex;
    align-items: center;
    gap: 8px;
}

#submitBtn:hover {
    background-color: #2980b9;
}

/* 反馈区域 */
.feedback {
    padding: 15px;
    border-radius: 8px;
    text-align: center;
    font-size: 1.1rem;
    margin-bottom: 20px;
    transition: all 0.3s ease;
}

.correct {
    background-color: rgba(46, 204, 113, 0.1);
    color: #27ae60;
    border: 1px solid #2ecc71;
}

.incorrect {
    background-color: rgba(231, 76, 60, 0.1);
    color: #e74c3c;
    border: 1px solid #e74c3c;
}

.hidden {
    display: none;
}

/* 控制按钮 */
.controls {
    text-align: center;
}

#restartBtn {
    padding: 10px 20px;
    background-color: #95a5a6;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 1rem;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    gap: 8px;
    justify-content: center;
}

#restartBtn:hover {
    background-color: #7f8c8d;
}

/* 游戏统计 */
.game-stats {
    display: flex;
    justify-content: space-around;
    background-color: white;
    border-radius: 12px;
    padding: 15px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.05);
}

.stat-item {
    display: flex;
    align-items: center;
    gap: 8px;
    color: #7f8c8d;
    font-size: 0.95rem;
}

.stat-item i {
    color: #f39c12;
}

.stat-item span {
    font-weight: 500;
}

/* 响应式设计 */
@media (max-width: 500px) {
    .problem {
        flex-direction: column;
        gap: 10px;
    }
    
    .problem span {
        font-size: 2rem;
    }
    
    #answerForm {
        flex: 0 0 100%;
    }
    
    .score-board {
        flex-direction: column;
        gap: 15px;
    }
    
    .game-stats {
        flex-direction: column;
        gap: 10px;
        text-align: center;
    }
    
    .stat-item {
        justify-content: center;
    }
}
  • game.js
js 复制代码
const gameState = {
  currentScore: 0,
  highScore: 0,
  num1: 0,
  num2: 0,
  currentAnswer: 0,
  streak: 0,
  maxStreak: 0
};

// DOM元素
const num1El = document.getElementById('num1');
const num2El = document.getElementById('num2');
const answerInput = document.getElementById('answerInput');
const answerForm = document.getElementById('answerForm');
const feedbackEl = document.getElementById('feedback');
const currentScoreEl = document.getElementById('currentScore');
const highScoreEl = document.getElementById('highScore');
const restartBtn = document.getElementById('restartBtn');
const currentStreakEl = document.getElementById('currentStreak');
const maxStreakEl = document.getElementById('maxStreak');

// 初始化游戏
function initGame() {
  // 从本地存储加载分数
  loadScores();
  
  // 生成第一题
  generateProblem();
  
  // 绑定事件监听器
  bindEvents();
  
  // 更新UI显示
  updateStats();
}

// 从本地存储加载分数
function loadScores() {
  const savedScores = localStorage.getItem('multiplicationGameScores');
  if (savedScores) {
    const scores = JSON.parse(savedScores);
    gameState.highScore = scores.highScore || 0;
    gameState.maxStreak = scores.maxStreak || 0;
  }
}

// 保存分数到本地存储
function saveScores() {
  const scoresToSave = {
    highScore: gameState.highScore,
    maxStreak: gameState.maxStreak
  };
  localStorage.setItem('multiplicationGameScores', JSON.stringify(scoresToSave));
}

// 生成新题目
function generateProblem() {
  // 生成1-10之间的随机数
  gameState.num1 = Math.floor(Math.random() * 10) + 1;
  gameState.num2 = Math.floor(Math.random() * 10) + 1;
  gameState.currentAnswer = gameState.num1 * gameState.num2;
  
  // 更新UI显示题目
  num1El.textContent = gameState.num1;
  num2El.textContent = gameState.num2;
  
  // 清空输入框并聚焦
  answerInput.value = '';
  answerInput.focus();
  
  // 隐藏反馈
  feedbackEl.classList.add('hidden');
}

// 检查答案
function checkAnswer(userAnswer) {
  const isCorrect = userAnswer === gameState.currentAnswer;
  
  // 显示反馈
  showFeedback(isCorrect);
  
  if (isCorrect) {
    // 答对处理
    handleCorrectAnswer();
  } else {
    // 答错处理
    handleWrongAnswer();
  }
  
  // 短暂延迟后生成新题目
  setTimeout(generateProblem, 1500);
}

// 显示答题反馈
function showFeedback(isCorrect) {
  feedbackEl.classList.remove('hidden', 'correct', 'incorrect');
  
  if (isCorrect) {
    feedbackEl.classList.add('correct');
    feedbackEl.innerHTML = `<i class="fas fa-check-circle"></i> 正确!答案是 ${gameState.currentAnswer}`;
  } else {
    feedbackEl.classList.add('incorrect');
    feedbackEl.innerHTML = `<i class="fas fa-times-circle"></i> 错误,正确答案是 ${gameState.currentAnswer}`;
  }
}

// 处理正确答案
function handleCorrectAnswer() {
  // 增加分数
  gameState.currentScore += 10;
  
  // 增加连击数
  gameState.streak++;
  
  // 更新最大连击数
  if (gameState.streak > gameState.maxStreak) {
    gameState.maxStreak = gameState.streak;
  }
  
  // 检查是否打破最高分记录
  if (gameState.currentScore > gameState.highScore) {
    gameState.highScore = gameState.currentScore;
  }
  
  // 保存分数
  saveScores();
  
  // 更新UI
  updateStats();
  
  // 添加答题正确动画效果
  document.querySelector('.game-card').classList.add('correct-animation');
  setTimeout(() => {
    document.querySelector('.game-card').classList.remove('correct-animation');
  }, 500);
}

// 处理错误答案
function handleWrongAnswer() {
  // 重置连击数
  gameState.streak = 0;
  
  // 更新UI
  updateStats();
  
  // 添加答题错误动画效果
  document.querySelector('.game-card').classList.add('wrong-animation');
  setTimeout(() => {
    document.querySelector('.game-card').classList.remove('wrong-animation');
  }, 500);
}

// 更新游戏统计信息UI
function updateStats() {
  currentScoreEl.textContent = gameState.currentScore;
  highScoreEl.textContent = gameState.highScore;
  currentStreakEl.textContent = gameState.streak;
  maxStreakEl.textContent = gameState.maxStreak;
}

// 重置游戏
function resetGame() {
  // 重置当前分数和连击
  gameState.currentScore = 0;
  gameState.streak = 0;
  
  // 更新UI
  updateStats();
  
  // 生成新题目
  generateProblem();
  
  // 显示重置反馈
  feedbackEl.classList.remove('hidden', 'correct', 'incorrect');
  feedbackEl.innerHTML = '<i class="fas fa-gamepad"></i> 游戏已重置,开始新挑战吧!';
}

// 绑定事件监听器
function bindEvents() {
  // 答案提交表单
  answerForm.addEventListener('submit', (e) => {
    e.preventDefault();
    const userAnswer = parseInt(answerInput.value, 10);
    
    if (!isNaN(userAnswer)) {
      checkAnswer(userAnswer);
    }
  });
  
  // 重新开始按钮
  restartBtn.addEventListener('click', resetGame);
  
  // 添加键盘事件支持
  answerInput.addEventListener('focus', () => {
    answerInput.select();
  });
}

// 添加CSS动画样式
const style = document.createElement('style');
style.textContent = `
  .correct-animation {
    animation: correctPulse 0.5s ease-in-out;
  }
  
  .wrong-animation {
    animation: wrongShake 0.5s ease-in-out;
  }
  
  @keyframes correctPulse {
    0% { box-shadow: 0 6px 20px rgba(0,0,0,0.08); }
    50% { box-shadow: 0 6px 20px rgba(46, 204, 113, 0.3); }
    100% { box-shadow: 0 6px 20px rgba(0,0,0,0.08); }
  }
  
  @keyframes wrongShake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-10px); }
    50% { transform: translateX(10px); }
    75% { transform: translateX(-10px); }
  }
`;
document.head.appendChild(style);

// 初始化游戏
document.addEventListener('DOMContentLoaded', initGame);

效果展示:

相关推荐
枫叶梨花22 分钟前
使用Go语言获取Windows系统信息:从CPU到电池的全维度监控
开发语言·windows·golang
C_Liu_26 分钟前
从C语言到C++:拥抱面向对象编程的全新世界
c语言·开发语言·c++
哈基咩29 分钟前
Go 语言模糊测试 (Fuzz Testing) 深度解析与实践
开发语言·后端·golang
元气少女小圆丶31 分钟前
Mirror学习笔记
java·开发语言·学习
lly20240633 分钟前
Perl 面向对象编程深入解析
开发语言
谷宇.35 分钟前
【Unity3D实例-功能-镜头】第三人称视觉
游戏·unity·unity3d·游戏开发·游戏编程·steam
瓦特what?38 分钟前
C + +
c语言·开发语言·c++·经验分享·笔记·算法·程序员创富
@十八子德月生39 分钟前
第三阶段—8天Python从入门到精通【itheima】-143节(pyspark实战——数据计算——flatmap方法)
大数据·开发语言·python·数据分析·pyspark·好好学习,天天向上·question answer
沐知全栈开发1 小时前
C# 运算符重载
开发语言
前端开发爱好者1 小时前
尤雨溪官宣:Vite 历史性的一刻!超越 Webpack!
前端·javascript·vite