吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4383|回复: 73
收起左侧

[其他原创] HTML打字练习

  [复制链接]
zhengzhenhui945 发表于 2025-5-15 03:33
起因是这样的,招聘了一名妹子说是之前做过文员,入职第三天,
偶然发现工作时单指敲击键盘,打字效率低客户都跑了。。。
后面给开了三天工资让离职了。
不得已制定针对性的打字技能测试流程,来筛查员工的实际打字水平。

========================================
字母以及数字练习
360截图20250515032458611.jpg

汉字输入练习
360截图20250515032812763.jpg

[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小学生打字练习</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#4B5563', // 主色调:深灰色
                        secondary: '#EC4899', // 辅助色:粉色
                        accent: '#10B981', // 强调色:绿色
                        dark: '#1F2937', // 深色背景
                        light: '#F9FAFB', // 浅色文本
                        neutral: '#6B7280', // 中性色
                    },
                    fontFamily: {
                        game: ['Comic Sans MS', 'KaiTi', 'sans-serif'],
                    },
                    animation: {
                        'fall': 'fall 3s linear forwards',
                        'bounce-in': 'bounceIn 0.5s ease-out',
                        'fade-out': 'fadeOut 0.3s ease-in forwards',
                        'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
                    },
                    keyframes: {
                        fall: {
                            '0%': { transform: 'translateY(-50px)' },
                            '100%': { transform: 'translateY(550px)' },
                        },
                        bounceIn: {
                            '0%': { transform: 'scale(0)', opacity: '0' },
                            '60%': { transform: 'scale(1.1)', opacity: '1' },
                            '100%': { transform: 'scale(1)' },
                        },
                        fadeOut: {
                            '0%': { transform: 'scale(1)', opacity: '1' },
                            '100%': { transform: 'scale(1.5)', opacity: '0' },
                        }
                    }
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        [url=home.php?mod=space&uid=1688376]@layer[/url] utilities {
            .content-auto {
                content-visibility: auto;
            }
            .text-shadow {
                text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
            }
            .glass-effect {
                backdrop-filter: blur(10px);
                background-color: rgba(31, 41, 55, 0.7);
            }
            .btn-hover {
                transition: all 0.3s ease;
            }
            .btn-hover:hover {
                transform: translateY(-3px);
                box-shadow: 0 10px 25px -5px rgba(75, 85, 99, 0.4);
            }
            .btn-active {
                transform: translateY(1px);
            }
            .stat-card {
                transition: all 0.3s ease;
            }
            .stat-card:hover {
                transform: translateY(-5px);
                box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
            }
            .letter {
                transition: all 0.2s ease;
            }
            .letter:hover {
                transform: scale(1.1);
                box-shadow: 0 0 15px rgba(75, 85, 99, 0.6);
            }
            .particle {
                position: absolute;
                border-radius: 50%;
                pointer-events: none;
                z-index: 10;
                opacity: 1;
                transition: all 0.5s cubic-bezier(0.1, 0.8, 0.2, 1);
            }
        }
    </style>
</head>
<body class="bg-gradient-to-br from-dark to-primary min-h-screen flex flex-col items-center justify-start p-4 font-game text-light">
    <!-- 页面头部 - 仅保留空的header标签 -->
    <header class="w-full max-w-4xl text-center mb-6 mt-4"></header>

    <!-- 主游戏区域 -->
    <main class="w-full max-w-4xl flex flex-col items-center">
        <!-- 游戏画布 -->
        <div id="gameContainer" class="w-full h-[500px] bg-dark/80 rounded-2xl border-2 border-primary/30 shadow-2xl shadow-primary/20 relative overflow-hidden mb-6">
            <!-- 字母将在这里动态生成 -->
        </div>

        <!-- 统计信息 -->
        <div class="grid grid-cols-2 md:grid-cols-4 gap-4 w-full mb-6">
            <div id="score" class="stat-card bg-dark/70 rounded-xl p-4 shadow-lg border border-primary/20">
                <div class="text-light/60 text-sm mb-1">得分</div>
                <div class="text-3xl font-bold text-secondary">0</div>
            </div>
            <div id="correct" class="stat-card bg-dark/70 rounded-xl p-4 shadow-lg border border-primary/20">
                <div class="text-light/60 text-sm mb-1">正确</div>
                <div class="text-3xl font-bold text-accent">0</div>
            </div>
            <div id="wrong" class="stat-card bg-dark/70 rounded-xl p-4 shadow-lg border border-primary/20">
                <div class="text-light/60 text-sm mb-1">错误</div>
                <div class="text-3xl font-bold text-red-500">0</div>
            </div>
            <div id="accuracy" class="stat-card bg-dark/70 rounded-xl p-4 shadow-lg border border-primary/20">
                <div class="text-light/60 text-sm mb-1">准确率</div>
                <div class="text-3xl font-bold text-blue-400">100%</div>
            </div>
        </div>

        <!-- 控制面板 - 优化为单行布局 -->
        <div class="glass-effect w-full p-4 rounded-xl shadow-lg border border-primary/20 mb-6">
            <div class="flex flex-col md:flex-row gap-4 items-center justify-between">
                <!-- 游戏模式选择 - 减小宽度 -->
                <div class="w-full md:w-auto md:min-w-[160px]">
                    <select id="gameMode" class="w-full bg-dark/60 text-light border border-primary/30 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-secondary">
                        <option value="letters">字母模式 (A-Z)</option>
                        <option value="numbers">数字模式 (0-9 +.-*/)</option>
                    </select>
                </div>
                
                <!-- 游戏控制按钮 - 增大按钮尺寸 -->
                <div class="flex gap-2 w-full md:w-auto justify-center md:justify-start">
                    <button id="startBtn" class="btn-hover bg-primary hover:bg-primary/90 text-white font-bold py-2.5 px-6 rounded-full shadow-lg focus:outline-none focus:ring-2 focus:ring-primary/50 text-base">
                        <i class="fa fa-play mr-1"></i>开始
                    </button>
                    <button id="pauseBtn" class="btn-hover bg-neutral hover:bg-neutral/80 text-white font-bold py-2.5 px-6 rounded-full shadow-lg focus:outline-none focus:ring-2 focus:ring-neutral/50 text-base" disabled>
                        <i class="fa fa-pause mr-1"></i>暂停
                    </button>
                    <button id="resetBtn" class="btn-hover bg-neutral hover:bg-neutral/80 text-white font-bold py-2.5 px-6 rounded-full shadow-lg focus:outline-none focus:ring-2 focus:ring-neutral/50 text-base" disabled>
                        <i class="fa fa-refresh mr-1"></i>重置
                    </button>
                </div>
                
                <!-- 游戏速度控制 -->
                <div class="w-full md:w-auto flex items-center gap-2 min-w-[180px]">
                    <label for="speedSlider" class="text-light font-medium whitespace-nowrap">游戏速度:</label>
                    <input type="range" id="speedSlider" min="1" max="10" value="3" 
                           class="w-full h-2 bg-neutral rounded-lg appearance-none cursor-pointer">
                    <span id="speedValue" class="text-accent font-bold min-w-[30px] text-center">3</span>
                </div>
            </div>
        </div>

        <button id="highScoresBtn" class="btn-hover bg-secondary hover:bg-secondary/90 text-white font-bold py-3 px-8 rounded-full shadow-lg focus:outline-none focus:ring-2 focus:ring-secondary/50 mb-8">
            <i class="fa fa-trophy mr-2"></i>查看最高分
        </button>
    </main>

    <!-- 最高分模态框 -->
    <div id="highScoresModal" class="fixed inset-0 bg-dark/90 flex items-center justify-center z-50 hidden">
        <div class="glass-effect w-full max-w-2xl rounded-2xl shadow-2xl overflow-hidden transform transition-all">
            <div class="flex justify-between items-center bg-primary/20 p-4">
                <h2 class="text-2xl font-bold text-light">&#127942; 最高分记录 &#127942;</h2>
                <button id="closeModal" class="text-light hover:text-secondary text-2xl transition-colors">
                    <i class="fa fa-times"></i>
                </button>
            </div>
            <div class="p-6 max-h-[70vh] overflow-y-auto">
                <div class="overflow-x-auto">
                    <table class="w-full text-left">
                        <thead>
                            <tr class="bg-primary/10 text-light">
                                <th class="py-3 px-4 rounded-tl-lg">排名</th>
                                <th class="py-3 px-4">得分</th>
                                <th class="py-3 px-4">正确数</th>
                                <th class="py-3 px-4">准确率</th>
                                <th class="py-3 px-4 rounded-tr-lg">日期</th>
                                <th class="py-3 px-4">模式</th>
                            </tr>
                        </thead>
                        <tbody id="highScoresBody">
                            <!-- 分数记录将在这里动态添加 -->
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

    <!-- 游戏结束模态框 -->
    <div id="gameOverModal" class="fixed inset-0 bg-dark/90 flex items-center justify-center z-50 hidden">
        <div class="glass-effect w-full max-w-md rounded-2xl shadow-2xl overflow-hidden transform transition-all animate-bounce-in">
            <div class="bg-secondary/20 p-6 text-center">
                <h2 class="text-3xl font-bold text-secondary mb-2">游戏结束!</h2>
                <p class="text-xl text-light/80">你的得分: <span id="gameOverScore" class="text-secondary font-bold">0</span></p>
                <div class="grid grid-cols-2 gap-4 mt-4 mb-6">
                    <div class="bg-dark/50 p-3 rounded-lg">
                        <div class="text-light/60 text-sm">正确</div>
                        <div id="gameOverCorrect" class="text-xl font-bold text-accent">0</div>
                    </div>
                    <div class="bg-dark/50 p-3 rounded-lg">
                        <div class="text-light/60 text-sm">错误</div>
                        <div id="gameOverWrong" class="text-xl font-bold text-red-500">0</div>
                    </div>
                    <div class="bg-dark/50 p-3 rounded-lg">
                        <div class="text-light/60 text-sm">准确率</div>
                        <div id="gameOverAccuracy" class="text-xl font-bold text-blue-400">100%</div>
                    </div>
                    <div class="bg-dark/50 p-3 rounded-lg">
                        <div class="text-light/60 text-sm">模式</div>
                        <div id="gameOverMode" class="text-xl font-bold text-blue-400">字母模式</div>
                    </div>
                </div>
                <button id="closeGameOverModal" class="btn-hover bg-accent hover:bg-accent/90 text-white font-bold py-3 px-8 rounded-full shadow-lg">
                    确定
                </button>
            </div>
        </div>
    </div>

    <script>
        // 游戏变量
        let gameActive = false;
        let gamePaused = false;
        let score = 0;
        let correctCount = 0;
        let wrongCount = 0;
        let letters = [];
        let letterSpeed = 3; // 默认速度
        let gameMode = 'letters'; // 默认模式:字母
        let letterInterval;
        let animationFrame;
        let gameContainer = document.getElementById('gameContainer');
        let scoreElement = document.getElementById('score').querySelector('div:last-child');
        let correctElement = document.getElementById('correct').querySelector('div:last-child');
        let wrongElement = document.getElementById('wrong').querySelector('div:last-child');
        let accuracyElement = document.getElementById('accuracy').querySelector('div:last-child');
        let startBtn = document.getElementById('startBtn');
        let pauseBtn = document.getElementById('pauseBtn');
        let resetBtn = document.getElementById('resetBtn');
        let highScoresBtn = document.getElementById('highScoresBtn');
        let speedSlider = document.getElementById('speedSlider');
        let speedValue = document.getElementById('speedValue');
        let highScoresModal = document.getElementById('highScoresModal');
        let closeModal = document.getElementById('closeModal');
        let highScoresBody = document.getElementById('highScoresBody');
        let gameOverModal = document.getElementById('gameOverModal');
        let closeGameOverModal = document.getElementById('closeGameOverModal');
        let gameOverScore = document.getElementById('gameOverScore');
        let gameOverCorrect = document.getElementById('gameOverCorrect');
        let gameOverWrong = document.getElementById('gameOverWrong');
        let gameOverAccuracy = document.getElementById('gameOverAccuracy');
        let gameModeSelect = document.getElementById('gameMode');
        let gameOverMode = document.getElementById('gameOverMode');

        // 字母颜色数组
        const letterColors = [
            '#4B5563', '#EC4899', '#10B981', '#3B82F6', 
            '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899',
            '#14B8A6', '#6366F1', '#F97316', '#A855F7'
        ];

        // 特殊字符集 (. + - * /)
        const specialChars = ['.', '+', '-', '*', '/'];

        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            console.log('游戏初始化完成');
            
            // 确保游戏容器正确加载
            if (!gameContainer) {
                console.error('游戏容器未找到!');
                return;
            }

            // 加载最高分
            loadHighScores();

            // 事件监听器
            startBtn.addEventListener('click', startGame);
            pauseBtn.addEventListener('click', togglePause);
            resetBtn.addEventListener('click', resetGame);
            highScoresBtn.addEventListener('click', showHighScores);
            closeModal.addEventListener('click', hideHighScores);
            speedSlider.addEventListener('input', updateSpeed);
            closeGameOverModal.addEventListener('click', hideGameOverModal);
            gameModeSelect.addEventListener('change', changeGameMode);

            // 键盘事件监听
            document.addEventListener('keydown', handleKeyPress);
        });

        // 改变游戏模式
        function changeGameMode() {
            gameMode = gameModeSelect.value;
            console.log('游戏模式已切换为:', gameMode);
            
            if (gameActive) {
                alert('游戏进行中,模式将在下一轮开始时生效');
            }
        }

        // 开始游戏
        function startGame() {
            if (gameActive) return;

            gameActive = true;
            gamePaused = false;
            score = 0;
            correctCount = 0;
            wrongCount = 0;

            updateStats();

            startBtn.disabled = true;
            pauseBtn.disabled = false;
            resetBtn.disabled = false;
            
            // 改变按钮样式
            startBtn.classList.remove('bg-primary', 'hover:bg-primary/90');
            startBtn.classList.add('bg-secondary', 'hover:bg-secondary/90');
            startBtn.innerHTML = '<i class="fa fa-gamepad mr-2"></i>游戏中...';

            // 清除所有现有字母
            clearLetters();

            console.log('开始生成', gameMode === 'letters' ? '字母' : '数字和符号', '速度:', letterSpeed);

            // 开始生成字母/数字
            letterInterval = setInterval(generateLetter, 1500 - (letterSpeed * 100));

            // 开始字母下落动画
            startLetterAnimation();
        }

        // 开始字母下落动画
        function startLetterAnimation() {
            if (animationFrame) {
                cancelAnimationFrame(animationFrame);
            }
            updateLetters();
        }

        // 暂停/恢复游戏
        function togglePause() {
            if (!gameActive) return;

            gamePaused = !gamePaused;

            if (gamePaused) {
                clearInterval(letterInterval);
                cancelAnimationFrame(animationFrame);
                pauseBtn.innerHTML = '<i class="fa fa-play mr-2"></i>继续';
                pauseBtn.classList.remove('bg-neutral', 'hover:bg-neutral/80');
                pauseBtn.classList.add('bg-accent', 'hover:bg-accent/90');
                console.log('游戏已暂停');
            } else {
                letterInterval = setInterval(generateLetter, 1500 - (letterSpeed * 100));
                updateLetters();
                pauseBtn.innerHTML = '<i class="fa fa-pause mr-2"></i>暂停';
                pauseBtn.classList.remove('bg-accent', 'hover:bg-accent/90');
                pauseBtn.classList.add('bg-neutral', 'hover:bg-neutral/80');
                console.log('游戏已恢复');
            }
        }

        // 重置游戏
        function resetGame() {
            gameActive = false;
            gamePaused = false;

            clearInterval(letterInterval);
            cancelAnimationFrame(animationFrame);
            clearLetters();

            startBtn.disabled = false;
            pauseBtn.disabled = true;
            resetBtn.disabled = true;
            
            // 恢复按钮样式
            startBtn.classList.remove('bg-secondary', 'hover:bg-secondary/90');
            startBtn.classList.add('bg-primary', 'hover:bg-primary/90');
            startBtn.innerHTML = '<i class="fa fa-play mr-2"></i>开始';
            
            pauseBtn.innerHTML = '<i class="fa fa-pause mr-2"></i>暂停';
            pauseBtn.classList.remove('bg-accent', 'hover:bg-accent/90');
            pauseBtn.classList.add('bg-neutral', 'hover:bg-neutral/80');

            updateStats();
            console.log('游戏已重置');
        }

        // 生成随机字母或数字
        function generateLetter() {
            if (gamePaused) return;

            const letter = document.createElement('div');
            letter.className = 'letter absolute flex items-center justify-center font-bold text-white text-shadow rounded-full shadow-lg animate-fall';
            
            let char;
            
            // 根据游戏模式生成字母或数字
            if (gameMode === 'letters') {
                // 随机选择字母 (A-Z)
                const charCode = Math.floor(Math.random() * 26) + 65;
                char = String.fromCharCode(charCode);
            } else {
                // 数字模式:20%概率生成特殊字符,80%概率生成数字
                if (Math.random() < 0.2) {
                    // 随机选择特殊字符
                    char = specialChars[Math.floor(Math.random() * specialChars.length)];
                } else {
                    // 随机选择数字 (0-9)
                    const charCode = Math.floor(Math.random() * 10) + 48;
                    char = String.fromCharCode(charCode);
                }
            }
            
            letter.textContent = char;
            letter.dataset.char = char;
            
            // 随机颜色
            const colorIndex = Math.floor(Math.random() * letterColors.length);
            const color = letterColors[colorIndex];
            letter.style.backgroundColor = color;
            letter.style.width = '50px';
            letter.style.height = '50px';
            letter.style.fontSize = '28px';
            
            // 随机水平位置
            const left = Math.random() * (gameContainer.offsetWidth - 50);
            letter.style.left = `${left}px`;
            letter.style.top = '-50px';
            
            // 设置动画持续时间
            const duration = 5 - (letterSpeed * 0.3); // 速度越快,下落时间越短
            letter.style.animationDuration = `${duration}s`;
            
            // 添加到游戏容器
            gameContainer.appendChild(letter);
            
            // 添加字母到数组
            letters.push({
                element: letter,
                char: char,
                speed: 0.5 + (letterSpeed * 0.3),
                position: -50
            });
        }

        // 更新字母位置
        function updateLetters() {
            if (gamePaused || !gameActive) {
                return;
            }

            const containerHeight = gameContainer.offsetHeight;

            for (let i = letters.length - 1; i >= 0; i--) {
                const letter = letters[i];
                letter.position += letter.speed;
                letter.element.style.top = `${letter.position}px`;

                // 检查字母是否超出底部边界
                if (letter.position > containerHeight) {
                    // 移除字母
                    if (letter.element.parentNode) {
                        gameContainer.removeChild(letter.element);
                    }
                    letters.splice(i, 1);
                    wrongCount++;
                    updateStats();
                }
            }

            // 继续动画
            animationFrame = requestAnimationFrame(updateLetters);
        }

        // 处理按键
        function handleKeyPress(e) {
            if (!gameActive || gamePaused) return;

            let keyPressed = e.key;
            
            // 处理特殊字符
            if (specialChars.includes(keyPressed)) {
                keyPressed = keyPressed;
            } else if (gameMode === 'numbers' && /^[0-9]$/.test(keyPressed)) {
                keyPressed = keyPressed;
            } else if (gameMode === 'letters' && /^[a-zA-Z]$/.test(keyPressed)) {
                keyPressed = keyPressed.toUpperCase();
            } else {
                // 非数字和字母键不处理
                return;
            }

            // 检查是否按下了正确的键
            console.log('按键:', keyPressed);
            let letterFound = false;
            
            // 查找匹配的字母/数字 (从最下面的开始)
            for (let i = letters.length - 1; i >= 0; i--) {
                if (letters[i].char === keyPressed) {
                    console.log('找到匹配:', keyPressed);
                    
                    // 获取匹配的字母元素
                    const matchedLetter = letters[i];
                    
                    // 移除匹配的字母
                    letters.splice(i, 1);
                    
                    // 增加分数
                    correctCount++;
                    score += 10;
                    
                    // 添加击碎效果
                    createShatterEffect(matchedLetter.element);
                    
                    letterFound = true;
                    break;
                }
            }

            if (!letterFound) {
                wrongCount++;
                console.log('未找到匹配,错误数增加');
            }

            updateStats();
        }

        // 清除所有字母
        function clearLetters() {
            letters.forEach(letter => {
                if (letter.element.parentNode) {
                    letter.element.parentNode.removeChild(letter.element);
                }
            });
            letters = [];
        }

        // 更新统计信息
        function updateStats() {
            scoreElement.textContent = score;
            correctElement.textContent = correctCount;
            wrongElement.textContent = wrongCount;

            const total = correctCount + wrongCount;
            const accuracy = total > 0 ? Math.round((correctCount / total) * 100) : 100;
            accuracyElement.textContent = `${accuracy}%`;

            // 更新游戏结束弹窗内容
            gameOverScore.textContent = score;
            gameOverCorrect.textContent = correctCount;
            gameOverWrong.textContent = wrongCount;
            gameOverAccuracy.textContent = `${accuracy}%`;
            gameOverMode.textContent = gameMode === 'letters' ? '字母模式' : '数字模式 (+.-*/)';

            // 检查游戏是否结束
            if (wrongCount >= 20) {
                gameOver();
            }
        }

        // 更新速度
        function updateSpeed() {
            letterSpeed = parseInt(speedSlider.value);
            speedValue.textContent = letterSpeed;
            console.log('游戏速度已更新为:', letterSpeed);

            if (gameActive && !gamePaused) {
                clearInterval(letterInterval);
                letterInterval = setInterval(generateLetter, 1500 - (letterSpeed * 100));
                console.log('字母生成间隔已更新为:', 1500 - (letterSpeed * 100), 'ms');
            }
        }

        // 显示最高分
        function showHighScores() {
            loadHighScores();
            highScoresModal.classList.remove('hidden');
        }

        // 隐藏最高分
        function hideHighScores() {
            highScoresModal.classList.add('hidden');
        }

        // 加载最高分
        function loadHighScores() {
            try {
                // 从本地存储获取最高分
                let highScores = JSON.parse(localStorage.getItem('typingGameHighScores')) || [];

                // 按分数排序
                highScores.sort((a, b) => b.score - a.score);

                // 只保留前10名
                highScores = highScores.slice(0, 10);

                // 更新表格
                highScoresBody.innerHTML = '';

                highScores.forEach((scoreData, index) => {
                    const row = document.createElement('tr');
                    row.className = 'border-b border-primary/20 hover:bg-primary/10 transition-colors';

                    // 排名列
                    const rankCell = document.createElement('td');
                    rankCell.className = 'py-3 px-4';
                    if (index === 0) {
                        rankCell.innerHTML = '<span class="text-gold font-bold">&#129351;</span>';
                    } else if (index === 1) {
                        rankCell.innerHTML = '<span class="text-silver font-bold">&#129352;</span>';
                    } else if (index === 2) {
                        rankCell.innerHTML = '<span class="text-bronze font-bold">&#129353;</span>';
                    } else {
                        rankCell.textContent = index + 1;
                    }

                    // 得分列
                    const scoreCell = document.createElement('td');
                    scoreCell.className = 'py-3 px-4 font-bold';
                    scoreCell.textContent = scoreData.score;

                    // 正确数列
                    const correctCell = document.createElement('td');
                    correctCell.className = 'py-3 px-4';
                    correctCell.textContent = scoreData.correct;

                    // 准确率列
                    const accuracyCell = document.createElement('td');
                    accuracyCell.className = 'py-3 px-4';
                    accuracyCell.textContent = `${scoreData.accuracy}%`;

                    // 日期列
                    const dateCell = document.createElement('td');
                    dateCell.className = 'py-3 px-4 text-light/70';
                    const date = new Date(scoreData.date);
                    dateCell.textContent = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`;

                    // 模式列
                    const modeCell = document.createElement('td');
                    modeCell.className = 'py-3 px-4';
                    modeCell.textContent = scoreData.mode === 'letters' ? '字母模式' : '数字模式 (+.-*/)';

                    row.appendChild(rankCell);
                    row.appendChild(scoreCell);
                    row.appendChild(correctCell);
                    row.appendChild(accuracyCell);
                    row.appendChild(dateCell);
                    row.appendChild(modeCell);

                    highScoresBody.appendChild(row);
                });
            } catch (error) {
                console.error('加载最高分记录时出错:', error);
            }
        }

        // 保存分数
        function saveScore() {
            try {
                const total = correctCount + wrongCount;
                const accuracy = total > 0 ? Math.round((correctCount / total) * 100) : 100;

                const gameData = {
                    score: score,
                    correct: correctCount,
                    accuracy: accuracy,
                    date: new Date().toISOString(),
                    mode: gameMode // 保存游戏模式
                };

                // 获取现有分数
                let highScores = JSON.parse(localStorage.getItem('typingGameHighScores')) || [];

                // 添加新分数
                highScores.push(gameData);

                // 保存回本地存储
                localStorage.setItem('typingGameHighScores', JSON.stringify(highScores));
                console.log('分数已保存:', gameData);
            } catch (error) {
                console.error('保存分数记录时出错:', error);
            }
        }

        // 游戏结束
        function gameOver() {
            gameActive = false;
            clearInterval(letterInterval);
            cancelAnimationFrame(animationFrame);

            // 保存分数
            saveScore();

            // 更新按钮状态
            startBtn.disabled = false;
            pauseBtn.disabled = true;
            resetBtn.disabled = false;
            
            // 恢复按钮样式
            startBtn.classList.remove('bg-secondary', 'hover:bg-secondary/90');
            startBtn.classList.add('bg-primary', 'hover:bg-primary/90');
            startBtn.innerHTML = '<i class="fa fa-play mr-2"></i>开始';
            
            pauseBtn.innerHTML = '<i class="fa fa-pause mr-2"></i>暂停';
            pauseBtn.classList.remove('bg-accent', 'hover:bg-accent/90');
            pauseBtn.classList.add('bg-neutral', 'hover:bg-neutral/80');

            // 显示游戏结束弹窗
            gameOverModal.classList.remove('hidden');
            console.log('游戏已结束');
        }

        // 隐藏游戏结束弹窗
        function hideGameOverModal() {
            gameOverModal.classList.add('hidden');
        }

        // 创建击碎效果 - 优化版本
        function createShatterEffect(element) {
            const rect = element.getBoundingClientRect();
            const containerRect = gameContainer.getBoundingClientRect();
            const x = rect.left - containerRect.left + rect.width / 2;
            const y = rect.top - containerRect.top + rect.height / 2;
            const color = element.style.backgroundColor;
            
            // 立即隐藏原字母
            element.style.display = 'none';
            
            // 创建碎片
            const numParticles = 32; // 更多碎片,增强效果
            for (let i = 0; i < numParticles; i++) {
                const particle = document.createElement('div');
                particle.className = 'particle';
                
                // 随机大小
                const size = Math.random() * 6 + 2;
                particle.style.width = `${size}px`;
                particle.style.height = `${size}px`;
                
                // 使用原字母的颜色
                particle.style.backgroundColor = color;
                
                // 设置初始位置为字母中心
                particle.style.left = `${x - size/2}px`;
                particle.style.top = `${y - size/2}px`;
                
                // 添加到游戏容器
                gameContainer.appendChild(particle);
                
                // 计算碎片飞出的角度和距离
                const angle = Math.random() * Math.PI * 2;
                const distance = Math.random() * 60 + 30;
                const destX = x + Math.cos(angle) * distance;
                const destY = y + Math.sin(angle) * distance;
                
                // 强制重排
                particle.offsetWidth;
                
                // 应用动画
                particle.style.transform = `translate(${destX - x}px, ${destY - y}px)`;
                particle.style.opacity = '0';
                
                // 移除碎片
                setTimeout(() => {
                    if (particle.parentNode) {
                        particle.parentNode.removeChild(particle);
                    }
                }, 500);
            }
        }
    </script>
</body>
</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>打字练习</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#F97316',
                        dark: '#1E293B',
                        light: '#F8FAFC',
                        accent: '#8B5CF6',
                        success: '#10B981',
                        danger: '#EF4444',
                        neutral: '#64748B'
                    },
                    fontFamily: {
                        inter: ['Inter', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .typing-text-shadow {
                text-shadow: 0 0 8px rgba(59, 130, 246, 0.6);
            }
            .typing-container {
                background-image: radial-gradient(circle, rgba(59, 130, 246, 0.1) 0%, rgba(30, 41, 59, 0) 70%);
            }
            .key-press-animation {
                animation: keyPress 0.2s ease-out;
            }
            .char-correct {
                color: #10B981;
                text-decoration: underline;
                text-decoration-color: #10B981;
            }
            .char-incorrect {
                color: #EF4444;
                text-decoration: underline;
                text-decoration-color: #EF4444;
            }
            .bg-gradient-game {
                background: linear-gradient(135deg, #1E293B 0%, #0F172A 100%);
            }
            .typing-cursor {
                position: relative;
            }
            .typing-cursor::after {
                content: '';
                position: absolute;
                right: -2px;
                top: 0;
                height: 100%;
                width: 2px;
                background-color: #3B82F6;
                animation: blink 1s infinite;
            }
            .stat-card {
                transition: all 0.3s ease;
            }
            .stat-card:hover {
                transform: translateY(-5px);
                box-shadow: 0 10px 25px -5px rgba(59, 130, 246, 0.1), 0 10px 10px -5px rgba(59, 130, 246, 0.04);
            }
            .keyboard-row {
                display: flex;
                justify-content: center;
                margin-bottom: 0.375rem;
            }
            .key {
                display: flex;
                align-items: center;
                justify-content: center;
                border-radius: 0.375rem;
                transition: all 0.15s ease;
                user-select: none;
                transform-origin: center;
                position: relative;
                overflow: hidden;
            }
            .key::before {
                content: '';
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0) 100%);
                pointer-events: none;
            }
            .typing-text-container {
                max-height: 8rem;
                overflow-y: auto;
                scrollbar-width: thin;
                scrollbar-color: #3B82F6 rgba(255, 255, 255, 0.1);
            }
            .typing-text-container::-webkit-scrollbar {
                width: 6px;
            }
            .typing-text-container::-webkit-scrollbar-thumb {
                background-color: #3B82F6;
                border-radius: 3px;
            }
            .typing-text-container::-webkit-scrollbar-track {
                background-color: rgba(255, 255, 255, 0.1);
            }
        }

        @keyframes keyPress {
            0% { transform: scale(1); box-shadow: 0 0 0 rgba(59, 130, 246, 0); }
            50% { transform: scale(0.95); box-shadow: 0 0 10px rgba(59, 130, 246, 0.5); }
            100% { transform: scale(1); box-shadow: 0 0 0 rgba(59, 130, 246, 0); }
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        @keyframes pulseGlow {
            0% { box-shadow: 0 0 5px rgba(59, 130, 246, 0.5); }
            50% { box-shadow: 0 0 20px rgba(59, 130, 246, 0.8); }
            100% { box-shadow: 0 0 5px rgba(59, 130, 246, 0.5); }
        }

        @keyframes blink {
            0%, 100% { opacity: 1; }
            50% { opacity: 0; }
        }

        .animate-fade-in {
            animation: fadeIn 0.5s ease-out forwards;
        }

        .animate-pulse-glow {
            animation: pulseGlow 2s infinite;
        }
    </style>
</head>
<body class="font-inter bg-gradient-game min-h-screen text-light flex flex-col">
    <!-- 导航栏 -->
    <nav class="bg-dark/80 backdrop-blur-md border-b border-primary/20 sticky top-0 z-50 transition-all duration-300">
        <div class="container mx-auto px-4 py-3 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa-solid fa-keyboard text-primary text-2xl"></i>
                <h1 class="text-xl md:text-2xl font-bold bg-gradient-to-r from-primary to-blue-400 text-transparent bg-clip-text">
                    打字练习
                </h1>
            </div>
            <button class="md:hidden text-gray-300 hover:text-primary transition-colors duration-300">
                <i class="fa-solid fa-bars text-xl"></i>
            </button>
        </div>
    </nav>

    <!-- 主要内容区 -->
    <main class="flex-grow container mx-auto px-4 py-8">
        <!-- 游戏区域 -->
        <section class="max-w-4xl mx-auto bg-dark/60 backdrop-blur-sm rounded-2xl p-6 md:p-8 border border-primary/30 shadow-xl shadow-primary/10 mb-8 transform transition-all duration-500 hover:shadow-primary/20">
            <!-- 游戏状态信息 -->
            <div class="flex flex-wrap justify-between items-center mb-6 gap-4">
                <div class="flex items-center space-x-4">
                    <div class="stat-card bg-dark/80 rounded-xl p-3 border border-primary/20 flex items-center space-x-2 animate-fade-in" style="animation-delay: 0.1s">
                        <i class="fa-solid fa-clock text-primary text-xl"></i>
                        <div>
                            <p class="text-xs text-gray-400">剩余时间</p>
                            <p id="timer" class="text-2xl font-bold">60</p>
                        </div>
                    </div>
                    <div class="stat-card bg-dark/80 rounded-xl p-3 border border-primary/20 flex items-center space-x-2 animate-fade-in" style="animation-delay: 0.2s">
                        <i class="fa-solid fa-tachometer-alt text-primary text-xl"></i>
                        <div>
                            <p class="text-xs text-gray-400">当前速度</p>
                            <p id="wpm" class="text-2xl font-bold">0</p>
                            <p class="text-xs text-gray-400">WPM</p>
                        </div>
                    </div>
                </div>
                <div class="flex items-center space-x-4">
                    <div class="stat-card bg-dark/80 rounded-xl p-3 border border-primary/20 flex items-center space-x-2 animate-fade-in" style="animation-delay: 0.3s">
                        <i class="fa-solid fa-check-circle text-green-500 text-xl"></i>
                        <div>
                            <p class="text-xs text-gray-400">正确率</p>
                            <p id="accuracy" class="text-2xl font-bold">0%</p>
                        </div>
                    </div>
                    <button id="start-btn" class="bg-primary hover:bg-primary/90 text-white font-bold py-3 px-6 rounded-xl transition-all duration-300 transform hover:scale-105 flex items-center space-x-2 animate-fade-in animate-pulse-glow" style="animation-delay: 0.4s">
                        <i class="fa-solid fa-play"></i>
                        <span>开始游戏</span>
                    </button>
                    <!-- 添加刷新按钮 -->
                    <button id="refresh-btn" class="bg-primary hover:bg-primary/90 text-white font-bold py-3 px-6 rounded-xl transition-all duration-300 transform hover:scale-105 flex items-center space-x-2 animate-fade-in" style="animation-delay: 0.4s">
                        <i class="fa-solid fa-sync"></i>
                        <span>刷新文本</span>
                    </button>
                </div>
            </div>

            <!-- 打字区域 -->
            <div class="typing-container bg-dark/80 rounded-xl p-6 md:p-8 border border-primary/20 mb-6 animate-fade-in transform transition-all duration-300 hover:shadow-lg hover:shadow-primary/10" style="animation-delay: 0.5s">
                <div class="flex items-center justify-center mb-4">
                    <div class="w-24 h-1 bg-primary/30 rounded-full overflow-hidden">
                        <div id="progress-bar" class="h-full bg-primary" style="width: 0%"></div>
                    </div>
                </div>
                <!-- 滚动容器 -->
                <div id="typing-text-container" class="typing-text-container mb-4">
                    <p id="typing-text" class="text-2xl md:text-3xl font-medium leading-relaxed">
                        准备好了吗?点击开始按钮,然后开始输入显示的文本。尽量快速且准确地输入!
                    </p>
                </div>
                <div class="relative">
                    <input type="text" id="typing-input" class="w-full bg-dark/50 text-light text-xl md:text-2xl py-4 px-6 rounded-lg border border-primary/40 focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all duration-300 placeholder-gray-500" placeholder="开始输入..." disabled>
                    <div class="absolute right-4 top-1/2 transform -translate-y-1/2 text-gray-500">
                        <i id="caps-lock-indicator" class="fa-solid fa-lock-open hidden"></i>
                    </div>
                </div>
            </div>

            <!-- 键盘可视化 -->
            <div class="keyboard-container bg-dark/80 rounded-xl p-4 border border-primary/20 animate-fade-in transform transition-all duration-300 hover:shadow-lg hover:shadow-primary/10" style="animation-delay: 0.6s">
                <div id="keyboard" class="keyboard-wrapper w-full overflow-x-auto pb-2">
                    <!-- 键盘将由JS动态生成 -->
                </div>
            </div>
        </section>

        <!-- 游戏结果 -->
        <section id="results-section" class="max-w-4xl mx-auto bg-dark/60 backdrop-blur-sm rounded-2xl p-6 md:p-8 border border-primary/30 shadow-xl shadow-primary/10 mb-8 hidden transform transition-all duration-500 hover:shadow-primary/20">
            <h2 class="text-2xl md:text-3xl font-bold text-center mb-6 bg-gradient-to-r from-primary to-blue-400 text-transparent bg-clip-text">游戏结果</h2>
            <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
                <div class="stat-card bg-dark/80 rounded-xl p-6 border border-primary/20 text-center transform transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-primary/20">
                    <div class="w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4">
                        <i class="fa-solid fa-tachometer-alt text-primary text-3xl"></i>
                    </div>
                    <h3 class="text-lg font-medium text-gray-400 mb-1">最终速度</h3>
                    <p id="final-wpm" class="text-4xl font-bold">0 WPM</p>
                    <div class="mt-2 h-1 w-full bg-primary/20 rounded-full overflow-hidden">
                        <div class="final-wpm-progress h-full bg-primary" style="width: 0%"></div>
                    </div>
                </div>
                <div class="stat-card bg-dark/80 rounded-xl p-6 border border-primary/20 text-center transform transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-primary/20">
                    <div class="w-16 h-16 bg-green-500/10 rounded-full flex items-center justify-center mx-auto mb-4">
                        <i class="fa-solid fa-check-circle text-green-500 text-3xl"></i>
                    </div>
                    <h3 class="text-lg font-medium text-gray-400 mb-1">正确率</h3>
                    <p id="final-accuracy" class="text-4xl font-bold">0%</p>
                    <div class="mt-2 h-1 w-full bg-green-500/20 rounded-full overflow-hidden">
                        <div class="final-accuracy-progress h-full bg-green-500" style="width: 0%"></div>
                    </div>
                </div>
                <div class="stat-card bg-dark/80 rounded-xl p-6 border border-primary/20 text-center transform transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-primary/20">
                    <div class="w-16 h-16 bg-secondary/10 rounded-full flex items-center justify-center mx-auto mb-4">
                        <i class="fa-solid fa-pencil-alt text-secondary text-3xl"></i>
                    </div>
                    <h3 class="text-lg font-medium text-gray-400 mb-1">总输入</h3>
                    <p id="total-characters" class="text-4xl font-bold">0 字符</p>
                    <div class="mt-2 h-1 w-full bg-secondary/20 rounded-full overflow-hidden">
                        <div class="final-chars-progress h-full bg-secondary" style="width: 0%"></div>
                    </div>
                </div>
            </div>
            <div class="mt-8 flex justify-center">
                <button id="play-again-btn" class="bg-primary hover:bg-primary/90 text-white font-bold py-3 px-8 rounded-xl transition-all duration-300 transform hover:scale-105 flex items-center space-x-2">
                    <i class="fa-solid fa-redo"></i>
                    <span>再玩一次</span>
                </button>
            </div>
        </section>

        <!-- 难度选择 -->
        <section class="max-w-4xl mx-auto bg-dark/60 backdrop-blur-sm rounded-2xl p-6 md:p-8 border border-primary/30 shadow-xl shadow-primary/10 mb-8 transform transition-all duration-500 hover:shadow-primary/20">
            <h2 class="text-xl md:text-2xl font-bold mb-4 bg-gradient-to-r from-primary to-blue-400 text-transparent bg-clip-text">难度设置</h2>
            <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
                <div class="difficulty-option border-2 border-primary/30 rounded-xl p-4 cursor-pointer hover:border-primary transition-all duration-300 transform hover:scale-105 bg-dark/80" data-difficulty="easy">
                    <div class="flex items-center justify-between mb-2">
                        <h3 class="font-bold">简单</h3>
                        <span class="bg-green-500/20 text-green-400 text-xs px-2 py-1 rounded-full">初学者</span>
                    </div>
                    <p class="text-sm text-gray-400 mb-3">简短的句子,较慢的倒计时</p>
                    <div class="flex justify-between items-center">
                        <span class="text-xs text-gray-500">时间: 90秒</span>
                        <i class="fa-solid fa-check-circle text-green-500 opacity-0"></i>
                    </div>
                </div>
                <div class="difficulty-option border-2 border-primary/30 rounded-xl p-4 cursor-pointer hover:border-primary transition-all duration-300 transform hover:scale-105 bg-dark/80" data-difficulty="medium">
                    <div class="flex items-center justify-between mb-2">
                        <h3 class="font-bold">中等</h3>
                        <span class="bg-yellow-500/20 text-yellow-400 text-xs px-2 py-1 rounded-full">进阶者</span>
                    </div>
                    <p class="text-sm text-gray-400 mb-3">中等长度句子,标准倒计时</p>
                    <div class="flex justify-between items-center">
                        <span class="text-xs text-gray-500">时间: 60秒</span>
                        <i class="fa-solid fa-check-circle text-green-500 opacity-100"></i>
                    </div>
                </div>
                <div class="difficulty-option border-2 border-primary/30 rounded-xl p-4 cursor-pointer hover:border-primary transition-all duration-300 transform hover:scale-105 bg-dark/80" data-difficulty="hard">
                    <div class="flex items-center justify-between mb-2">
                        <h3 class="font-bold">困难</h3>
                        <span class="bg-red-500/20 text-red-400 text-xs px-2 py-1 rounded-full">专家</span>
                    </div>
                    <p class="text-sm text-gray-400 mb-3">长句子,快速倒计时</p>
                    <div class="flex justify-between items-center">
                        <span class="text-xs text-gray-500">时间: 30秒</span>
                        <i class="fa-solid fa-check-circle text-green-500 opacity-0"></i>
                    </div>
                </div>
            </div>
        </section>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark/80 backdrop-blur-md border-t border-primary/20 py-6">
        <div class="container mx-auto px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <div class="flex items-center space-x-2">
                        <i class="fa-solid fa-keyboard text-primary text-xl"></i>
                        <span class="font-bold text-lg">打字练习</span>
                    </div>
                    <p class="text-sm text-gray-400 mt-1">提升你的打字速度,挑战极限!</p>
                </div>
                <div class="flex space-x-6">
                    <a href="#" class="text-gray-400 hover:text-primary transition-colors duration-300">
                        <i class="fa-brands fa-github text-xl"></i>
                    </a>
                    <a href="#" class="text-gray-400 hover:text-primary transition-colors duration-300">
                        <i class="fa-brands fa-twitter text-xl"></i>
                    </a>
                    <a href="#" class="text-gray-400 hover:text-primary transition-colors duration-300">
                        <i class="fa-brands fa-instagram text-xl"></i>
                    </a>
                </div>
            </div>
            <div class="border-t border-primary/10 mt-6 pt-6 text-center text-sm text-gray-500">
                &#169; 2025 打字练习 | 提升你的打字技能
            </div>
        </div>
    </footer>

    <script>
        // 打字游戏逻辑
        document.addEventListener('DOMContentLoaded', function() {
            // DOM元素
            const startBtn = document.getElementById('start-btn');
            const typingInput = document.getElementById('typing-input');
            const typingTextContainer = document.getElementById('typing-text-container');
            const typingText = document.getElementById('typing-text');
            const timerEl = document.getElementById('timer');
            const wpmEl = document.getElementById('wpm');
            const accuracyEl = document.getElementById('accuracy');
            const resultsSection = document.getElementById('results-section');
            const finalWpmEl = document.getElementById('final-wpm');
            const finalAccuracyEl = document.getElementById('final-accuracy');
            const totalCharactersEl = document.getElementById('total-characters');
            const playAgainBtn = document.getElementById('play-again-btn');
            const progressBar = document.getElementById('progress-bar');
            const capsLockIndicator = document.getElementById('caps-lock-indicator');
            const difficultyOptions = document.querySelectorAll('.difficulty-option');
            const keyboardWrapper = document.getElementById('keyboard');
            const refreshBtn = document.getElementById('refresh-btn'); // 获取刷新按钮

            // 游戏状态
            let gameStarted = false;
            let timer = 60;
            let timerInterval;
            let startTime;
            let currentText = '';
            let correctChars = 0;
            let totalChars = 0;
            let currentDifficulty = 'medium';

            // 文本库
            const textBank = [
                "编程是与计算机对话的艺术,每个程序员都是代码世界的诗人。",
                "在数字的海洋中,算法是指引我们前行的灯塔,数据是无尽的宝藏。",
                "学习编程不仅是掌握一门技术,更是培养一种解决问题的思维方式。",
                "当你的代码开始有了生命,你会发现编程是世界上最神奇的魔法。",
                "最好的代码是那些既能够高效运行,又能够被人理解的代码。",
                "在编程的世界里,没有完美的代码,但有不断追求完美的程序员。",
                "调试是将错误从你的代码中解放出来的过程,也是编程中最有趣的部分。",
                "每一个bug都是一次学习的机会,每一次修复都是一次成长。",
                "编程教会我们,复杂的问题可以分解为简单的步骤来解决。",
                "真正的程序员不写代码,他们只是和编译器交流自己的想法。",
                "代码是写给人看的,只是恰好能被机器执行。",
                "如果你认为数学很难,那你应该试试编程。",
                "编程就像下棋,一步错可能导致满盘皆输,但坚持下去总会有转机。",
                "在编程中,如同在生活中,重要的不是你遇到了多少问题,而是你如何解决它们。",
                "编程是未来的语言,学习它就是在为明天做准备。",
                "Web开发需要掌握HTML、CSS和JavaScript,这三者缺一不可。",
                "数据结构和算法是编程的基础,良好的基础能让你走得更远。",
                "人工智能正在改变世界,机器学习是人工智能的核心技术。",
                "响应式设计确保网站在各种设备上都能提供良好的用户体验。",
                "版本控制系统如Git,是现代软件开发中不可或缺的工具。",
                "前端框架如React、Vue和Angular正在重塑Web开发的方式。",
                "数据库设计是构建高效应用程序的关键环节。",
                "云计算让我们能够更高效地利用计算资源,降低成本。",
                "移动应用开发需要考虑屏幕尺寸、触摸交互等多种因素。",
                "用户体验设计是创造成功产品的重要组成部分。",
                "测试是软件开发过程中不可或缺的环节,能确保代码质量。"
            ];

            // 生成键盘可视化
            function generateKeyboard() {
                keyboardWrapper.innerHTML = '';

                // 键盘布局定义
                const keyboardLayout = [
                    ['`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'Backspace'],
                    ['Tab', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\\'],
                    ['Caps Lock', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', 'Enter'],
                    ['Shift', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'Shift'],
                    [' ', 'Space', ' ']
                ];

                // 特殊按键宽度配置 - 使用相对单位
                const keyWidths = {
                    'Backspace': 1.5,
                    'Tab': 1.25,
                    '\\': 1.25,
                    'Caps Lock': 1.35,
                    'Enter': 1.85,
                    'Shift': 1.75,
                    'Space': 5
                };

                // 计算基础尺寸
                const baseKeyWidth = 50; // 基础按键宽度(px)
                const baseKeyHeight = 50; // 基础按键高度(px)
                const baseSpacing = 4; // 基础间距(px)

                // 计算键盘总宽度
                let maxRowWidth = 0;
                keyboardLayout.forEach(row => {
                    let rowWidth = 0;
                    row.forEach(key => {
                        const width = keyWidths[key] || 1;
                        rowWidth += width;
                    });
                    if(rowWidth > maxRowWidth) {
                        maxRowWidth = rowWidth;
                    }
                });

                // 计算缩放因子,使键盘适应容器
                const containerWidth = keyboardWrapper.clientWidth;
                const availableWidth = containerWidth - (baseSpacing * (14 - 1)); // 14个按键的间距
                const scaleFactor = Math.min(1, availableWidth / (maxRowWidth * baseKeyWidth));

                // 应用缩放后的尺寸
                const scaledKeyWidth = baseKeyWidth * scaleFactor;
                const scaledKeyHeight = baseKeyHeight * scaleFactor;
                const scaledSpacing = baseSpacing * scaleFactor;

                // 为每个键盘行创建容器
                keyboardLayout.forEach((row, rowIndex) => {
                    const rowEl = document.createElement('div');
                    rowEl.className = 'keyboard-row';
                    rowEl.style.marginBottom = `${scaledSpacing}px`;

                    // 创建每行的按键
                    row.forEach(key => {
                        const keyEl = document.createElement('div');

                        // 计算按键宽度
                        const keyWidth = (keyWidths[key] || 1) * scaledKeyWidth;

                        // 设置按键样式
                        keyEl.className = `key bg-dark/50 text-light border border-primary/30 rounded-md mx-${scaledSpacing / 2} transition-all duration-150 transform hover:scale-105 hover:bg-primary/20 text-center select-none`;
                        keyEl.style.width = `${keyWidth}px`;
                        keyEl.style.height = `${scaledKeyHeight}px`;
                        keyEl.dataset.key = key;

                        // 特殊键的显示文本
                        let displayText = key;
                        if(key === ' ') displayText = 'Space';

                        // 根据屏幕尺寸调整字体大小
                        const isMobile = window.innerWidth < 768;
                        const fontSize = isMobile ? 'text-xs' : key.length > 1 ? 'text-xs' : 'text-sm';

                        keyEl.innerHTML = `<span class="${fontSize}">${displayText}</span>`;
                        rowEl.appendChild(keyEl);
                    });

                    keyboardWrapper.appendChild(rowEl);
                });
            }

            // 高亮按下的键
            function highlightKey(key) {
                // 处理特殊情况
                if (key === ' ') {
                    key = 'Space';
                }
                // 统一转换为大写,以匹配键盘布局
                key = key.toUpperCase();

                const keyEl = document.querySelector(`.key[data-key="${key}"]`);
                if (keyEl) {
                    keyEl.classList.add('bg-primary/30', 'key-press-animation');
                    setTimeout(() => {
                        keyEl.classList.remove('bg-primary/30', 'key-press-animation');
                    }, 150);
                }
            }

            // 根据难度获取文本
            function getTextByDifficulty() {
                // 复制原数组
                const filteredTexts = [...textBank];

                // 根据难度调整文本长度
                if(currentDifficulty === 'easy') {
                    // 简单难度:短文本
                    filteredTexts.sort((a, b) => a.length - b.length);
                    return filteredTexts[Math.floor(Math.random() * (filteredTexts.length / 2))];
                } else if(currentDifficulty === 'hard') {
                    // 困难难度:长文本
                    filteredTexts.sort((a, b) => b.length - a.length);
                    return filteredTexts[Math.floor(Math.random() * (filteredTexts.length / 2))];
                } else {
                    // 中等难度:随机文本
                    return filteredTexts[Math.floor(Math.random() * filteredTexts.length)];
                }
            }

            // 选择随机文本
            function getRandomText() {
                return getTextByDifficulty();
            }

            // 格式化打字文本,添加高亮效果和光标
            function formatTypingText(input) {
                input = input || '';
                let html = '';

                for(let i = 0; i < currentText.length; i++) {
                    if(i < input.length) {
                        if(input[i] === currentText[i]) {
                            html += `<span class="char-correct">${currentText[i]}</span>`;
                        } else {
                            html += `<span class="char-incorrect">${currentText[i]}</span>`;
                        }
                    } else if(i === input.length) {
                        html += `<span class="typing-cursor">${currentText[i]}</span>`;
                    } else {
                        html += currentText[i];
                    }
                }

                typingText.innerHTML = html;
                
                // 自动滚动到当前光标位置
                const cursorElement = typingText.querySelector('.typing-cursor');
                if (cursorElement) {
                    const cursorRect = cursorElement.getBoundingClientRect();
                    const containerRect = typingTextContainer.getBoundingClientRect();
                    
                    // 计算需要滚动的距离
                    if (cursorRect.bottom > containerRect.bottom) {
                        typingTextContainer.scrollTop += cursorRect.bottom - containerRect.bottom;
                    } else if (cursorRect.top < containerRect.top) {
                        typingTextContainer.scrollTop -= containerRect.top - cursorRect.top;
                    }
                }
            }

            // 计算WPM(每分钟字数)
            function calculateWPM() {
                const timeSpent = (Date.now() - startTime) / 60000; // 转换为分钟
                if(timeSpent === 0) return 0;
                const wpm = Math.round(correctChars / 5 / timeSpent);
                return wpm;
            }

            // 计算正确率
            function calculateAccuracy() {
                if(totalChars === 0) return 0;
                return Math.round((correctChars / totalChars) * 100);
            }

            // 更新计时器和进度条
            function updateTimer() {
                timer--;
                timerEl.textContent = timer;

                // 更新进度条
                const percentage = (timer / getTimeLimit()) * 100;
                progressBar.style.width = `${percentage}%`;

                // 时间快结束时的视觉效果
                if(timer <= 10) {
                    timerEl.classList.add('text-red-500', 'animate-pulse');
                    progressBar.classList.add('bg-red-500');
                    progressBar.classList.remove('bg-primary');
                } else {
                    progressBar.classList.remove('bg-red-500');
                    progressBar.classList.add('bg-primary');
                }

                if(timer <= 0) {
                    endGame();
                }
            }

            // 根据难度获取时间限制
            function getTimeLimit() {
                switch(currentDifficulty) {
                    case 'easy': return 90;
                    case 'medium': return 60;
                    case 'hard': return 30;
                    default: return 60;
                }
            }

            // 开始游戏
            function startGame() {
                if(gameStarted) return;

                // 设置游戏状态
                gameStarted = true;
                startBtn.disabled = true;
                startBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i><span>游戏进行中</span>';
                typingInput.disabled = false;
                typingInput.focus();

                // 重置游戏数据
                timer = getTimeLimit();
                timerEl.textContent = timer;
                timerEl.classList.remove('text-red-500', 'animate-pulse');
                correctChars = 0;
                totalChars = 0;
                wpmEl.textContent = '0';
                accuracyEl.textContent = '0%';
                progressBar.style.width = '100%';
                progressBar.classList.remove('bg-red-500');
                progressBar.classList.add('bg-primary');

                // 获取随机文本
                currentText = getRandomText();
                typingText.textContent = currentText; // 在游戏开始前显示要打的文本
                formatTypingText();

                // 开始计时器
                startTime = Date.now();
                timerInterval = setInterval(updateTimer, 1000);

                // 滚动到打字区域
                typingInput.scrollIntoView({ behavior: 'smooth', block: 'center' });
            }

            // 结束游戏
            function endGame() {
                if(!gameStarted) return;

                // 清除计时器
                clearInterval(timerInterval);
                gameStarted = false;

                // 更新UI
                startBtn.disabled = false;
                startBtn.innerHTML = '<i class="fa-solid fa-play"></i><span>开始游戏</span>';
                typingInput.disabled = true;
                typingInput.value = '';

                // 计算最终结果
                const finalWpm = calculateWPM();
                const accuracy = calculateAccuracy();

                // 显示结果
                finalWpmEl.textContent = `${finalWpm} WPM`;
                finalAccuracyEl.textContent = `${accuracy}%`;
                totalCharactersEl.textContent = `${totalChars} 字符`;

                // 结果动画
                animateResultBar('.final-wpm-progress', finalWpm, 150);
                animateResultBar('.final-accuracy-progress', accuracy, 150);
                animateResultBar('.final-chars-progress', Math.min(totalChars / 100 * 100, 100), 150);

                // 显示结果部分并添加动画
                resultsSection.classList.remove('hidden');
                resultsSection.classList.add('animate-fade-in');

                // 滚动到结果部分
                setTimeout(() => {
                    resultsSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
                }, 300);
            }

            // 结果进度条动画
            function animateResultBar(selector, value, duration) {
                const elements = document.querySelectorAll(selector);
                elements.forEach(el => {
                    let start = 0;
                    const interval = setInterval(() => {
                        start += 1;
                        el.style.width = `${start}%`;
                        if(start >= value) {
                            clearInterval(interval);
                        }
                    }, duration / value);
                });
            }

            // 重置游戏
            function resetGame() {
                if(gameStarted) {
                    clearInterval(timerInterval);
                    gameStarted = false;
                }

                // 重置UI
                startBtn.disabled = false;
                startBtn.innerHTML = '<i class="fa-solid fa-play"></i><span>开始游戏</span>';
                typingInput.disabled = true;
                typingInput.value = '';
                timerEl.textContent = getTimeLimit();
                timerEl.classList.remove('text-red-500', 'animate-pulse');
                wpmEl.textContent = '0';
                accuracyEl.textContent = '0%';
                progressBar.style.width = '100%';
                progressBar.classList.remove('bg-red-500');
                progressBar.classList.add('bg-primary');
                typingText.textContent = '准备好了吗?点击开始按钮,然后开始输入显示的文本。尽量快速且准确地输入!';

                // 隐藏结果部分
                resultsSection.classList.add('hidden');
            }

            // 切换文本函数
            function changeText() {
                currentText = getRandomText();
                typingText.textContent = currentText;
                if (gameStarted) {
                    typingInput.value = '';
                    correctChars = 0;
                    totalChars = 0;
                    wpmEl.textContent = '0';
                    accuracyEl.textContent = '0%';
                    formatTypingText();
                }
            }

            // 事件监听器
            startBtn.addEventListener('click', startGame);
            playAgainBtn.addEventListener('click', () => {
                resetGame();
                startGame();
            });
            refreshBtn.addEventListener('click', changeText); // 为刷新按钮添加点击事件监听器

            typingInput.addEventListener('input', function() {
                if(!gameStarted) return;

                const input = typingInput.value;
                totalChars = input.length;

                // 计算正确字符数
                correctChars = 0;
                for(let i = 0; i < Math.min(input.length, currentText.length); i++) {
                    if(input[i] === currentText[i]) {
                        correctChars++;
                    }
                }

                // 更新显示
                formatTypingText(input);
                wpmEl.textContent = calculateWPM();
                accuracyEl.textContent = `${calculateAccuracy()}%`;

                // 检查是否完成
                if(input.length === currentText.length) {
                    endGame();
                }
            });

            // 键盘事件监听
            document.addEventListener('keydown', function(e) {
                if(e.key === 'CapsLock') {
                    capsLockIndicator.classList.toggle('hidden');
                    capsLockIndicator.classList.toggle('fa-lock-open');
                    capsLockIndicator.classList.toggle('fa-lock');
                }

                // 高亮按下的键
                if(e.key.length === 1 || ['Backspace', 'Tab', 'Enter', 'Shift', ' '].includes(e.key)) {
                    let keyDisplay = e.key;
                    if(keyDisplay === ' ') keyDisplay = 'Space';
                    highlightKey(keyDisplay);
                }

                // 如果游戏未开始,按任意键不聚焦输入框
                if(!gameStarted) {
                    e.preventDefault();
                }
            });

            // 难度选择
            difficultyOptions.forEach(option => {
                option.addEventListener('click', function() {
                    // 移除所有选中状态
                    difficultyOptions.forEach(opt => {
                        opt.querySelector('i').classList.add('opacity-0');
                        opt.classList.remove('border-primary');
                        opt.classList.add('border-primary/30');
                    });

                    // 添加当前选中状态
                    this.querySelector('i').classList.remove('opacity-0');
                    this.classList.remove('border-primary/30');
                    this.classList.add('border-primary');

                    // 更新难度
                    currentDifficulty = this.dataset.difficulty;

                    // 如果游戏未开始,更新计时器显示
                    if(!gameStarted) {
                        timerEl.textContent = getTimeLimit();
                        // 重新获取文本并显示
                        currentText = getRandomText();
                        typingText.textContent = currentText;
                    }
                });
            });

            // 初始化
            generateKeyboard();
            // 在游戏开始前显示要打的文本
            currentText = getRandomText();
            typingText.textContent = currentText;

            // 页面滚动效果
            window.addEventListener('scroll', function() {
                const nav = document.querySelector('nav');
                if (window.scrollY > 10) {
                    nav.classList.add('py-2');
                    nav.classList.remove('py-3');
                } else {
                    nav.classList.add('py-3');
                    nav.classList.remove('py-2');
                }
            });

            // 窗口大小变化时重新生成键盘
            window.addEventListener('resize', generateKeyboard);
        });
    </script>
</body>
</html>    

打字练习.zip

16.85 KB, 下载次数: 375, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 13吾爱币 +19 热心值 +12 收起 理由
小懒虫 + 1 + 1 真是太好了
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
acail + 1 + 1 谢谢@Thanks!
5omggx + 1 + 1 用心讨论,共获提升!
chao0927 + 1 谢谢@Thanks!
jk998 + 1 + 1 我很赞同!
sam喵喵 + 1 谢谢@Thanks!
hehehero + 2 + 1 热心回复!
tianyulouzhu + 1 + 1 收下了
fqy890 + 1 + 1 我很赞同!
常胜将军 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
superboy8286 + 1 + 1 谢谢@Thanks!
jinqiaoa1a + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沉默之剑 发表于 2025-5-15 09:46
提一个bug,中文的拼音算作字符数,如果拼音长度超过句子字数,就会结束计时。
VeryCapture_20250515094507.jpg
 楼主| zhengzhenhui945 发表于 2025-5-16 20:45
本帖最后由 zhengzhenhui945 于 2025-5-16 20:46 编辑
dickwolf 发表于 2025-5-16 08:27
不错 不过小孩打字的话 建议可以把字加大一些 ,字母活动范围再大一些,以前的学习机有打船啊 打小飞机啊  ...

有大字版本给自己娃子用的,有点小BUG我没优化,感觉够用,你看凑合用下
[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>打字大师</title>
    <script>
        // jQuery v3.6.0 核心代码(简化版)
        (function (window, undefined) {
            var jQuery = function (selector, context) {
                return new jQuery.fn.init(selector, context);
            };
            jQuery.fn = jQuery.prototype = {
                init: function (selector, context) {
                    // 初始化逻辑
                    return this;
                }
            };
            jQuery.fn.init.prototype = jQuery.fn;
            window.jQuery = window.$ = jQuery;
        })(window);
    </script>
    <style>
        :root {
            --primary-color: #6a11cb;
            --secondary-color: #2575fc;
            --accent-color: #ff416c;
            --text-color: #ffffff;
            --bg-color: #1a1a2e;
            --letter-bg: #ffffff;
            --math-color: #FFD700; /* 数学符号专用颜色 */
            --correct-color: #4CAF50; /* 正确颜色 */
            --wrong-color: #F44336; /* 错误颜色 */
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Arial', sans-serif;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: var(--bg-color);
            overflow: hidden;
        }

        .game-container {
            position: relative;
            width: 90vw;
            max-width: 960px;
            height: 80vh;
            background: radial-gradient(circle, #2a2a4a 0%, #1a1a2e 100%);
            border-radius: 15px;
            box-shadow: 0 0 30px rgba(0, 0, 0, 0.5);
            overflow: hidden;
        }

        .bottom-controls {
            position: absolute;
            bottom: 30px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 20px;
            z-index: 50;
        }

        .score-panel {
            display: flex;
            align-items: center;
            background: rgba(0, 0, 0, 0.6);
            padding: 15px 30px;
            border-radius: 50px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
            width: 100%;
            justify-content: center;
            flex-wrap: wrap; /* 允许内容换行 */
        }

        .btn {
            background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
            color: var(--text-color);
            border: none;
            padding: 10px 20px;
            border-radius: 25px;
            font-size: 18px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 4px 15px rgba(106, 17, 203, 0.4);
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(106, 17, 203, 0.6);
        }

        .score-value {
            color: var(--text-color);
            font-size: 32px;
            font-weight: bold;
            margin: 0 20px;
        }

        .health-indicator {
            display: flex;
            margin-left: 15px;
        }

        .heart {
            width: 35px;
            height: 35px;
            margin: 0 3px;
            fill: #ff3333;
            transition: all 0.3s ease;
        }

        .heart.lost {
            fill: #666666;
        }

        .start-button {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
            color: var(--text-color);
            border: none;
            padding: 20px 50px;
            border-radius: 50px;
            font-size: 36px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 0 30px rgba(106, 17, 203, 0.6);
            z-index: 100;
        }

        .start-button:hover {
            transform: translate(-50%, -50%) scale(1.05);
            box-shadow: 0 0 40px rgba(106, 17, 203, 0.8);
        }

        .letter {
            position: absolute;
            width: 100px;
            height: 100px;
            transition: all 0.2s ease;
            z-index: 20;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 48px;
            font-weight: bold;
            color: #333;
            border-radius: 50%;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
            animation: float 1s ease-in-out infinite alternate;
        }

        .math-symbol {
            background-color: var(--math-color) !important;
            box-shadow: 0 4px 15px rgba(255, 215, 0, 0.4) !important;
            transform: scale(1.1);
            z-index: 21;
        }

        @keyframes float {
            0% {
                transform: translateY(-5px);
            }

            100% {
                transform: translateY(5px);
            }
        }

        .letter.hit {
            display: none;
        }

        .fragment {
            position: absolute;
            width: 10px;
            height: 10px;
            background-color: inherit;
            border-radius: 50%;
            animation: shatter 0.5s ease forwards;
        }

        @keyframes shatter {
            0% {
                transform: scale(1) translate(0, 0);
                opacity: 1;
            }

            100% {
                transform: scale(0) translate(var(--x), var(--y));
                opacity: 0;
            }
        }

        .game-over {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.9);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 200;
            opacity: 0;
            visibility: hidden;
            transition: all 0.5s ease;
        }

        .game-over.visible {
            opacity: 1;
            visibility: visible;
        }

        .game-over h2 {
            color: var(--text-color);
            font-size: 64px;
            margin-bottom: 30px;
            text-shadow: 0 0 15px rgba(106, 17, 203, 0.8);
        }

        .final-score {
            color: var(--text-color);
            font-size: 48px;
            margin-bottom: 50px;
        }

        .restart-button {
            background: linear-gradient(to right, var(--accent-color), #ff4b2b);
            color: var(--text-color);
            border: none;
            padding: 20px 50px;
            border-radius: 50px;
            font-size: 32px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 0 30px rgba(255, 65, 108, 0.6);
        }

        .restart-button:hover {
            transform: scale(1.05);
            box-shadow: 0 0 40px rgba(255, 65, 108, 0.8);
        }

        /* 新增滑块样式 */
        .speed-slider {
            position: absolute;
            bottom: 20px;
            right: 20px;
            z-index: 50;
        }

        input[type="range"] {
            -webkit-appearance: none;
            appearance: none;
            width: 150px;
            height: 10px;
            background: #d3d3d3;
            outline: none;
            opacity: 0.7;
            -webkit-transition: .2s;
            transition: opacity .2s;
            border-radius: 5px;
        }

        input[type="range"]:hover {
            opacity: 1;
        }

        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 20px;
            height: 20px;
            background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
            cursor: pointer;
            border-radius: 50%;
        }

        input[type="range"]::-moz-range-thumb {
            width: 20px;
            height: 20px;
            background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
            cursor: pointer;
            border-radius: 50%;
        }

        /* 模式选择下拉框样式 */
        .mode-selector-dropdown {
            position: absolute;
            top: 20px;
            right: 20px;
            z-index: 50;
        }

        select {
            background: rgba(0, 0, 0, 0.4);
            color: var(--text-color);
            border: none;
            padding: 8px 20px;
            border-radius: 25px;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            min-width: 120px;
        }

        /* 统计信息样式 */
        .stats-container {
            display: flex;
            align-items: center;
            margin-top: 10px;
            color: var(--text-color);
            font-size: 18px;
        }

        .stat-item {
            margin: 0 15px;
            display: flex;
            align-items: center;
        }

        .stat-icon {
            margin-right: 5px;
            font-size: 20px;
        }

        .correct-count {
            color: var(--correct-color);
        }

        .wrong-count {
            color: var(--wrong-color);
        }

        /* 响应式调整 */
        [url=home.php?mod=space&uid=945662]@media[/url] (max-width: 768px) {
            .game-container {
                width: 95vw;
                height: 70vh;
            }

            .bottom-controls {
                bottom: 20px;
                gap: 15px;
            }

            .score-panel {
                padding: 10px 20px;
            }

            .btn {
                padding: 8px 16px;
                font-size: 16px;
            }

            .score-value {
                font-size: 24px;
            }

            .heart {
                width: 25px;
                height: 25px;
            }

            .start-button,
            .restart-button {
                font-size: 28px;
                padding: 15px 40px;
            }

            .game-over h2 {
                font-size: 48px;
            }

            .final-score {
                font-size: 36px;
            }

            .letter {
                width: 80px;
                height: 80px;
                font-size: 36px;
            }

            .mode-selector-dropdown {
                top: 10px;
                right: 10px;
            }

            .speed-slider {
                bottom: 10px;
                right: 10px;
            }

            .stats-container {
                font-size: 14px;
            }

            .stat-item {
                margin: 0 10px;
            }

            .stat-icon {
                font-size: 16px;
            }
        }
    </style>
</head>

<body>
    <div class="game-container" id="gameContainer">
        <div class="bottom-controls">
            <div class="score-panel">
                <button class="btn">分数</button>
                <span class="score-value" id="scoreValue">0</span>
                <button class="btn" id="healthLabel">血量</button>
                <div class="health-indicator" id="healthIndicator">
                    <svg class="heart" viewBox="0 0 24 24">
                        <path d="M12,21.35L10.55,20.03C5.4,15.36 2,12.28 2,8.5C2,5.42 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.42 22,8.5C22,12.28 18.6,15.36 13.45,20.03L12,21.35Z" />
                    </svg>
                    <svg class="heart" viewBox="0 0 24 24">
                        <path d="M12,21.35L10.55,20.03C5.4,15.36 2,12.28 2,8.5C2,5.42 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.42 22,8.5C22,12.28 18.6,15.36 13.45,20.03L12,21.35Z" />
                    </svg>
                    <svg class="heart" viewBox="0 0 24 24">
                        <path d="M12,21.35L10.55,20.03C5.4,15.36 2,12.28 2,8.5C2,5.42 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.42 22,8.5C22,12.28 18.6,15.36 13.45,20.03L12,21.35Z" />
                    </svg>
                </div>
            </div>
            
            <!-- 新增统计信息 -->
            <div class="stats-container">
                <div class="stat-item correct-count">
                    <i class="stat-icon fa fa-check-circle"></i>
                    <span>正确: <span id="correctCount">0</span></span>
                </div>
                <div class="stat-item wrong-count">
                    <i class="stat-icon fa fa-times-circle"></i>
                    <span>错误: <span id="wrongCount">0</span></span>
                </div>
            </div>
        </div>

        <div class="game-over" id="gameOver">
            <h2 id="gameOverTitle">游戏结束!</h2>
            <div class="final-score">你的得分: <span id="finalScore">0</span></div>
            <button class="restart-button">重新开始</button>
        </div>

        <!-- 新增滑块 -->
        <div class="speed-slider">
            <label for="speedSlider" style="color: white;">下落速度</label>
            <input type="range" id="speedSlider" min="1" max="3" value="1" step="0.1">
        </div>

        <!-- 新增模式选择下拉框 -->
        <div class="mode-selector-dropdown">
            <select id="modeSelector">
                <option value="normal">经典模式</option>
                <option value="endless">无尽模式</option>
                <option value="numbers">数字模式</option>
                <option value="numbers-endless">数字无尽模式</option>
            </select>
        </div>
    </div>

    <button class="start-button">开始游戏</button>

    <script>
        // 游戏配置
        const GAME_CONFIG = {
            letterSize: 100,
            canvasWidth: 960,
            canvasHeight: 720,
            initialSpeed: 1,
            maxSpeed: 3,
            spawnRate: 120,
            health: 3,
            colors: [
                '#4CAF50', '#2196F3', '#9C27B0', '#FF9800', '#F44336',
                '#E91E63', '#00BCD4', '#8BC34A', '#FFC107', '#FF5722'
            ],
            mathSymbols: '+-*/.', // 新增数学符号
            mathSymbolWeight: 0.2 // 数学符号出现的概率
        };

        // 游戏状态 - 添加正确和错误计数
        let gameState = {
            score: 0,
            health: GAME_CONFIG.health,
            speed: GAME_CONFIG.initialSpeed,
            letters: [],
            gameActive: false,
            spawnTimer: 0,
            currentMode: 'normal', // 'normal' 或 'endless' 或 'numbers' 或 'numbers-endless'
            userControlledSpeed: GAME_CONFIG.initialSpeed, // 用户控制的速度
            correctCount: 0, // 正确计数
            wrongCount: 0 // 错误计数
        };

        // 模式切换
        document.getElementById('modeSelector').addEventListener('change', function () {
            setGameMode(this.value);
        });

        function setGameMode(mode) {
            gameState.currentMode = mode;

            // 更新UI
            if (mode === 'endless' || mode === 'numbers-endless') {
                document.getElementById('healthLabel').style.display = 'none';
                document.getElementById('healthIndicator').style.display = 'none';
            } else {
                document.getElementById('healthLabel').style.display = 'block';
                document.getElementById('healthIndicator').style.display = 'flex';
            }

            // 更新游戏结束标题
            const titles = {
                'normal': '经典模式结束!',
                'endless': '无尽模式结束!',
                'numbers': '数字模式结束!',
                'numbers-endless': '数字无尽模式结束!'
            };
            document.getElementById('gameOverTitle').textContent = titles[mode] || '游戏结束!';
        }

        // 开始游戏
        function startGame() {
            document.querySelector('.start-button').style.display = 'none';
            document.getElementById('gameContainer').style.display = 'block';
            gameState = {
                score: 0,
                health: GAME_CONFIG.health,
                speed: GAME_CONFIG.initialSpeed,
                letters: [],
                gameActive: true,
                spawnTimer: 0,
                currentMode: gameState.currentMode,
                userControlledSpeed: GAME_CONFIG.initialSpeed,
                correctCount: 0, // 重置正确计数
                wrongCount: 0 // 重置错误计数
            };
            updateScore();
            updateHealth();
            updateStats(); // 更新统计信息
            gameLoop();
            setupKeyboardListener();
            setupSpeedSlider();
            setGameMode(gameState.currentMode); // 初始化模式
        }

        // 游戏循环
        function gameLoop() {
            if (!gameState.gameActive) return;

            // 使用用户控制的速度
            gameState.speed = gameState.userControlledSpeed;

            gameState.spawnTimer++;

            if (gameState.spawnTimer >= GAME_CONFIG.spawnRate / gameState.speed) {
                spawnLetter();
                gameState.spawnTimer = 0;
            }

            updateLetters();

            requestAnimationFrame(gameLoop);
        }

        // 生成字母
        function spawnLetter() {
            let characters;
            let isMathSymbol = false;
            
            if (gameState.currentMode === 'numbers' || gameState.currentMode === 'numbers-endless') {
                // 数字模式和数字无尽模式下,有一定概率生成数学符号
                if (Math.random() < GAME_CONFIG.mathSymbolWeight) {
                    characters = GAME_CONFIG.mathSymbols;
                    isMathSymbol = true;
                } else {
                    characters = '0123456789';
                }
            } else {
                characters = 'abcdefghijklmnopqrstuvwxyz'; // 其他模式生成字母
            }
            
            const randomChar = characters.charAt(Math.floor(Math.random() * characters.length));
            let randomColor;
            
            if (isMathSymbol) {
                // 数学符号使用特殊颜色
                randomColor = '#FFD700'; // 金色
            } else {
                randomColor = GAME_CONFIG.colors[Math.floor(Math.random() * GAME_CONFIG.colors.length)];
            }
            
            const x = Math.random() * (document.getElementById('gameContainer').offsetWidth - GAME_CONFIG.letterSize);

            const letter = {
                char: randomChar,
                x: x,
                y: -GAME_CONFIG.letterSize,
                color: randomColor,
                element: createLetterElement(randomChar, x, randomColor, isMathSymbol),
                isMathSymbol: isMathSymbol
            };

            gameState.letters.push(letter);
        }

        // 创建字母元素
        function createLetterElement(char, x, color, isMathSymbol) {
            const container = document.createElement('div');
            container.className = 'letter' + (isMathSymbol ? ' math-symbol' : '');
            container.style.left = `${x}px`;
            container.style.top = '-100px';
            container.style.backgroundColor = color;
            container.textContent = char;

            document.getElementById('gameContainer').appendChild(container);
            return container;
        }

        // 更新所有字母位置
        function updateLetters() {
            for (let i = gameState.letters.length - 1; i >= 0; i--) {
                const letter = gameState.letters[i];
                letter.y += gameState.speed;
                letter.element.style.top = `${letter.y}px`;

                if (letter.y > document.getElementById('gameContainer').offsetHeight) {
                    removeLetter(i);

                    // 只有在经典模式和数字模式下才会减少生命值
                    if (gameState.currentMode === 'normal' || gameState.currentMode === 'numbers') {
                        loseHealth();
                    }
                }
            }
        }

        // 移除字母
        function removeLetter(index) {
            const letter = gameState.letters[index];
            letter.element.remove();
            gameState.letters.splice(index, 1);
        }

        // 设置键盘监听 - 修复版本
        function setupKeyboardListener() {
            document.onkeydown = function (e) {
                // 调试输出
                console.log(`按键: ${e.key}, 按键码: ${e.keyCode}`);

                if (!gameState.gameActive) return;

                // 使用 e.key 替代 String.fromCharCode(e.which)
                const key = e.key;

                // 根据当前模式过滤按键
                let validKeys;
                if (gameState.currentMode === 'numbers' || gameState.currentMode === 'numbers-endless') {
                    // 数字模式和数字无尽模式接受数字和数学符号
                    validKeys = /^[0-9\+\-\*\/\.]$/;
                } else {
                    validKeys = /^[a-z]$/; // 其他模式接受字母键
                }
                
                // 忽略非有效键
                if (!validKeys.test(key)) {
                    console.log(`忽略非有效键: ${key}`);
                    return;
                }

                // 找到最顶部的匹配字母
                let topMostMatchIndex = -1;
                let topMostY = Infinity;

                for (let i = 0; i < gameState.letters.length; i++) {
                    if (gameState.letters[i].char === key) {
                        if (gameState.letters[i].y < topMostY) {
                            topMostY = gameState.letters[i].y;
                            topMostMatchIndex = i;
                        }
                    }
                }

                // 如果找到匹配的字母,处理它
                if (topMostMatchIndex !== -1) {
                    console.log(`匹配成功: 按键=${key}, 字母=${gameState.letters[topMostMatchIndex].char}, 位置=${topMostMatchIndex}`);

                    // 数学符号得分加倍
                    const scoreValue = gameState.letters[topMostMatchIndex].isMathSymbol ? 20 : 10;
                    
                    shatterLetter(gameState.letters[topMostMatchIndex]);
                    gameState.score += scoreValue;
                    gameState.correctCount++; // 增加正确计数
                    updateScore();
                    updateStats(); // 更新统计信息

                    setTimeout(() => {
                        removeLetter(topMostMatchIndex);
                    }, 500);
                } else {
                    console.log(`匹配失败: 按键=${key}, 当前字母=${gameState.letters.map(l => l.char)}`);
                    gameState.wrongCount++; // 增加错误计数
                    updateStats(); // 更新统计信息
                }
            };
        }

        // 更新分数显示
        function updateScore() {
            document.getElementById('scoreValue').textContent = gameState.score;
        }

        // 更新统计信息显示
        function updateStats() {
            document.getElementById('correctCount').textContent = gameState.correctCount;
            document.getElementById('wrongCount').textContent = gameState.wrongCount;
        }

        // 减少生命值
        function loseHealth() {
            // 无尽模式和数字无尽模式不减少生命值
            if (gameState.currentMode === 'endless' || gameState.currentMode === 'numbers-endless') return;

            gameState.health--;
            updateHealth();

            if (gameState.health <= 0) {
                endGame();
            }
        }

        // 更新生命值显示
        function updateHealth() {
            // 无尽模式和数字无尽模式不显示生命值
            if (gameState.currentMode === 'endless' || gameState.currentMode === 'numbers-endless') return;

            const hearts = document.querySelectorAll('.heart');
            hearts.forEach((heart, index) => {
                if (index < gameState.health) {
                    heart.classList.remove('lost');
                } else {
                    heart.classList.add('lost');
                }
            });
        }

        // 游戏结束
        function endGame() {
            gameState.gameActive = false;
            document.getElementById('finalScore').textContent = gameState.score;
            document.getElementById('gameOver').classList.add('visible');
        }

        // 重新开始游戏
        function restartGame() {
            gameState.letters.forEach(letter => {
                letter.element.remove();
            });

            document.getElementById('gameOver').classList.remove('visible');
            startGame();
        }

        // 初始化游戏模式
        setGameMode('normal');

        // 设置滑块监听
        function setupSpeedSlider() {
            const speedSlider = document.getElementById('speedSlider');
            speedSlider.value = gameState.userControlledSpeed;
            speedSlider.addEventListener('input', function () {
                gameState.userControlledSpeed = parseFloat(this.value);
                gameState.speed = gameState.userControlledSpeed; // 立即应用速度变化
            });
        }

        // 击碎字母效果
        function shatterLetter(letter) {
            letter.element.classList.add('hit');
            const numFragments = 10;
            for (let i = 0; i < numFragments; i++) {
                const fragment = document.createElement('div');
                fragment.className = 'fragment';
                fragment.style.left = `${letter.x + GAME_CONFIG.letterSize / 2 - 5}px`;
                fragment.style.top = `${letter.y + GAME_CONFIG.letterSize / 2 - 5}px`;
                fragment.style.backgroundColor = letter.color;

                const angle = (i / numFragments) * 360;
                const distance = Math.random() * 100 + 50;
                const x = Math.cos(angle * (Math.PI / 180)) * distance;
                const y = Math.sin(angle * (Math.PI / 180)) * distance;
                fragment.style.setProperty('--x', `${x}px`);
                fragment.style.setProperty('--y', `${y}px`);

                document.getElementById('gameContainer').appendChild(fragment);

                setTimeout(() => {
                    fragment.remove();
                }, 500);
            }
        }
    </script>
</body>

</html>
jinqiaoa1a 发表于 2025-5-15 06:47
alidadai 发表于 2025-5-15 06:57
感谢大佬的资源,感谢大佬的故事,有点想笑
冬天冷了多穿点 发表于 2025-5-15 07:20
感谢分享 哈哈哈
moyc 发表于 2025-5-15 07:31
好玩,喜欢
ljk199 发表于 2025-5-15 07:50
我怎么打不开,浏览器要怎么设置吗?
applepv 发表于 2025-5-15 07:50
当小游戏玩玩,,,还是挺不错的
ahehaoyu 发表于 2025-5-15 07:58
怎么每次输入到最后一两个字的时候就结束了? 是错的太多了吗
kenkenss 发表于 2025-5-15 08:11
感谢分享,挺好的。
Uwa 发表于 2025-5-15 08:13
感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-15 01:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表