🎮ArcadeLab

幼儿认知分类小游戏

by SilverPirate44
297 lines13.9 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>幼儿认知分类小游戏</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Microsoft Yahei", sans-serif; }
        body { background-color: #e6f7ff; padding: 20px; user-select: none; overflow: hidden; }
        .container { max-width: 900px; margin: 0 auto; text-align: center; position: relative; z-index: 10; }
        h1 { color: #ff6688; font-size: 36px; margin-bottom: 10px; margin-top: 20px; }
        .tip-text { font-size: 28px; color: #333; margin-bottom: 30px; font-weight: bold; }
        .level-text { color: #ff9900; font-size: 32px; }
        .game-board { display: flex; flex-wrap: wrap; justify-content: center; gap: 30px; min-height: 400px; align-items: center; }
        .item { width: 140px; height: 140px; cursor: pointer; transition: transform 0.2s ease; position: relative; background: #fff; border-radius: 20px; box-shadow: 0 6px 15px rgba(0,0,0,0.1); display: flex; justify-content: center; align-items: center; font-size: 80px; }
        
        .item.correct-click { transform: scale(1.15); pointer-events: none; }
        .item.correct-click { box-shadow: 0 0 25px #ffdd00, 0 0 50px #ffaa00; background: #fffcf0; }
        
        @keyframes shake {
            0%,100% { transform: translateX(0); }
            25% { transform: translateX(-10px); }
            75% { transform: translateX(10px); }
        }
        .item.wrong-click { animation: shake 0.4s ease; }
        
        .star { position: absolute; top: -15px; right: -15px; font-size: 45px; display: none; animation: pop 0.3s ease; }
        .item.correct-click .star { display: block; }
        @keyframes pop { 0% { transform: scale(0); } 100% { transform: scale(1); } }

        .float-tip { position: fixed; left: 50%; top: 40%; transform: translate(-50%, -50%); font-size: 46px; font-weight: bold; z-index: 50; animation: floatUp 1.2s ease forwards; pointer-events: none; text-shadow: 2px 2px 4px rgba(0,0,0,0.2); }
        .tip-good { color: #28b948; }
        .tip-bad { color: #ff3333; }
        @keyframes floatUp { 0% { opacity: 1; transform: translate(-50%, -50%) scale(1); } 100% { opacity: 0; transform: translate(-50%, -100%) scale(1.2); } }

        .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 999; display: none; }
        .modal-box { background: #fff; padding: 50px; border-radius: 30px; text-align: center; box-shadow: 0 10px 30px rgba(0,0,0,0.3); }
        .modal-box h2 { font-size: 40px; color: #22bb55; margin-bottom: 30px; }
        button { padding: 15px 40px; font-size: 26px; border: none; background: #4285f4; color: white; border-radius: 15px; cursor: pointer; font-weight: bold; transition: 0.2s; }
        button:hover { background: #2b6ed9; transform: scale(1.05); }

        /* 彩带画布 */
        #confettiCanvas { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 100; }
    </style>
</head>
<body>
    <!-- 彩带容器 -->
    <canvas id="confettiCanvas"></canvas>

    <div class="container">
        <h1>🎈幼儿认知分类小游戏</h1>
        <div class="tip-text" id="levelTip"></div>
        <div class="game-board" id="gameBoard"></div>
    </div>

    <div class="modal" id="passModal">
        <div class="modal-box">
            <h2 id="modalTitle">🎉太棒啦!通关成功!</h2>
            <button id="nextBtn">下一关</button>
        </div>
    </div>

    <script>
        // ==== 🔊 音频合成器 ====
        let audioCtx;
        function initAudio() {
            if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            if(audioCtx.state === 'suspended') audioCtx.resume();
        }

        function playCorrectSound() {
            initAudio();
            const osc = audioCtx.createOscillator();
            const gainNode = audioCtx.createGain();
            osc.type = 'sine';
            osc.frequency.setValueAtTime(880, audioCtx.currentTime);
            osc.frequency.exponentialRampToValueAtTime(1760, audioCtx.currentTime + 0.1);
            gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime);
            gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.4);
            osc.connect(gainNode); gainNode.connect(audioCtx.destination);
            osc.start(); osc.stop(audioCtx.currentTime + 0.4);
        }

        function playWrongSound() {
            initAudio();
            const osc = audioCtx.createOscillator();
            const gainNode = audioCtx.createGain();
            osc.type = 'sawtooth';
            osc.frequency.setValueAtTime(150, audioCtx.currentTime);
            osc.frequency.linearRampToValueAtTime(100, audioCtx.currentTime + 0.3);
            gainNode.gain.setValueAtTime(0.3, audioCtx.currentTime);
            gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
            osc.connect(gainNode); gainNode.connect(audioCtx.destination);
            osc.start(); osc.stop(audioCtx.currentTime + 0.3);
        }

        // 🎉 胜利专属音效(欢快的琶音)
        function playWinSound() {
            initAudio();
            const notes = [523.25, 659.25, 783.99, 1046.50]; // C5, E5, G5, C6
            notes.forEach((freq, index) => {
                setTimeout(() => {
                    const osc = audioCtx.createOscillator();
                    const gainNode = audioCtx.createGain();
                    osc.type = 'triangle';
                    osc.frequency.setValueAtTime(freq, audioCtx.currentTime);
                    gainNode.gain.setValueAtTime(0.4, audioCtx.currentTime);
                    gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
                    osc.connect(gainNode); gainNode.connect(audioCtx.destination);
                    osc.start(); osc.stop(audioCtx.currentTime + 0.3);
                }, index * 150); // 每个音符间隔0.15秒
            });
        }

        // ==== 🎊 彩带特效逻辑 ====
        function createConfetti() {
            const canvas = document.getElementById('confettiCanvas');
            const ctx = canvas.getContext('2d');
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;

            const confettiCount = 200; // 彩带数量
            const colors = ['#ff595e', '#ffca3a', '#8ac926', '#1982c4', '#6a4c93'];
            let confettis = [];

            for (let i = 0; i < confettiCount; i++) {
                confettis.push({
                    x: Math.random() * canvas.width,
                    y: Math.random() * canvas.height - canvas.height,
                    w: Math.random() * 10 + 5,
                    h: Math.random() * 10 + 5,
                    color: colors[Math.floor(Math.random() * colors.length)],
                    speedY: Math.random() * 3 + 2,
                    speedX: Math.random() * 2 - 1,
                    rot: Math.random() * 360,
                    rotSpeed: Math.random() * 5 - 2.5
                });
            }

            function updateConfetti() {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                let active = false;

                confettis.forEach(c => {
                    c.y += c.speedY;
                    c.x += c.speedX;
                    c.rot += c.rotSpeed;

                    if (c.y < canvas.height) active = true;

                    ctx.save();
                    ctx.translate(c.x, c.y);
                    ctx.rotate(c.rot * Math.PI / 180);
                    ctx.fillStyle = c.color;
                    ctx.fillRect(-c.w / 2, -c.h / 2, c.w, c.h);
                    ctx.restore();
                });

                if (active) {
                    requestAnimationFrame(updateConfetti);
                } else {
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                }
            }
            updateConfetti();
        }

        // ==== 🎮 游戏主逻辑 ====
        const pool = {
            fruits: ["🍎", "🍌", "🍇", "🍓", "🍉", "🍊", "🍒", "🥝", "🍍", "🍑", "🍐", "🍋", "🥥", "🥭"],
            animals: ["🐱", "🐶", "🐰", "🐼", "🐯", "🦁", "🐸", "🐵", "🐷", "🐮", "🐔", "🦊", "🐻", "🐨"],
            vehicles: ["🚗", "🚌", "✈️", "🚲", "🚂", "🚀", "🚁", "🚢", "🚕", "🏎️", "🛵", "🚓", "🚑", "🚒"]
        };

        const levelsConfig = [
            { title: "请点击所有的【水果】🍎", rightType: "fruits", wrongType: "animals" },
            { title: "请点击所有的【动物】🐱", rightType: "animals", wrongType: "vehicles" },
            { title: "请点击所有的【交通工具】🚗", rightType: "vehicles", wrongType: "fruits" }
        ];

        let currentLevel = 0;
        let correctCount = 0;
        let totalRight = 0;
        
        const gameBoard = document.getElementById("gameBoard");
        const levelTip = document.getElementById("levelTip");
        const passModal = document.getElementById("passModal");
        const nextBtn = document.getElementById("nextBtn");
        const modalTitle = document.getElementById("modalTitle");

        function shuffle(array) {
            let currentIndex = array.length, randomIndex;
            while (currentIndex != 0) {
                randomIndex = Math.floor(Math.random() * currentIndex);
                currentIndex--;
                [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
            }
            return array;
        }

        function getRandomItems(arr, count) {
            let shuffled = shuffle([...arr]);
            return shuffled.slice(0, count);
        }

        function showFloatText(text, type) {
            const div = document.createElement("div");
            div.innerText = text;
            div.className = "float-tip " + type;
            document.body.appendChild(div);
            setTimeout(()=>div.remove(), 1200);
        }

        function loadLevel() {
            const config = levelsConfig[currentLevel];
            // 显示关卡号
            levelTip.innerHTML = `<span class="level-text">第 ${currentLevel + 1} 关</span><br>${config.title}`;
            
            gameBoard.innerHTML = "";
            correctCount = 0;
            
            const rightItems = getRandomItems(pool[config.rightType], 3).map(e => ({emoji: e, isRight: true}));
            const wrongItems = getRandomItems(pool[config.wrongType], 3).map(e => ({emoji: e, isRight: false}));
            
            const currentItems = shuffle([...rightItems, ...wrongItems]);
            totalRight = rightItems.length;
            passModal.style.display = "none";

            currentItems.forEach(item => {
                const div = document.createElement("div");
                div.className = "item";
                div.innerText = item.emoji;

                const star = document.createElement("span");
                star.innerText = "⭐";
                star.className = "star";
                div.appendChild(star);

                div.onclick = () => {
                    if(div.classList.contains("correct-click")) return;
                    
                    if(item.isRight) {
                        playCorrectSound();
                        div.classList.add("correct-click");
                        correctCount++;
                        showFloatText("太棒啦!", "tip-good");
                        
                        if(correctCount >= totalRight) {
                            setTimeout(()=> {
                                passModal.style.display = "flex";
                                if(currentLevel === levelsConfig.length - 1) {
                                    // 第三关(最后一关)通关!
                                    modalTitle.innerText = "🎉全部通关!你太厉害了!";
                                    nextBtn.innerText = "再玩一次";
                                    playWinSound(); // 播放胜利音效
                                    createConfetti(); // 播放彩带
                                } else {
                                    modalTitle.innerText = "🎉太棒啦!通关成功!";
                                    nextBtn.innerText = "进入下一关";
                                }
                            }, 600);
                        }
                    } else {
                        playWrongSound();
                        div.classList.add("wrong-click");
                        showFloatText("再试一试哦~", "tip-bad");
                        setTimeout(()=> div.classList.remove("wrong-click"), 400);
                    }
                };
                gameBoard.appendChild(div);
            });
        }

        nextBtn.onclick = () => {
            if(currentLevel < levelsConfig.length - 1) {
                currentLevel++;
            } else {
                currentLevel = 0; // 重新开始
                // 如果是重新开始,清理彩带
                const canvas = document.getElementById('confettiCanvas');
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            }
            loadLevel();
        };

        // 窗口大小改变时调整彩带画布
        window.addEventListener('resize', () => {
            const canvas = document.getElementById('confettiCanvas');
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        });

        loadLevel();
    </script>
</body>
</html>

Game Source: 幼儿认知分类小游戏

Creator: SilverPirate44

Libraries: none

Complexity: complex (297 lines, 13.9 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-silverpirate44" to link back to the original. Then publish at arcadelab.ai/publish.