横评报告大模型

同题横评:做一个网页版的消消乐小游戏,要果冻的效果,颜色要果糖色

…

结论速览

> 本报告由「AI 大众点评 · 同题横评工作台」自动生成,同一任务并发调用多家大模型后对比输出。

本次横评产品(4)

# 同题横评# 通义千问# Kimi# DeepSeek# 智谱 GLM

横评任务

做一个网页版的消消乐小游戏,要果冻的效果,颜色要果糖色
冠军Kimi6.8综合分 / 10
亚军DeepSeek5.9综合分 / 10
季军通义千问4.1综合分 / 10
第 4 名智谱 GLM2.6综合分 / 10
综合分 6.8 5.9 4.1 2.6
质量分 9.0 5.8 4.8 0.0
性能分 1.5 6.1 2.5 8.8
正确性/可运行性 7.5 6.0 6.0 0.0
逻辑性 10.0 5.5 5.0 0.0
完整性 10.0 6.0 2.5 0.0
稳定性 7.5 6.0 6.0 0.0
风格 10.0 5.5 5.0 0.0
效率 10.0 6.0 2.5 0.0
响应耗时 105.1s 23.8s 134.3s 29.4s
Token(入/出) 23 / 7287 23 / 6243 27 / 6090 23 / 632
调用费用 ¥0.12 ¥0.01 ¥0.01 免费

高亮为该指标最优值。综合分 = 质量分 × 70% + 性能分 × 30%;性能分 = 速度 45% + Token 效率 40% + 费用 15%(费用项最高 8 分);质量分为六维人工打分加权(正确性/可运行性 30% + 逻辑性 25% + 完整性 20% + 稳定性 10% + 风格 10% + 效率 5%)。输出被截断或可运行性 ≤ 2 时,综合分封顶 4.0。

输出对比

产物可直接在线试玩(等比缩放),下方仅展示实现要点,完整源码默认折叠。

1Kimi6.8
点击放大试玩在线试玩
查看完整源码
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Jelly Crush - 果冻消消乐</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
    <link href="https://fonts.googleapis.com/css2?family=Fredoka+One&family=Varela+Round&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Varela Round', sans-serif;
            background-color: #FFF5F7;
            background-image: radial-gradient(#FFD1DC 1px, transparent 1px), radial-gradient(#FFD1DC 1px, transparent 1px);
            background-size: 20px 20px;
            background-position: 0 0, 10px 10px;
            overflow: hidden;
            touch-action: none; /* Prevent scrolling while dragging */
        }

        h1, h2, .score-text {
            font-family: 'Fredoka One', cursive;
        }

        /* Jelly Cube Styling */
        .jelly {
            width: 100%;
            height: 100%;
            border-radius: 35%; /* Soft rounded squares */
            position: relative;
            cursor: pointer;
            transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            box-shadow: 
                inset 0 0 20px rgba(255,255,255,0.5),
                inset 0 0 5px rgba(255,255,255,0.9),
                0 5px 10px rgba(0,0,0,0.1),
                0 10px 20px rgba(0,0,0,0.05);
            z-index: 10;
        }

        /* Inner shine for 3D effect */
        .jelly::after {
            content: '';
            position: absolute;
            top: 10%;
            left: 15%;
            width: 25%;
            height: 15%;
            border-radius: 50%;
            background: rgba(255,255,255,0.7);
            filter: blur(1px);
            transform: rotate(-45deg);
        }

        /* Specific Colors */
        .color-strawberry { background: linear-gradient(135deg, #FF9A9E 0%, #FECFEF 100%); }
        .color-lemon { background: linear-gradient(135deg, #f6d365 0%, #fda085 100%); }
        .color-mint { background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%); }
        .color-blueberry { background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%); }
        .color-grape { background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%); }
        .color-orange { background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 99%, #fecfef 100%); } /* Adjusted to be more orange */
        .color-orange { background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%); }

        /* Animations */
        @keyframes popIn {
            0% { transform: scale(0); opacity: 0; }
            70% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(1); opacity: 1; }
        }

        @keyframes jellyWobble {
            0% { transform: scale(1, 1); }
            30% { transform: scale(1.25, 0.75); }
            40% { transform: scale(0.75, 1.25); }
            50% { transform: scale(1.15, 0.85); }
            65% { transform: scale(0.95, 1.05); }
            75% { transform: scale(1.05, 0.95); }
            100% { transform: scale(1, 1); }
        }

        @keyframes floatUp {
            0% { transform: translateY(0) scale(1); opacity: 1; }
            100% { transform: translateY(-50px) scale(1.5); opacity: 0; }
        }

        .animate-pop { animation: popIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; }
        .animate-wobble { animation: jellyWobble 0.6s both; }
        .animate-match { animation: popIn 0.2s reverse forwards; }

        /* Selected State */
        .selected .jelly {
            transform: scale(1.15);
            box-shadow: 
                inset 0 0 20px rgba(255,255,255,0.8),
                0 0 15px rgba(255,255,255,0.8),
                0 0 30px currentColor;
            z-index: 20;
            filter: brightness(1.1);
        }

        /* Grid Container */
        #game-grid {
            display: grid;
            grid-template-columns: repeat(6, 1fr);
            grid-template-rows: repeat(6, 1fr);
            gap: 8px;
            width: 100%;
            max-width: 500px;
            aspect-ratio: 1;
            margin: 0 auto;
            padding: 10px;
            background: rgba(255, 255, 255, 0.4);
            border-radius: 20px;
            box-shadow: inset 0 0 20px rgba(0,0,0,0.05);
            backdrop-filter: blur(5px);
        }

        .cell {
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            position: relative;
        }

        /* Particle Canvas */
        #particles {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 50;
        }

        /* UI Elements */
        .glass-panel {
            background: rgba(255, 255, 255, 0.7);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            border: 2px solid rgba(255, 255, 255, 0.9);
            box-shadow: 0 10px 30px rgba(0,0,0,0.05);
        }

        .btn-primary {
            background: linear-gradient(45deg, #FF9A9E, #FECFEF);
            border: none;
            color: white;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
            transition: all 0.2s;
        }
        .btn-primary:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(255, 154, 158, 0.4);
        }
        .btn-primary:active {
            transform: translateY(1px);
        }

    </style>
</head>
<body class="h-screen w-screen flex flex-col items-center justify-center text-gray-700 select-none">

    <!-- Background Particles -->
    <canvas id="particles"></canvas>

    <!-- Header -->
    <div class="w-full max-w-md px-4 mb-4 flex justify-between items-center z-10">
        <div class="glass-panel px-6 py-3 flex flex-col items-center">
            <span class="text-xs uppercase tracking-widest text-pink-400 font-bold">分数</span>
            <span id="score" class="score-text text-3xl text-gray-800 leading-none">0</span>
        </div>
        <div class="text-center">
            <h1 class="text-4xl text-transparent bg-clip-text bg-gradient-to-r from-pink-400 to-purple-400 drop-shadow-sm">Jelly Crush</h1>
        </div>
        <div class="glass-panel px-6 py-3 flex flex-col items-center">
            <span class="text-xs uppercase tracking-widest text-blue-400 font-bold">时间</span>
            <span id="timer" class="score-text text-3xl text-gray-800 leading-none">60</span>
        </div>
    </div>

    <!-- Game Area -->
    <div class="relative w-full max-w-lg px-4 z-10">
        <div id="game-grid">
            <!-- Grid generated by JS -->
        </div>
        
        <!-- Start Overlay -->
        <div id="start-overlay" class="absolute inset-0 bg-white/80 backdrop-blur-sm rounded-3xl flex flex-col items-center justify-center z-50">
            <div class="text-6xl mb-4 animate-bounce">🍬</div>
            <h2 class="text-3xl text-pink-500 mb-2">准备好了吗?</h2>
            <p class="text-gray-500 mb-6 text-sm">交换果冻,凑齐3个或更多!</p>
            <button id="start-btn" class="btn-primary px-8 py-3 rounded-full text-xl font-bold shadow-lg">开始游戏</button>
        </div>

        <!-- Game Over Overlay -->
        <div id="game-over-overlay" class="hidden absolute inset-0 bg-white/90 backdrop-blur-md rounded-3xl flex flex-col items-center justify-center z-50">
            <h2 class="text-4xl text-purple-500 mb-2">时间到!</h2>
            <div class="text-6xl mb-4">✨</div>
            <p class="text-gray-600 mb-2">最终得分</p>
            <p id="final-score" class="text-5xl font-bold text-gray-800 mb-8">0</p>
            <button id="restart-btn" class="btn-primary px-8 py-3 rounded-full text-xl font-bold shadow-lg">再玩一次</button>
        </div>
    </div>

    <!-- Footer Controls -->
    <div class="mt-6 z-10 flex gap-4">
        <button id="sound-toggle" class="glass-panel p-3 rounded-full hover:bg-white transition-colors">
            🔊
        </button>
        <button id="shuffle-btn" class="glass-panel px-4 py-2 rounded-full text-sm font-bold text-gray-500 hover:text-pink-500 transition-colors">
            重置版面 (-50分)
        </button>
    </div>

    <script>
        // --- Configuration ---
        const GRID_SIZE = 6;
        const COLORS = [
            { name: 'strawberry', class: 'color-strawberry', hex: '#FF9A9E' },
            { name: 'lemon', class: 'color-lemon', hex: '#f6d365' },
            { name: 'mint', class: 'color-mint', hex: '#84fab0' },
            { name: 'blueberry', class: 'color-blueberry', hex: '#a18cd1' },
            { name: 'orange', class: 'color-orange', hex: '#fcb69f' }
        ];
        
        // --- State ---
        let grid = []; // 2D array storing color indices
        let score = 0;
        let timeLeft = 60;
        let timerInterval;
        let selectedCell = null; // {r, c}
        let isProcessing = false;
        let isSoundOn = true;
        let isGameActive = false;

        // --- DOM Elements ---
        const gridEl = document.getElementById('game-grid');
        const scoreEl = document.getElementById('score');
        const timerEl = document.getElementById('timer');
        const startOverlay = document.getElementById('start-overlay');
        const gameOverOverlay = document.getElementById('game-over-overlay');
        const finalScoreEl = document.getElementById('final-score');
        const startBtn = document.getElementById('start-btn');
        const restartBtn = document.getElementById('restart-btn');
        const soundBtn = document.getElementById('sound-toggle');
        const shuffleBtn = document.getElementById('shuffle-btn');

        // --- Audio Setup (Tone.js) ---
        let synth, membrane, metal;
        
        async function initAudio() {
            await Tone.start();
            
            // Synth for matching sounds (cute plucks)
            synth = new Tone.PolySynth(Tone.Synth, {
                oscillator: { type: "triangle" },
                envelope: { attack: 0.02, decay: 0.1, sustain: 0.1, release: 0.5 }
            }).toDestination();
            synth.volume.value = -10;

            // Membrane for "pop" sounds
            membrane = new Tone.MembraneSynth().toDestination();
            membrane.volume.value = -15;

            // Metal for selection
            metal = new Tone.MetalSynth({
                frequency: 200, envelope: { attack: 0.001, decay: 0.1, release: 0.01 },
                harmonicity: 5.1, modulationIndex: 32, resonance: 4000, octaves: 1.5
            }).toDestination();
            metal.volume.value = -20;
        }

        function playSound(type) {
            if (!isSoundOn || !synth) return;
            
            switch(type) {
                case 'select':
                    metal.triggerAttackRelease("C6", "32n");
                    break;
                case 'swap':
                    membrane.triggerAttackRelease("C2", "32n");
                    break;
                case 'match3':
                    synth.triggerAttackRelease(["C5", "E5"], "16n");
                    break;
                case 'match4':
                    synth.triggerAttackRelease(["C5", "E5", "G5"], "16n");
                    break;
                case 'match5':
                    synth.triggerAttackRelease(["C5", "E5", "G5", "C6"], "8n");
                    break;
                case 'bad':
                    membrane.triggerAttackRelease("A1", "16n");
                    break;
                case 'fall':
                    // Random light plinks
                    const notes = ["C6", "D6", "E6", "G6"];
                    const note = notes[Math.floor(Math.random() * notes.length)];
                    synth.triggerAttackRelease(note, "32n", Tone.now(), 0.5);
                    break;
            }
        }

        // --- Game Logic ---

        function initGame() {
            score = 0;
            timeLeft = 60;
            updateScore(0);
            updateTimer();
            
            // Initialize grid without matches
            do {
                fillGridRandom();
            } while (findMatches().length > 0);

            renderGrid();
            startTimer();
            isGameActive = true;
            isProcessing = false;
        }

        function fillGridRandom() {
            grid = [];
            for (let r = 0; r < GRID_SIZE; r++) {
                let row = [];
                for (let c = 0; c < GRID_SIZE; c++) {
                    row.push(Math.floor(Math.random() * COLORS.length));
                }
                grid.push(row);
            }
        }

        function renderGrid() {
            gridEl.innerHTML = '';
            for (let r = 0; r < GRID_SIZE; r++) {
                for (let c = 0; c < GRID_SIZE; c++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell';
                    cell.dataset.r = r;
                    cell.dataset.c = c;
                    
                    const jelly = document.createElement('div');
                    const colorIdx = grid[r][c];
                    jelly.className = `jelly ${COLORS[colorIdx].class} animate-pop`;
                    jelly.style.animationDelay = `${(r * GRID_SIZE + c) * 0.02}s`;
                    
                    cell.appendChild(jelly);
                    cell.addEventListener('click', () => handleCellClick(r, c));
                    gridEl.appendChild(cell);
                }
            }
        }

        function updateCell(r, c) {
            const cell = document.querySelector(`.cell[data-r="${r}"][data-c="${c}"]`);
            if (cell) {
                const jelly = cell.querySelector('.jelly');
                const colorIdx = grid[r][c];
                // Reset classes
                jelly.className = `jelly ${COLORS[colorIdx].class} animate-pop`;
            }
        }

        function handleCellClick(r, c) {
            if (!isGameActive || isProcessing) return;

            const clickedCell = document.querySelector(`.cell[data-r="${r}"][data-c="${c}"]`);

            // If nothing selected, select this
            if (!selectedCell) {
                selectedCell = { r, c, el: clickedCell };
                clickedCell.classList.add('selected');
                playSound('select');
                return;
            }

            // If clicked same cell, deselect
            if (selectedCell.r === r && selectedCell.c === c) {
                selectedCell.el.classList.remove('selected');
                selectedCell = null;
                return;
            }

            // Check adjacency
            const dr = Math.abs(selectedCell.r - r);
            const dc = Math.abs(selectedCell.c - c);
            
            if (dr + dc === 1) {
                // Valid swap attempt
                swapJellies(selectedCell, { r, c, el: clickedCell });
            } else {
                // Invalid, select new
                selectedCell.el.classList.remove('selected');
                selectedCell = { r, c, el: clickedCell };
                clickedCell.classList.add('selected');
                playSound('select');
            }
        }

        async function swapJellies(cell1, cell2) {
            isProcessing = true;
            playSound('swap');

            // Visual Swap (Simple transform approach for smoother feel, or re-render)
            // Here we swap data first, update visual, then check.
            
            // Temporarily swap in data
            let temp = grid[cell1.r][cell1.c];
            grid[cell1.r][cell1.c] = grid[cell2.r][cell2.c];
            grid[cell2.r][cell2.c] = temp;

            // Update Visuals immediately
            updateCell(cell1.r, cell1.c);
            updateCell(cell2.r, cell2.c);

            // Remove selection
            cell1.el.classList.remove('selected');
            selectedCell = null;

            // Check matches
            const matches = findMatches();

            if (matches.length > 0) {
                await processMatches(matches);
            } else {
                // Swap back if no match
                await new Promise(r => setTimeout(r, 200));
                playSound('bad');
                
                // Swap back data
                temp = grid[cell1.r][cell1.c];
                grid[cell1.r][cell1.c] = grid[cell2.r][cell2.c];
                grid[cell2.r][cell2.c] = temp;

                // Shake animation
                const j1 = cell1.el.querySelector('.jelly');
                const j2 = cell2.el.querySelector('.jelly');
                j1.classList.add('animate-wobble');
                j2.classList.add('animate-wobble');

                updateCell(cell1.r, cell1.c);
                updateCell(cell2.r, cell2.c);
                
                setTimeout(() => {
                    j1.classList.remove('animate-wobble');
                    j2.classList.remove('animate-wobble');
                    isProcessing = false;
                }, 500);
            }
        }

        function findMatches() {
            let matchedSet = new Set();

            // Horizontal
            for (let r = 0; r < GRID_SIZE; r++) {
                for (let c = 0; c < GRID_SIZE - 2; c++) {
                    let color = grid[r][c];
                    if (color === -1) continue; // Empty
                    if (grid[r][c+1] === color && grid[r][c+2] === color) {
                        matchedSet.add(`${r},${c}`);
                        matchedSet.add(`${r},${c+1}`);
                        matchedSet.add(`${r},${c+2}`);
                        // Check for 4 or 5
                        if (c+3 < GRID_SIZE && grid[r][c+3] === color) {
                            matchedSet.add(`${r},${c+3}`);
                            if (c+4 < GRID_SIZE && grid[r][c+4] === color) {
                                matchedSet.add(`${r},${c+4}`);
                            }
                        }
                    }
                }
            }

            // Vertical
            for (let c = 0; c < GRID_SIZE; c++) {
                for (let r = 0; r < GRID_SIZE - 2; r++) {
                    let color = grid[r][c];
                    if (color === -1) continue;
                    if (grid[r+1][c] === color && grid[r+2][c] === color) {
                        matchedSet.add(`${r},${c}`);
                        matchedSet.add(`${r+1},${c}`);
                        matchedSet.add(`${r+2},${c}`);
                         // Check for 4 or 5
                         if (r+3 < GRID_SIZE && grid[r+3][c] === color) {
                            matchedSet.add(`${r+3},${c}`);
                            if (r+4 < GRID_SIZE && grid[r+4][c] === color) {
                                matchedSet.add(`${r+4},${c}`);
                            }
                        }
                    }
                }
            }

            return Array.from(matchedSet).map(str => {
                const [r, c] = str.split(',').map(Number);
                return { r, c, color: grid[r][c] };
            });
        }

        async function processMatches(matches) {
            // 1. Score & Sound
            const points = matches.length * 10 + (matches.length > 3 ? (matches.length - 3) * 20 : 0);
            updateScore(score + points);
            
            if (matches.length >= 5) playSound('match5');
            else if (matches.length >= 4) playSound('match4');
            else playSound('match3');

            // 2. Particle Effects
            matches.forEach(m => {
                const cell = document.querySelector(`.cell[data-r="${m.r}"][data-c="${m.c}"]`);
                const rect = cell.getBoundingClientRect();
                const centerX = rect.left + rect.width / 2;
                const centerY = rect.top + rect.height / 2;
                createParticles(centerX, centerY, COLORS[m.color].hex);
            });

            // 3. Remove Visuals
            matches.forEach(m => {
                const cell = document.querySelector(`.cell[data-r="${m.r}"][data-c="${m.c}"]`);
                const jelly = cell.querySelector('.jelly');
                jelly.style.transform = "scale(0)";
                jelly.style.opacity = "0";
            });

            await new Promise(r => setTimeout(r, 300));

            // 4. Update Logic Grid (Set to -1)
            matches.forEach(m => grid[m.r][m.c] = -1);

            // 5. Drop Down
            await dropJellies();

            // 6. Fill Top
            fillTop();

            // 7. Re-render new ones
            // We need to re-render the whole grid or just the changed ones. 
            // For simplicity in this vanilla approach, we can re-render or target specific cells.
            // Let's update specific cells for animation.
            for(let r=0; r<GRID_SIZE; r++) {
                for(let c=0; c<GRID_SIZE; c++) {
                    if(grid[r][c] !== -1) {
                        updateCell(r, c);
                    }
                }
            }

            // 8. Check for cascading matches
            const newMatches = findMatches();
            if (newMatches.length > 0) {
                await new Promise(r => setTimeout(r, 300));
                await processMatches(newMatches);
            } else {
                isProcessing = false;
            }
        }

        async function dropJellies() {
            // Logic: For each column, move non -1 items to bottom
            for (let c = 0; c < GRID_SIZE; c++) {
                let col = [];
                for (let r = 0; r < GRID_SIZE; r++) {
                    if (grid[r][c] !== -1) col.push(grid[r][c]);
                }
                // Fill top with -1
                while (col.length < GRID_SIZE) {
                    col.unshift(-1);
                }
                // Put back
                for (let r = 0; r < GRID_SIZE; r++) {
                    grid[r][c] = col[r];
                }
            }
            playSound('fall');
        }

        function fillTop() {
            for (let c = 0; c < GRID_SIZE; c++) {
                for (let r = 0; r < GRID_SIZE; r++) {
                    if (grid[r][c] === -1) {
                        grid[r][c] = Math.floor(Math.random() * COLORS.length);
                    }
                }
            }
        }

        function updateScore(newScore) {
            score = newScore;
            scoreEl.innerText = score;
            
            // Pop animation for score
            scoreEl.style.transform = "scale(1.5)";
            scoreEl.style.color = "#FF69B4";
            setTimeout(() => {
                scoreEl.style.transform = "scale(1)";
                scoreEl.style.color = "#1F2937";
            }, 200);
        }

        function startTimer() {
            clearInterval(timerInterval);
            timerInterval = setInterval(() => {
                timeLeft--;
                updateTimer();
                if (timeLeft <= 0) {
                    endGame();
                }
            }, 1000);
        }

        function updateTimer() {
            timerEl.innerText = timeLeft;
            if (timeLeft <= 10) {
                timerEl.classList.add('text-red-500');
                timerEl.classList.add('animate-pulse');
            } else {
                timerEl.classList.remove('text-red-500');
                timerEl.classList.remove('animate-pulse');
            }
        }

        function endGame() {
            clearInterval(timerInterval);
            isGameActive = false;
            finalScoreEl.innerText = score;
            gameOverOverlay.classList.remove('hidden');
        }

        // --- Particle System ---
        const canvas = document.getElementById('particles');
        const ctx = canvas.getContext('2d');
        let particles = [];

        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        }
        window.addEventListener('resize', resizeCanvas);
        resizeCanvas();

        class Particle {
            constructor(x, y, color) {
                this.x = x;
                this.y = y;
                this.color = color;
                this.size = Math.random() * 8 + 4;
                this.speedX = Math.random() * 6 - 3;
                this.speedY = Math.random() * 6 - 3;
                this.gravity = 0.15;
                this.life = 1;
            }
            update() {
                this.x += this.speedX;
                this.y += this.speedY;
                this.speedY += this.gravity;
                this.life -= 0.02;
                this.size *= 0.95;
            }
            draw() {
                ctx.fillStyle = this.color;
                ctx.globalAlpha = this.life;
                ctx.beginPath();
                // Draw a square-ish particle for "sugar" feel
                ctx.rect(this.x, this.y, this.size, this.size);
                ctx.fill();
                ctx.globalAlpha = 1;
            }
        }

        function createParticles(x, y, color) {
            for (let i = 0; i < 15; i++) {
                particles.push(new Particle(x, y, color));
            }
        }

        function animateParticles() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            for (let i = 0; i < particles.length; i++) {
                particles[i].update();
                particles[i].draw();
                if (particles[i].life <= 0) {
                    particles.splice(i, 1);
                    i--;
                }
            }
            requestAnimationFrame(animateParticles);
        }
        animateParticles();

        // --- Event Listeners ---
        startBtn.addEventListener('click', async () => {
            await initAudio();
            startOverlay.classList.add('hidden');
            initGame();
        });

        restartBtn.addEventListener('click', () => {
            gameOverOverlay.classList.add('hidden');
            initGame();
        });

        soundBtn.addEventListener('click', () => {
            isSoundOn = !isSoundOn;
            soundBtn.innerText = isSoundOn ? '🔊' : '🔇';
            if(isSoundOn) Tone.start();
        });

        shuffleBtn.addEventListener('click', () => {
            if(isProcessing || !isGameActive) return;
            if(score >= 50) {
                updateScore(score - 50);
                isProcessing = true;
                // Reshuffle logic
                for(let r=0; r<GRID_SIZE; r++) {
                    for(let c=0; c<GRID_SIZE; c++) {
                        grid[r][c] = Math.floor(Math.random() * COLORS.length);
                    }
                }
                renderGrid();
                isProcessing = false;
            } else {
                alert("分数不足!");
            }
        });

        // Drag Support (Basic implementation for desktop/mobile)
        let isDragging = false;
        let dragStartCell = null;

        gridEl.addEventListener('mousedown', (e) => {
            const cell = e.target.closest('.cell');
            if(cell) {
                isDragging = true;
                dragStartCell = cell;
            }
        });

        gridEl.addEventListener('mouseover', (e) => {
            if(isDragging && dragStartCell) {
                const cell = e.target.closest('.cell');
                if(cell && cell !== dragStartCell) {
                    // Trigger click on both to simulate swap logic
                    // Actually, simpler to just call handleCellClick logic
                    const r1 = parseInt(dragStartCell.dataset.r);
                    const c1 = parseInt(dragStartCell.dataset.c);
                    const r2 = parseInt(cell.dataset.r);
                    const c2 = parseInt(cell.dataset.c);
                    
                    // Check adjacency
                    if (Math.abs(r1-r2) + Math.abs(c1-c2) === 1) {
                        selectedCell = { r: r1, c: c1, el: dragStartCell };
                        dragStartCell.classList.add('selected');
                        handleCellClick(r2, c2);
                        isDragging = false;
                        dragStartCell = null;
                    }
                }
            }
        });

        window.addEventListener('mouseup', () => {
            isDragging = false;
            dragStartCell = null;
        });

    </script>
</body>
</html>
```
2DeepSeek5.9
点击放大试玩在线试玩
实现要点

以下是您需要的果冻糖果风格消消乐小游戏HTML代码。它是一款用原生JS和CSS构建的、拥有果冻般质感和鲜艳果糖色的三消游戏。

游戏玩法与视觉亮点

点击相邻的果冻方块交换位置,凑齐三个或以上同色即可消除得分。游戏的核心乐趣在于其独特的视觉与操作反馈。

  • 果冻质感与操作:每个方块都拥有高光、内阴影和弹性变形动画,点击或选中时会有“Q弹”的抖动效果,消除时则会缩小消失。
  • 果糖色系与动画:六种方块使用了从草莓粉、芒果黄到葡萄紫等高饱和度的渐变色彩,并搭配了柔和的投影,整体明亮多汁。得分时会有数字浮动动画。
  • 计分与连锁:消除的方块越多,单次得分越高(4个以上有额外加分),并且消除后上方方块会掉落填充,可能引发连锁消除。
查看完整源码
以下是您需要的果冻糖果风格消消乐小游戏HTML代码。它是一款用原生JS和CSS构建的、拥有果冻般质感和鲜艳果糖色的三消游戏。
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>🌈 果冻消消乐 · 果糖色</title>
    <style>
        * {
            box-sizing: border-box;
            user-select: none;
        }

        body {
            margin: 0;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background: radial-gradient(circle at 30% 10%, #ffe6f0, #c7e9fb, #fbe8c9);
            font-family: 'Segoe UI', 'Fredoka', system-ui, -apple-system, sans-serif;
            padding: 16px;
        }

        .game-wrapper {
            background: rgba(255, 255, 255, 0.35);
            backdrop-filter: blur(10px);
            border-radius: 72px 72px 48px 48px;
            padding: 28px 32px 32px 32px;
            box-shadow: 
                0 25px 40px rgba(0, 0, 0, 0.15),
                inset 0 0 30px rgba(255, 255, 255, 0.8),
                0 0 0 2px rgba(255, 255, 255, 0.6);
            border: 1px solid #ffffff80;
        }

        .header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 22px;
            padding: 0 8px;
            color: #5e3d5c;
            text-shadow: 0 2px 8px #fff8;
        }

        .score-box {
            background: #ffe9b6;
            padding: 10px 26px;
            border-radius: 120px;
            font-weight: 700;
            font-size: 1.7rem;
            letter-spacing: 1px;
            box-shadow: 0 6px 0 #b98e5c, 0 12px 22px #ffb98b55, inset 0 2px 12px #fff7b0;
            color: #7a4f2e;
            border: 1px solid #ffd966;
            backdrop-filter: blur(5px);
            transition: 0.15s;
        }

        .score-label {
            font-size: 0.9rem;
            text-transform: uppercase;
            letter-spacing: 2px;
            color: #ad7a5c;
            margin-right: 6px;
        }

        .new-game-btn {
            background: linear-gradient(145deg, #ffb9d3, #ff8eae);
            border: none;
            border-radius: 200px;
            padding: 12px 26px;
            font-weight: 700;
            font-size: 1.15rem;
            color: #482736;
            box-shadow: 0 7px 0 #b34166, 0 10px 18px #ff8eae80, inset 0 2px 12px #ffd9e6;
            cursor: pointer;
            transition: 0.08s linear;
            letter-spacing: 0.5px;
            border: 1px solid #ffdae9;
            display: flex;
            align-items: center;
            gap: 6px;
            text-shadow: 0 1px 2px #ffc0d0;
        }

        .new-game-btn:active {
            transform: translateY(5px);
            box-shadow: 0 2px 0 #b34166, 0 8px 16px #ff8eae80;
        }

        .grid-container {
            display: grid;
            grid-template-columns: repeat(8, 1fr);
            gap: 8px;
            background: rgba(255, 240, 235, 0.5);
            padding: 16px;
            border-radius: 48px;
            box-shadow: inset 0 0 30px #ffffffd0, 0 10px 25px #d4a5a5;
            border: 1px solid #ffffffd0;
            backdrop-filter: blur(4px);
        }

        /* 果冻方块 —— 灵魂所在 */
        .jelly {
            aspect-ratio: 1 / 1;
            width: 62px;
            border-radius: 35% 45% 40% 45% / 45% 35% 45% 40%;
            box-shadow: 
                0 9px 0 rgba(0, 0, 0, 0.08),
                0 14px 18px -8px rgba(0, 0, 0, 0.3),
                inset 0 -4px 8px rgba(255, 255, 255, 0.8),
                inset 0 6px 8px rgba(255, 255, 255, 0.4),
                inset 0 -10px 10px rgba(0, 0, 0, 0.05);
            transition: all 0.12s cubic-bezier(0.25, 0.46, 0.45, 0.94);
            cursor: pointer;
            border: 1px solid rgba(255, 255, 255, 0.65);
            /* 果冻弹性变形 */
            animation: jiggle 0.4s ease-out;
            position: relative;
            transform-origin: center;
        }

        /* 果冻摇头动画 */
        @keyframes jiggle {
            0% { transform: scale(0.9) rotate(-0.5deg); border-radius: 40% 40% 40% 40%; }
            30% { transform: scale(1.05) rotate(1deg); border-radius: 38% 48% 42% 48%; }
            70% { transform: scale(0.98) rotate(-0.8deg); border-radius: 42% 38% 45% 40%; }
            100% { transform: scale(1) rotate(0deg); border-radius: 35% 45% 40% 45% / 45% 35% 45% 40%; }
        }

        /* 选中状态——果冻弹跳 */
        .jelly.selected {
            animation: selectedJelly 0.4s infinite alternate;
            box-shadow: 
                0 0 0 4px #fff9e6,
                0 0 0 8px #f7b7d4,
                0 12px 20px #ffb0c0,
                inset 0 -4px 12px white,
                inset 0 6px 15px white;
            z-index: 5;
            transform: scale(1.02);
            border-radius: 50% 40% 50% 40% / 55% 50% 45% 50%;
            filter: brightness(1.1) saturate(1.2);
        }

        @keyframes selectedJelly {
            from { transform: scale(1) rotate(-1.5deg); border-radius: 45% 35% 50% 40% / 50% 45% 40% 55%; }
            to { transform: scale(1.07) rotate(1.5deg); border-radius: 35% 50% 40% 55% / 45% 55% 45% 40%; }
        }

        /* 每个糖果的颜色——果糖色系,高饱和度、明亮多汁 */
        .jelly[data-type="0"] { /* 草莓果冻 */
            background: radial-gradient(circle at 30% 25%, #ffd4e6, #ff7aa7, #d43f6b);
            box-shadow: 0 7px 0 #b33055, 0 12px 18px -6px #d43f6b99, inset 0 -5px 10px #ffe0f0, inset 0 7px 12px #ffeeee;
        }
        .jelly[data-type="1"] { /* 芒果布丁 */
            background: radial-gradient(circle at 30% 25%, #fff3c9, #ffba5e, #e58b2a);
            box-shadow: 0 7px 0 #b46f1a, 0 12px 18px -6px #e58b2a99, inset 0 -5px 10px #ffecb3, inset 0 7px 12px #fff1d0;
        }
        .jelly[data-type="2"] { /* 蓝柑果冻 */
            background: radial-gradient(circle at 30% 25%, #c2f0ff, #57c8f0, #208bc2);
            box-shadow: 0 7px 0 #176a97, 0 12px 18px -6px #208bc299, inset 0 -5px 10px #d6f4ff, inset 0 7px 12px #d9f2ff;
        }
        .jelly[data-type="3"] { /* 青柠果冻 */
            background: radial-gradient(circle at 30% 25%, #e4ffc7, #9bde4a, #5eac1c);
            box-shadow: 0 7px 0 #427816, 0 12px 18px -6px #5eac1c99, inset 0 -5px 10px #eaffd0, inset 0 7px 12px #f0ffdb;
        }
        .jelly[data-type="4"] { /* 葡萄果冻 */
            background: radial-gradient(circle at 30% 25%, #e7c9ff, #b775f0, #8641c2);
            box-shadow: 0 7px 0 #602d8c, 0 12px 18px -6px #8641c299, inset 0 -5px 10px #eed9ff, inset 0 7px 12px #e9d0ff;
        }
        .jelly[data-type="5"] { /* 蜜桃果冻 */
            background: radial-gradient(circle at 30% 25%, #ffe0cc, #ffab7a, #dc6e3a);
            box-shadow: 0 7px 0 #a84e26, 0 12px 18px -6px #dc6e3a99, inset 0 -5px 10px #ffdfca, inset 0 7px 12px #ffe7d9;
        }

        /* 为了更明显的果冻感,给每个糖果加一点高光 */
        .jelly::after {
            content: "";
            position: absolute;
            top: 12%;
            left: 18%;
            width: 26%;
            height: 20%;
            background: radial-gradient(circle, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0) 80%);
            border-radius: 50%;
            opacity: 0.9;
            pointer-events: none;
            filter: blur(1px);
            mix-blend-mode: overlay;
        }

        /* 消除时的果冻消失动画 (临时) */
        .jelly.vanishing {
            animation: vanishJelly 0.3s forwards ease-in;
            pointer-events: none;
        }

        @keyframes vanishJelly {
            0% { transform: scale(1); opacity: 1; filter: brightness(1.2); }
            50% { transform: scale(0.7) rotate(8deg); opacity: 0.7; background: white; }
            100% { transform: scale(0); opacity: 0; }
        }

        /* 得分动画浮动 */
        .floating-score {
            position: absolute;
            pointer-events: none;
            font-weight: 900;
            color: #ff3b6f;
            text-shadow: 0 4px 10px white, 0 0 15px #ffc0d0;
            font-size: 1.8rem;
            animation: floatUp 0.7s ease-out forwards;
            z-index: 100;
        }

        @keyframes floatUp {
            0% { opacity: 1; transform: translateY(0) scale(1); }
            100% { opacity: 0; transform: translateY(-80px) scale(1.5); }
        }

        /* 响应式 */
        @media (max-width: 620px) {
            .game-wrapper { padding: 16px; }
            .jelly { width: 44px; }
            .grid-container { gap: 5px; padding: 10px; }
            .score-box { font-size: 1.3rem; padding: 6px 18px; }
            .new-game-btn { font-size: 0.95rem; padding: 8px 16px; }
        }
    </style>
</head>
<body>
<div class="game-wrapper">
    <div class="header">
        <div class="score-box">
            <span class="score-label">🍬</span> <span id="scoreDisplay">0</span>
        </div>
        <button class="new-game-btn" id="newGameBtn">✨ 新果冻</button>
    </div>
    <div id="grid" class="grid-container"></div>
</div>

<script>
    (function(){
        const ROWS = 8;
        const COLS = 8;
        const TYPES = 6;        // 6种果糖色
        let grid = [];          // 2D数组存储每个格子的类型(0~5)
        let score = 0;
        let selectedRow = -1, selectedCol = -1;  // -1代表无选中
        let isProcessing = false;                // 防止连点/交换时多次触发

        const gridElement = document.getElementById('grid');
        const scoreDisplay = document.getElementById('scoreDisplay');

        // 初始化或重新开始
        function initGame() {
            // 生成无三连的初始棋盘
            do {
                grid = Array.from({ length: ROWS }, () => 
                    Array.from({ length: COLS }, () => Math.floor(Math.random() * TYPES))
                );
            } while (hasMatch());  // 如果没有匹配就跳出循环
            
            score = 0;
            selectedRow = selectedCol = -1;
            isProcessing = false;
            renderGrid();
            updateScoreDisplay();
        }

        // 检查当前grid是否存在匹配(三消)
        function hasMatch() {
            // 横向检查
            for (let r = 0; r < ROWS; r++) {
                for (let c = 0; c < COLS - 2; c++) {
                    const val = grid[r][c];
                    if (val === -1) continue; // 不可能-1,但安全
                    if (grid[r][c + 1] === val && grid[r][c + 2] === val) return true;
                }
            }
            // 竖向检查
            for (let c = 0; c < COLS; c++) {
                for (let r = 0; r < ROWS - 2; r++) {
                    const val = grid[r][c];
                    if (grid[r + 1][c] === val && grid[r + 2][c] === val) return true;
                }
            }
            return false;
        }

        // 渲染表格,绑定事件(事件委托)
        function renderGrid() {
            gridElement.innerHTML = '';
            for (let r = 0; r < ROWS; r++) {
                for (let c = 0; c < COLS; c++) {
                    const jelly = document.createElement('div');
                    jelly.className = 'jelly';
                    jelly.dataset.type = grid[r][c];
                    jelly.dataset.row = r;
                    jelly.dataset.col = c;
                    if (selectedRow === r && selectedCol === c) {
                        jelly.classList.add('selected');
                    }
                    gridElement.appendChild(jelly);
                }
            }
        }

        // 更新单个格子的视觉 (避免整体重绘)
        function updateJellyElement(r, c) {
            const index = r * COLS + c;
            const jelly = gridElement.children[index];
            if (!jelly) return;
            jelly.dataset.type = grid[r][c];
            if (selectedRow === r && selectedCol === c) {
                jelly.classList.add('selected');
            } else {
                jelly.classList.remove('selected');
            }
            // 为了重新触发果冻动画,强制重排 (小技巧)
            jelly.style.animation = 'none';
            jelly.offsetHeight; 
            jelly.style.animation = '';
        }

        // 更新所有格子视觉(重新渲染会丢失动画?但可以接受,并且更简单)
        // 为了保留果冻动画,我们选择整体重绘,但重新应用动画
        function refreshAllJellies() {
            for (let r = 0; r < ROWS; r++) {
                for (let c = 0; c < COLS; c++) {
                    const index = r * COLS + c;
                    const jelly = gridElement.children[index];
                    if (!jelly) continue;
                    jelly.dataset.type = grid[r][c];
                    if (selectedRow === r && selectedCol === c) {
                        jelly.classList.add('selected');
                    } else {
                        jelly.classList.remove('selected');
                    }
                    // 重置动画以让它再次jiggle (但频繁重置可能闪烁,但效果好)
                    jelly.style.animation = 'none';
                    void jelly.offsetHeight;
                    jelly.style.animation = '';
                }
            }
        }

        // 更新分数显示
        function updateScoreDisplay() {
            scoreDisplay.textContent = score;
        }

        // 查找所有匹配的坐标(返回要去除的格子集合)
        function getMatches() {
            const matches = new Set(); // 用字符串 "r,c" 存储

            // 横向三消及以上
            for (let r = 0; r < ROWS; r++) {
                for (let c = 0; c < COLS - 2; c++) {
                    const val = grid[r][c];
                    if (val === -1) continue;
                    let len = 1;
                    while (c + len < COLS && grid[r][c + len] === val) len++;
                    if (len >= 3) {
                        for (let i = 0; i < len; i++) {
                            matches.add(`${r},${c + i}`);
                        }
                    }
                    c += len - 1;
                }
            }

            // 竖向三消及以上
            for (let c = 0; c < COLS; c++) {
                for (let r = 0; r < ROWS - 2; r++) {
                    const val = grid[r][c];
                    if (val === -1) continue;
                    let len = 1;
                    while (r + len < ROWS && grid[r + len][c] === val) len++;
                    if (len >= 3) {
                        for (let i = 0; i < len; i++) {
                            matches.add(`${r + i},${c}`);
                        }
                    }
                    r += len - 1;
                }
            }
            return matches;
        }

        // 重力掉落 & 顶部填充新果冻
        function applyGravityAndRefill() {
            for (let c = 0; c < COLS; c++) {
                // 从下往上处理
                for (let r = ROWS - 1; r >= 0; r--) {
                    if (grid[r][c] === -1) { // 空位
                        // 寻找上方第一个非空
                        let foundRow = -1;
                        for (let k = r - 1; k >= 0; k--) {
                            if (grid[k][c] !== -1) {
                                foundRow = k;
                                break;
                            }
                        }
                        if (foundRow !== -1) {
                            // 掉落
                            grid[r][c] = grid[foundRow][c];
                            grid[foundRow][c] = -1;
                        } else {
                            // 没有上方非空,则填充新的随机类型
                            grid[r][c] = Math.floor(Math.random() * TYPES);
                        }
                    }
                }
            }
        }

        // 消除后处理循环:查找匹配→消除→掉落→填充→直到没有匹配
        function processMatches(originRow, originCol) {
            let matched = getMatches();
            if (matched.size === 0) {
                isProcessing = false;
                return;
            }

            // 累计消除个数用于加分
            const eliminatedCount = matched.size;
            // 用消除数量的平方增加爽感
            score += eliminatedCount * 2 + (eliminatedCount > 3 ? 10 : 0);
            updateScoreDisplay();

            // 播放消除动画 + 将匹配位置设为 -1
            matched.forEach(key => {
                const [r, c] = key.split(',').map(Number);
                const index = r * COLS + c;
                const jelly = gridElement.children[index];
                if (jelly) {
                    jelly.classList.add('vanishing');
                }
            });

            // 显示浮动得分(简单处理,在第一个消除位置显示)
            if (matched.size > 0) {
                const firstKey = matched.values().next().value;
                const [fr, fc] = firstKey.split(',').map(Number);
                const firstJelly = gridElement.children[fr * COLS + fc];
                if (firstJelly) {
                    const scorePop = document.createElement('div');
                    scorePop.className = 'floating-score';
                    scorePop.textContent = `+${eliminatedCount}`;
                    const rect = firstJelly.getBoundingClientRect();
                    const containerRect = gridElement.getBoundingClientRect();
                    // 简单相对定位,但浮动得分绝对定位相对于body会简单些,但为了演示简单,我们直接加在body
                    scorePop.style.position = 'fixed';
                    scorePop.style.left = rect.left + 'px';
                    scorePop.style.top = rect.top + 'px';
                    scorePop.style.zIndex = 999;
                    document.body.appendChild(scorePop);
                    setTimeout(() => scorePop.remove(), 700);
                }
            }

            // 短暂延迟后执行消除逻辑(让动画显示)
            setTimeout(() => {
                // 将匹配位置置为 -1
                matched.forEach(key => {
                    const [r, c] = key.split(',').map(Number);
                    grid[r][c] = -1;
                });

                // 重力填充
                applyGravityAndRefill();

                // 刷新UI
                refreshAllJellies();

                // 递归处理新的匹配 (消除连锁)
                setTimeout(() => processMatches(), 60);
            }, 180);
        }

        // 交换两个格子并检测是否形成匹配
        function trySwap(r1, c1, r2, c2) {
            if (isProcessing) return;

            // 简单边界检查
            if (r1 < 0 || r1 >= ROWS || c1 < 0 || c1 >= COLS ||
                r2 < 0 || r2 >= ROWS || c2 < 0 || c2 >= COLS) return;

            // 交换grid
            const temp = grid[r1][c1];
            grid[r1][c1] = grid[r2][c2];
            grid[r2][c2] = temp;

            // 检查是否有匹配
            if (hasMatch()) {
                isProcessing = true;
                // 交换成功,清除之前的选中状态
                selectedRow = selectedCol = -1;
                // 刷新两个格子(和所有?)
                refreshAllJellies();

                // 启动消除流程,加一点延迟让交换视觉生效
                setTimeout(() => {
                    processMatches();
                }, 80);
            } else {
                // 没有匹配,换回来,并且清空选中
                const tempBack = grid[r1][c1];
                grid[r1][c1] = grid[r2][c2];
                grid[r2][c2] = tempBack;

                // 视觉上也要复位, 刷新那两个格子 (但为了果冻抖动)
                updateJellyElement(r1, c1);
                updateJellyElement(r2, c2);
                // 取消选中
                selectedRow = selectedCol = -1;
                refreshAllJellies(); // 确保高亮去除

                // 可加一个错误抖动(轻微), 但保持简洁
            }
        }

        // 事件委托处理点击
        function handleGridClick(e) {
            const jelly = e.target.closest('.jelly');
            if (!jelly) return;
            if (isProcessing) return; // 动画处理中,不响应

            const row = parseInt(jelly.dataset.row);
            const col = parseInt(jelly.dataset.col);

            // 如果没有选中任何格子
            if (selectedRow === -1 || selectedCol === -1) {
                // 选中这个格子
                selectedRow = row;
                selectedCol = col;
                refreshAllJellies(); // 更新高亮
                return;
            }

            // 已经选中了一个格子
            const firstRow = selectedRow, firstCol = selectedCol;

            // 如果点击的是同一个格子:取消选中
            if (firstRow === row && firstCol === col) {
                selectedRow = selectedCol = -1;
                refreshAllJellies();
                return;
            }

            // 检查是否相邻(上下左右)
            const rowDiff = Math.abs(firstRow - row);
            const colDiff = Math.abs(firstCol - col);
            const isAdjacent = (rowDiff === 1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1);

            if (!isAdjacent) {
                // 不相邻,则选中新格子,取消旧选中
                selectedRow = row;
                selectedCol = col;
                refreshAllJellies();
                return;
            }

            // 相邻,尝试交换 (同时内部会处理清除选中)
            trySwap(firstRow, firstCol, row, col);
        }

        // 绑定全局点击到网格
        gridElement.addEventListener('click', handleGridClick);

        // 新游戏按钮
        document.getElementById('newGameBtn').addEventListener('click', () => {
            if (isProcessing) return; // 处理中不打断
            initGame();
        });

        // 启动游戏
        initGame();

        // 辅助: 因为刷新所有jelly会重置动画,我们可稍微调整让果冻总是有jiggle效果。
        // 在每次刷新后,给所有jelly重新触发动画已经在refreshAllJellies里实现。
        // 但也需要确保初始渲染有动画: 在initGame里调用renderGrid后动画会自然出现
    })();
</script>
</body>
</html>
```
### 游戏玩法与视觉亮点
点击相邻的果冻方块交换位置,凑齐三个或以上同色即可消除得分。游戏的核心乐趣在于其独特的视觉与操作反馈。

- **果冻质感与操作**:每个方块都拥有高光、内阴影和弹性变形动画,点击或选中时会有“Q弹”的抖动效果,消除时则会缩小消失。
- **果糖色系与动画**:六种方块使用了从草莓粉、芒果黄到葡萄紫等高饱和度的渐变色彩,并搭配了柔和的投影,整体明亮多汁。得分时会有数字浮动动画。
- **计分与连锁**:消除的方块越多,单次得分越高(4个以上有额外加分),并且消除后上方方块会掉落填充,可能引发连锁消除。
3通义千问4.1
点击放大试玩在线试玩
实现要点

下面是一个网页版果冻消消乐小游戏,采用「果糖色系」(柔和、通透、微渐变的糖果色调),并加入果冻物理效果(弹性动画、点击抖动、消除时的Q弹收缩+碎裂动画)。

✅ 特点:

  • 果糖色系:蜜桃粉 #FFB6C1、青柠绿 #B0F2B8、阳光橙 #FFD56F、蓝莓紫 #C7CEEA、草莓红 #FF9AA2、薄荷蓝 #A0E7E5
  • 果冻质感:CSS `filter: blur(1px)` + `box-shadow` 模拟通透感;`transform: scale()` + `transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55)` 实现弹性回弹
  • 消消乐逻辑:3连及以上可消除,支持横/竖滑动交换(鼠标拖拽或点击两个相邻格子)
  • 响应式设计,适配桌面与触屏(支持 touchstart/mousedown)

---

✅ 完整可运行代码(复制保存为 `jelly-match.html` 即可打开)

---

🌟 效果亮点说明:

| 特性 | 实现方式 |

|------|----------|

| 果糖色系 | 8种柔和糖果色:草莓红 `#FF9AA2`、蜜桃粉 `#FFB6C1`、阳光橙 `#FFD56F` 等,全部通过 CSS 变量定义,统一易改 |

| 果冻质感 | `filter: blur(0.8px)` + `radial-gradient` 内发光 + `box-shadow` 外光晕 + 圆角 + 透明边框 |

| 弹性动画 | `cubic-bezier(0.68, -0.55, 0.27, 1.55)` 模拟果冻回弹,用于选中、消除、下落 |

| 消除特效 | 先收缩(`scale(0.2)`)→ 再碎裂模糊(`blur(6px)`)→ 自动下落补位 |

| 交互反馈 | 点击抖动(无效交换)、高亮边框(选中)、悬浮上浮、提示高亮闪烁 |

| 响应式 | 支持手机触控(`touchstart` 兼容,已内置),小屏自动缩列(5×5 或 6×6) |

---

🍬 小贴士:

  • ✅ 直接保存为 `.html` 文件,双击用浏览器打开即可玩!
  • ✅ 支持鼠标拖拽(点击相邻格子交换)和触屏点击
  • ✅ 点击「提示」按钮可高亮一组可消除的交换位置
  • ✅ 连消有额外积分(当前按消除数量 ×10,可自行扩展连击倍率)

如需增强功能(如音效、粒子特效、关卡系统、排行榜、SVG果冻图标),我可为你继续升级!需要吗? 😊

查看完整源码
下面是一个**网页版果冻消消乐小游戏**,采用「果糖色系」(柔和、通透、微渐变的糖果色调),并加入**果冻物理效果**(弹性动画、点击抖动、消除时的Q弹收缩+碎裂动画)。

✅ 特点:
- 果糖色系:蜜桃粉 #FFB6C1、青柠绿 #B0F2B8、阳光橙 #FFD56F、蓝莓紫 #C7CEEA、草莓红 #FF9AA2、薄荷蓝 #A0E7E5
- 果冻质感:CSS `filter: blur(1px)` + `box-shadow` 模拟通透感;`transform: scale()` + `transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55)` 实现弹性回弹
- 消消乐逻辑:3连及以上可消除,支持横/竖滑动交换(鼠标拖拽或点击两个相邻格子)
- 响应式设计,适配桌面与触屏(支持 touchstart/mousedown)

---

### ✅ 完整可运行代码(复制保存为 `jelly-match.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>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
      background: linear-gradient(135deg, #f9f4ff, #eef8ff);
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      padding: 20px;
      color: #5a4a6c;
      overflow-x: hidden;
    }

    .header {
      text-align: center;
      margin-bottom: 20px;
      padding: 15px;
      width: 100%;
      max-width: 600px;
    }

    h1 {
      font-size: 2.8rem;
      font-weight: 800;
      background: linear-gradient(90deg, #FF9AA2, #FFB6C1, #FFD56F, #B0F2B8);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
      letter-spacing: 2px;
      margin-bottom: 8px;
      text-shadow: 0 2px 4px rgba(255, 182, 193, 0.2);
    }

    .subtitle {
      font-size: 1.1rem;
      opacity: 0.85;
      margin-bottom: 15px;
    }

    .stats {
      display: flex;
      justify-content: space-between;
      width: 100%;
      max-width: 600px;
      background: rgba(255, 255, 255, 0.75);
      border-radius: 20px;
      padding: 12px 24px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
      backdrop-filter: blur(6px);
      margin-bottom: 20px;
      font-weight: 600;
      color: #6a5b7c;
    }

    .score, .moves {
      display: flex;
      flex-direction: column;
      align-items: center;
    }

    .score-num, .moves-num {
      font-size: 1.8rem;
      font-weight: 700;
      color: #FF6B6B;
      text-shadow: 0 1px 2px rgba(255, 107, 107, 0.3);
    }

    /* 游戏容器 */
    #game-board {
      display: grid;
      grid-template-columns: repeat(8, 1fr);
      gap: 8px;
      max-width: 560px;
      width: 100%;
      aspect-ratio: 1/1;
      background: rgba(255, 255, 255, 0.5);
      padding: 12px;
      border-radius: 24px;
      box-shadow: 
        0 8px 32px rgba(255, 205, 170, 0.2),
        inset 0 0 20px rgba(255, 255, 255, 0.7);
      backdrop-filter: blur(10px);
      border: 1px solid rgba(255, 255, 255, 0.6);
    }

    /* 果冻块样式 */
    .jelly {
      border-radius: 16px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 2.2rem;
      font-weight: bold;
      cursor: pointer;
      user-select: none;
      transition: all 0.25s cubic-bezier(0.68, -0.55, 0.27, 1.55), 
                  filter 0.2s ease;
      position: relative;
      overflow: hidden;
      box-shadow: 
        0 4px 8px rgba(0, 0, 0, 0.08),
        0 0 0 2px rgba(255, 255, 255, 0.7);
      filter: blur(0.8px);
      /* 果冻通透感 */
      background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.6), transparent 60%),
                  linear-gradient(135deg, var(--color), rgba(255,255,255,0.3));
      /* 边框光晕 */
      outline: 1px solid rgba(255, 255, 255, 0.5);
    }

    /* 颜色变量(果糖色系)*/
    :root {
      --jelly-pink: #FF9AA2;   /* 草莓红 */
      --jelly-peach: #FFB6C1;  /* 蜜桃粉 */
      --jelly-orange: #FFD56F; /* 阳光橙 */
      --jelly-green: #B0F2B8;  /* 青柠绿 */
      --jelly-blue: #A0E7E5;   /* 薄荷蓝 */
      --jelly-purple: #C7CEEA; /* 蓝莓紫 */
      --jelly-yellow: #FFFACD; /* 柠檬黄(浅) */
      --jelly-rose: #FFB7C5;   /* 玫瑰粉 */
    }

    .jelly[data-type="1"] { --color: var(--jelly-pink); }
    .jelly[data-type="2"] { --color: var(--jelly-peach); }
    .jelly[data-type="3"] { --color: var(--jelly-orange); }
    .jelly[data-type="4"] { --color: var(--jelly-green); }
    .jelly[data-type="5"] { --color: var(--jelly-blue); }
    .jelly[data-type="6"] { --color: var(--jelly-purple); }
    .jelly[data-type="7"] { --color: var(--jelly-yellow); }
    .jelly[data-type="8"] { --color: var(--jelly-rose); }

    /* 选中态(高亮边框 + 微缩放)*/
    .jelly.selected {
      transform: scale(0.92);
      box-shadow: 
        0 0 0 4px rgba(255, 255, 255, 0.9),
        0 0 0 6px var(--color),
        0 4px 12px rgba(0, 0, 0, 0.15);
      z-index: 10;
      filter: blur(0.5px) brightness(1.1);
    }

    /* 消除动画:收缩 + 碎裂 */
    .jelly.removing {
      animation: jellyShrink 0.4s forwards, jellyShatter 0.3s 0.4s forwards;
      pointer-events: none;
      z-index: 1;
    }

    @keyframes jellyShrink {
      0% { transform: scale(1); opacity: 1; }
      100% { transform: scale(0.2); opacity: 0; }
    }

    @keyframes jellyShatter {
      0% { filter: blur(0.5px); }
      100% { filter: blur(6px) brightness(1.5); opacity: 0; }
    }

    /* 下落动画 */
    .jelly.falling {
      animation: jellyFall 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
    }

    @keyframes jellyFall {
      to { transform: translateY(0); opacity: 1; }
    }

    /* 抖动反馈(点击无效时)*/
    .jelly.shake {
      animation: jellyShake 0.4s ease-in-out;
    }

    @keyframes jellyShake {
      0%, 100% { transform: translateX(0); }
      25% { transform: translateX(-6px); }
      50% { transform: translateX(6px); }
      75% { transform: translateX(-4px); }
    }

    /* 控制按钮 */
    .controls {
      margin-top: 25px;
      display: flex;
      gap: 12px;
    }

    button {
      padding: 12px 28px;
      font-size: 1.1rem;
      font-weight: 600;
      border: none;
      border-radius: 50px;
      background: linear-gradient(135deg, #FF9AA2, #FFB6C1);
      color: white;
      cursor: pointer;
      box-shadow: 0 4px 14px rgba(255, 154, 162, 0.4);
      transition: all 0.2s;
      outline: none;
    }

    button:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 18px rgba(255, 154, 162, 0.6);
    }

    button:active {
      transform: translateY(0);
    }

    /* 响应式 */
    @media (max-width: 600px) {
      h1 { font-size: 2.2rem; }
      #game-board { grid-template-columns: repeat(6, 1fr); gap: 6px; }
      .jelly { font-size: 1.8rem; }
      .stats { padding: 10px 16px; }
    }

    @media (max-width: 420px) {
      #game-board { grid-template-columns: repeat(5, 1fr); gap: 4px; }
      .jelly { font-size: 1.4rem; }
      h1 { font-size: 1.8rem; }
    }

    /* 加载提示 */
    .loading {
      font-size: 1.2rem;
      color: #a89ac0;
      margin-top: 15px;
      font-style: italic;
    }
  </style>
</head>
<body>
  <div class="header">
    <h1>🍬 果糖果冻消消乐</h1>
    <p class="subtitle">轻点交换,三连即化——Q弹果冻,甜蜜消除!</p>
  </div>

  <div class="stats">
    <div class="score">
      <div>得分</div>
      <div id="score" class="score-num">0</div>
    </div>
    <div class="moves">
      <div>步数</div>
      <div id="moves" class="moves-num">20</div>
    </div>
  </div>

  <div id="game-board"></div>

  <div class="controls">
    <button id="new-game">🎮 新游戏</button>
    <button id="hint">💡 提示</button>
  </div>
  <p class="loading" id="hint-msg"></p>

  <script>
    // === 配置 ===
    const ROWS = 8;
    const COLS = 8;
    const JELLY_TYPES = 8; // 对应 1~8
    const INITIAL_MOVES = 20;

    // === 游戏状态 ===
    let board = [];
    let score = 0;
    let movesLeft = INITIAL_MOVES;
    let selectedCell = null;
    let isSwapping = false;
    let isAnimating = false;

    // 果糖色系数组(对应 data-type)
    const jellyColors = [
      '', // index 0 unused
      '#FF9AA2', '#FFB6C1', '#FFD56F', '#B0F2B8',
      '#A0E7E5', '#C7CEEA', '#FFFACD', '#FFB7C5'
    ];

    // 初始化棋盘
    function initBoard() {
      board = Array(ROWS).fill().map(() => Array(COLS).fill(0));
      // 随机填充,确保无初始三连
      for (let r = 0; r < ROWS; r++) {
        for (let c = 0; c < COLS; c++) {
          let type;
          do {
            type = Math.floor(Math.random() * JELLY_TYPES) + 1;
          } while (
            (r >= 2 && board[r-1][c] === type && board[r-2][c] === type) ||
            (c >= 2 && board[r][c-1] === type && board[r][c-2] === type)
          );
          board[r][c] = type;
        }
      }
    }

    // 渲染棋盘
    function renderBoard() {
      const boardEl = document.getElementById('game-board');
      boardEl.innerHTML = '';

      for (let r = 0; r < ROWS; r++) {
        for (let c = 0; c < COLS; c++) {
          const jelly = document.createElement('div');
          jelly.className = 'jelly';
          jelly.dataset.row = r;
          jelly.dataset.col = c;
          jelly.dataset.type = board[r][c];
          jelly.textContent = '🍬'; // 果冻图标(可替换为 SVG 更精致)

          jelly.addEventListener('click', () => handleCellClick(r, c));
          boardEl.appendChild(jelly);
        }
      }
    }

    // 处理点击
    function handleCellClick(row, col) {
      if (isAnimating || isSwapping || movesLeft <= 0) return;

      const cell = board[row][col];
      if (!cell) return;

      if (!selectedCell) {
        // 第一次点击:高亮
        selectedCell = { row, col };
        document.querySelector(`.jelly[data-row="${row}"][data-col="${col}"]`).classList.add('selected');
      } else {
        const { row: r0, col: c0 } = selectedCell;
        // 判断是否相邻(上下左右)
        const isAdjacent = 
          (row === r0 && Math.abs(col - c0) === 1) ||
          (col === c0 && Math.abs(row - r0) === 1);

        if (isAdjacent) {
          // 执行交换
          isSwapping = true;
          swapAndCheck(r0, c0, row, col);
        } else {
          // 点击非相邻 → 取消原选择,选新格子
          document.querySelector(`.jelly[data-row="${r0}"][data-col="${c0}"]`).classList.remove('selected');
          selectedCell = { row, col };
          document.querySelector(`.jelly[data-row="${row}"][data-col="${col}"]`).classList.add('selected');
        }
      }
    }

    // 交换并检测
    function swapAndCheck(r0, c0, r1, c1) {
      // 交换数据
      [board[r0][c0], board[r1][c1]] = [board[r1][c1], board[r0][c0]];

      // 检测消除
      const toRemove = findMatches();

      if (toRemove.length > 0) {
        // 有效交换 → 消除 + 得分
        removeJellies(toRemove);
        updateScore(toRemove.length * 10);
        movesLeft--;
      } else {
        // 无效交换 → 撤销 + 抖动提示
        [board[r0][c0], board[r1][c1]] = [board[r1][c1], board[r0][c0]];
        shakeCell(r0, c0);
        shakeCell(r1, c1);
      }

      // 清空选择
      clearSelection();
      isSwapping = false;
    }

    function clearSelection() {
      if (selectedCell) {
        const { row, col } = selectedCell;
        const el = document.querySelector(`.jelly[data-row="${row}"][data-col="${col}"]`);
        if (el) el.classList.remove('selected');
        selectedCell = null;
      }
    }

    function shakeCell(r, c) {
      const el = document.querySelector(`.jelly[data-row="${r}"][data-col="${c}"]`);
      if (el) {
        el.classList.add('shake');
        setTimeout(() => el.classList.remove('shake'), 400);
      }
    }

    // 查找所有匹配(行/列 ≥3)
    function findMatches() {
      const matches = new Set();

      // 行扫描
      for (let r = 0; r < ROWS; r++) {
        for (let c = 0; c < COLS; c++) {
          const type = board[r][c];
          if (!type) continue;

          // 向右延伸
          let len = 1;
          for (let j = c + 1; j < COLS && board[r][j] === type; j++) len++;
          if (len >= 3) {
            for (let j = c; j < c + len; j++) matches.add(`${r},${j}`);
          }

          // 向下延伸
          len = 1;
          for (let i = r + 1; i < ROWS && board[i][c] === type; i++) len++;
          if (len >= 3) {
            for (let i = r; i < r + len; i++) matches.add(`${i},${c}`);
          }
        }
      }

      return Array.from(matches).map(pos => {
        const [r, c] = pos.split(',').map(Number);
        return { r, c };
      });
    }

    // 移除果冻(带动画)
    function removeJellies(list) {
      isAnimating = true;
      list.forEach(({ r, c }) => {
        const el = document.querySelector(`.jelly[data-row="${r}"][data-col="${c}"]`);
        if (el) {
          el.classList.add('removing');
          board[r][c] = 0; // 清空
        }
      });

      setTimeout(() => {
        // 下落填充
        dropJellies();
      }, 400);
    }

    // 下落 + 新生成
    function dropJellies() {
      // 逐列处理:从底向上,把非零元素下沉到底部
      for (let c = 0; c < COLS; c++) {
        let writeIndex = ROWS - 1;
        // 先下沉现有元素
        for (let r = ROWS - 1; r >= 0; r--) {
          if (board[r][c] !== 0) {
            if (r !== writeIndex) {
              // 移动到 writeIndex 行
              const el = document.querySelector(`.jelly[data-row="${r}"][data-col="${c}"]`);
              if (el) {
                el.dataset.row = writeIndex;
                el.style.transform = `translateY(${(writeIndex - r) * 100}%)`;
                el.classList.add('falling');
              }
              board[writeIndex][c] = board[r][c];
              board[r][c] = 0;
            }
            writeIndex--;
          }
        }
        // 填充顶部空白
        while (writeIndex >= 0) {
          const type = Math.floor(Math.random() * JELLY_TYPES) + 1;
          board[writeIndex][c] = type;
          writeIndex--;
        }
      }

      // 重新渲染(或仅更新 DOM 属性)
      renderBoard();

      // 检查新匹配(递归消除)
      setTimeout(() => {
        const newMatches = findMatches();
        if (newMatches.length > 0) {
          removeJellies(newMatches);
        } else {
          isAnimating = false;
        }
      }, 500);
    }

    // 更新分数
    function updateScore(points) {
      score += points;
      document.getElementById('score').textContent = score;
      document.getElementById('moves').textContent = movesLeft;
    }

    // 提示功能(找一组可交换的)
    function showHint() {
      if (isAnimating || isSwapping || movesLeft <= 0) return;

      // 尝试每个相邻对
      for (let r = 0; r < ROWS; r++) {
        for (let c = 0; c < COLS; c++) {
          // 右
          if (c < COLS - 1) {
            swapTemp(r, c, r, c + 1);
            if (findMatches().length > 0) {
              highlightHint(r, c, r, c + 1);
              return;
            }
            swapTemp(r, c, r, c + 1); // 恢复
          }
          // 下
          if (r < ROWS - 1) {
            swapTemp(r, c, r + 1, c);
            if (findMatches().length > 0) {
              highlightHint(r, c, r + 1, c);
              return;
            }
            swapTemp(r, c, r + 1, c); // 恢复
          }
        }
      }
      document.getElementById('hint-msg').textContent = '暂无提示 —— 尝试移动试试吧!';
      setTimeout(() => document.getElementById('hint-msg').textContent = '', 2000);
    }

    function swapTemp(r0, c0, r1, c1) {
      [board[r0][c0], board[r1][c1]] = [board[r1][c1], board[r0][c0]];
    }

    function highlightHint(r0, c0, r1, c1) {
      const el0 = document.querySelector(`.jelly[data-row="${r0}"][data-col="${c0}"]`);
      const el1 = document.querySelector(`.jelly[data-row="${r1}"][data-col="${c1}"]`);
      if (el0 && el1) {
        el0.style.boxShadow = '0 0 0 4px white, 0 0 0 6px #FF6B6B, 0 0 12px #FF6B6B';
        el1.style.boxShadow = '0 0 0 4px white, 0 0 0 6px #FF6B6B, 0 0 12px #FF6B6B';
        document.getElementById('hint-msg').textContent = `💡 提示:交换 ${r0+1},${c0+1} 和 ${r1+1},${c1+1}`;
        setTimeout(() => {
          if (el0) el0.style.boxShadow = '';
          if (el1) el1.style.boxShadow = '';
          document.getElementById('hint-msg').textContent = '';
        }, 2500);
      }
    }

    // 事件绑定
    document.getElementById('new-game').addEventListener('click', () => {
      score = 0;
      movesLeft = INITIAL_MOVES;
      document.getElementById('score').textContent = '0';
      document.getElementById('moves').textContent = INITIAL_MOVES;
      initBoard();
      renderBoard();
      clearSelection();
      document.getElementById('hint-msg').textContent = '';
    });

    document.getElementById('hint').addEventListener('click', showHint);

    // 启动游戏
    window.onload = () => {
      initBoard();
      renderBoard();
    };
  </script>
</body>
</html>
```

---

### 🌟 效果亮点说明:

| 特性 | 实现方式 |
|------|----------|
| **果糖色系** | 8种柔和糖果色:草莓红 `#FF9AA2`、蜜桃粉 `#FFB6C1`、阳光橙 `#FFD56F` 等,全部通过 CSS 变量定义,统一易改 |
| **果冻质感** | `filter: blur(0.8px)` + `radial-gradient` 内发光 + `box-shadow` 外光晕 + 圆角 + 透明边框 |
| **弹性动画** | `cubic-bezier(0.68, -0.55, 0.27, 1.55)` 模拟果冻回弹,用于选中、消除、下落 |
| **消除特效** | 先收缩(`scale(0.2)`)→ 再碎裂模糊(`blur(6px)`)→ 自动下落补位 |
| **交互反馈** | 点击抖动(无效交换)、高亮边框(选中)、悬浮上浮、提示高亮闪烁 |
| **响应式** | 支持手机触控(`touchstart` 兼容,已内置),小屏自动缩列(5×5 或 6×6) |

---

### 🍬 小贴士:
- ✅ 直接保存为 `.html` 文件,双击用浏览器打开即可玩!  
- ✅ 支持鼠标拖拽(点击相邻格子交换)和触屏点击  
- ✅ 点击「提示」按钮可高亮一组可消除的交换位置  
- ✅ 连消有额外积分(当前按消除数量 ×10,可自行扩展连击倍率)

如需增强功能(如音效、粒子特效、关卡系统、排行榜、SVG果冻图标),我可为你继续升级!需要吗? 😊
4智谱 GLM2.6
点击放大试玩在线试玩
实现要点

制作一个网页版的消消乐小游戏涉及到前端和后端编程,以下是一个简化的前端实现方案,使用HTML、CSS和JavaScript。由于实现完整的消消乐游戏代码较为复杂,以下代码仅作为示例,展示如何创建一个简单的游戏界面和实现基本的游戏逻辑。

HTML结构

CSS样式

JavaScript逻辑

以上代码仅是一个基础框架,具体的游戏逻辑(如匹配、移除、添加新单元格等)需要根据游戏规则进行实现。你可以根据这个框架继续开发,添加更多的功能,如动画效果、得分系统等。由于实现完整的消消乐游戏逻辑较为复杂,建议参考相关教程或开源项目来完善游戏功能。

查看完整源码
制作一个网页版的消消乐小游戏涉及到前端和后端编程,以下是一个简化的前端实现方案,使用HTML、CSS和JavaScript。由于实现完整的消消乐游戏代码较为复杂,以下代码仅作为示例,展示如何创建一个简单的游戏界面和实现基本的游戏逻辑。

### HTML结构

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>果冻消消乐</title>
<style>
  /* 在这里添加CSS样式 */
</style>
</head>
<body>
<div id="game-container">
  <!-- 游戏区域 -->
</div>
<script>
  // 在这里添加JavaScript代码
</script>
</body>
</html>
```

### CSS样式

```css
/* 在这里添加CSS样式 */
#game-container {
  display: grid;
  grid-template-columns: repeat(10, 50px);
  grid-template-rows: repeat(10, 50px);
  gap: 5px;
  width: 500px;
  height: 500px;
  margin: auto;
}

.cell {
  width: 50px;
  height: 50px;
  background-color: #f7e9d2; /* 果糖色 */
  display: flex;
  justify-content: center;
  align-items: center;
  color: black;
  font-size: 24px;
  cursor: pointer;
}

/* 其他样式,例如选中、移动等 */
```

### JavaScript逻辑

```javascript
// 在这里添加JavaScript代码
const gameContainer = document.getElementById('game-container');
const rows = 10;
const cols = 10;
let board = [];

// 初始化游戏板
function initBoard() {
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      const cell = document.createElement('div');
      cell.classList.add('cell');
      cell.textContent = Math.floor(Math.random() * 2) + 1; // 随机生成数字
      cell.addEventListener('click', selectCell);
      gameContainer.appendChild(cell);
      board.push(cell);
    }
  }
}

// 选中单元格
function selectCell() {
  // 实现选中单元格的逻辑
}

// 移除匹配的单元格
function removeMatchedCells() {
  // 实现移除匹配单元格的逻辑
}

// 添加新单元格到游戏板
function addNewCells() {
  // 实现添加新单元格的逻辑
}

// 初始化游戏
initBoard();
```

以上代码仅是一个基础框架,具体的游戏逻辑(如匹配、移除、添加新单元格等)需要根据游戏规则进行实现。你可以根据这个框架继续开发,添加更多的功能,如动画效果、得分系统等。由于实现完整的消消乐游戏逻辑较为复杂,建议参考相关教程或开源项目来完善游戏功能。

评分结论

按「质量 70% + 性能 30%」加权,本场横评综合表现最佳:Kimi(综合分 6.8)。

质量分为测评人按正确性/可运行性 / 逻辑性 / 完整性 / 稳定性 / 风格 / 效率六维人工打分加权得出。

常见问题

《同题横评:做一个网页版的消消乐小游戏,要果冻的效果,颜色要果糖色》对比了哪些 AI 产品?
本次横评共覆盖 4 款产品:通义千问、Kimi、智谱清言、DeepSeek 对话。所有产品在同一题目、相同环境下实测。
《同题横评:做一个网页版的消消乐小游戏,要果冻的效果,颜色要果糖色》的核心结论是什么?
> 本报告由「AI 大众点评 · 同题横评工作台」自动生成,同一任务并发调用多家大模型后对比输出。
这份横评报告是如何产生的?
AI 大众点评 的横评报告基于同一题目、同一任务,由真人完整操作各 AI 产品并记录全过程,评分覆盖正确性、逻辑性、完整性、稳定性、风格与效率等维度,翻车情况也会如实呈现。

评论(0)

评论加载中…

图形验证码

点击图片可刷新验证码

登录后可评论,提交后即时展示