{"id":"c4356fff-024e-4354-be69-a4a3d72204cd","name":"酷炫飞翔的小鸟","type":"window","programmingType":"text","description":"像素飞翔的小鸟,AI助手生成","matches":[],"exclude":[],"include":[],"code":"const GAME_WIDTH = 800;\nconst GAME_HEIGHT = 600;\nconst BIRD_X = 112;\nconst BIRD_WIDTH = 48;\nconst BIRD_HEIGHT = 36;\nconst PIPE_WIDTH = 76;\nconst GAP = 180;\n\nconst css = `\n.flappy-stage {\n    position: relative;\n    width: 800px;\n    height: 600px;\n    margin: 24px auto;\n    overflow: hidden;\n    border-radius: 26px;\n    border: 1px solid rgba(120, 255, 255, 0.28);\n    background:\n        radial-gradient(ellipse at 50% 18%, rgba(140, 220, 255, 0.14), transparent 48%),\n        linear-gradient(180deg, #020617 0%, #05132f 48%, #071b34 100%);\n    box-shadow:\n        0 24px 80px rgba(0, 0, 0, 0.45),\n        0 0 60px rgba(0, 229, 255, 0.10),\n        inset 0 0 80px rgba(0, 0, 0, 0.30);\n    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, \"PingFang SC\", \"Microsoft YaHei\", monospace;\n    user-select: none;\n    touch-action: none;\n}\n\n.flappy-stage * {\n    box-sizing: border-box;\n}\n\n.flappy-bg {\n    position: absolute;\n    inset: 0;\n    z-index: 1;\n    pointer-events: none;\n}\n\n.flappy-grid {\n    position: absolute;\n    inset: 0;\n    z-index: 1;\n    opacity: 0.06;\n    pointer-events: none;\n    background-image:\n        linear-gradient(rgba(0, 245, 255, 0.8) 1px, transparent 1px),\n        linear-gradient(90deg, rgba(0, 245, 255, 0.8) 1px, transparent 1px);\n    background-size: 40px 40px;\n    transform: perspective(720px) rotateX(64deg) translateY(235px) scaleX(1.8);\n    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 36%, #000 100%);\n    mask-image: linear-gradient(to bottom, transparent 0, #000 36%, #000 100%);\n}\n\n.flappy-horizon {\n    position: absolute;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    height: 230px;\n    z-index: 2;\n    pointer-events: none;\n    background:\n        radial-gradient(ellipse at 50% 120%, rgba(0, 229, 255, 0.16), transparent 60%),\n        linear-gradient(to top, rgba(0, 255, 200, 0.06), transparent 70%);\n}\n\n.flappy-cloud {\n    position: absolute;\n    border-radius: 999px;\n    background: rgba(255, 255, 255, 0.07);\n    box-shadow: 0 0 34px rgba(255, 255, 255, 0.05);\n    filter: blur(0.4px);\n    animation: flappyDrift linear infinite;\n}\n\n@keyframes flappyDrift {\n    from { transform: translateX(-260px); }\n    to { transform: translateX(860px); }\n}\n\n.flappy-bird {\n    position: absolute;\n    left: 112px;\n    top: 300px;\n    width: 48px;\n    height: 36px;\n    z-index: 8;\n    transform-origin: 50% 50%;\n    filter: drop-shadow(0 0 14px rgba(255, 207, 58, 0.55));\n    pointer-events: none;\n}\n\n.flappy-wing {\n    transform-origin: 18px 18px;\n    animation: flappyWing 0.14s infinite alternate ease-in-out;\n}\n\n@keyframes flappyWing {\n    from { transform: rotate(-8deg) translateY(-2px); }\n    to { transform: rotate(12deg) translateY(2px); }\n}\n\n.flappy-pipe {\n    position: absolute;\n    width: 76px;\n    z-index: 5;\n    pointer-events: none;\n    border: 1px solid rgba(140, 255, 255, 0.38);\n    background:\n        linear-gradient(90deg, rgba(8, 45, 41, 1) 0%, rgba(41, 190, 125, 1) 46%, rgba(10, 64, 67, 1) 100%);\n    box-shadow:\n        0 0 28px rgba(0, 229, 255, 0.16),\n        inset 0 0 22px rgba(255, 255, 255, 0.08),\n        inset -4px 0 14px rgba(0, 0, 0, 0.30),\n        inset 4px 0 14px rgba(255, 255, 255, 0.06);\n}\n\n.flappy-pipe::before {\n    content: \"\";\n    position: absolute;\n    inset: 3px;\n    border-radius: 6px;\n    background: linear-gradient(180deg, rgba(255, 255, 255, 0.14), transparent 28%, rgba(0, 0, 0, 0.22));\n    opacity: 0.55;\n}\n\n.flappy-pipe-cap {\n    position: absolute;\n    height: 26px;\n    border-radius: 12px;\n    border: 1px solid rgba(160, 255, 255, 0.58);\n    background:\n        linear-gradient(90deg, rgba(10, 45, 41, 1) 0%, rgba(50, 240, 160, 1) 45%, rgba(10, 55, 62, 1) 100%);\n    box-shadow:\n        0 0 22px rgba(0, 229, 255, 0.26),\n        inset 0 0 16px rgba(255, 255, 255, 0.14),\n        inset 0 -3px 10px rgba(0, 0, 0, 0.32);\n}\n\n.flappy-pipe-top .flappy-pipe-cap {\n    bottom: -13px;\n}\n\n.flappy-pipe-bottom .flappy-pipe-cap {\n    top: -13px;\n}\n\n.flappy-score {\n    position: absolute;\n    top: 20px;\n    left: 50%;\n    transform: translateX(-50%);\n    z-index: 12;\n    min-width: 84px;\n    text-align: center;\n    font-size: 52px;\n    font-weight: 900;\n    letter-spacing: 2px;\n    color: #ffffff;\n    text-shadow:\n        0 0 12px rgba(0, 245, 255, 0.95),\n        0 0 30px rgba(255, 43, 214, 0.45),\n        0 4px 0 rgba(0, 0, 0, 0.25);\n    pointer-events: none;\n}\n\n.flappy-pop {\n    animation: flappyPop 0.32s cubic-bezier(0.2, 0.9, 0.2, 1);\n}\n\n@keyframes flappyPop {\n    0% { transform: translateX(-50%) scale(0.72) translateY(-8px); opacity: 0.2; }\n    55% { transform: translateX(-50%) scale(1.18) translateY(0); }\n    100% { transform: translateX(-50%) scale(1) translateY(0); opacity: 1; }\n}\n\n.flappy-hud {\n    position: absolute;\n    top: 18px;\n    left: 18px;\n    z-index: 12;\n    display: flex;\n    flex-direction: column;\n    gap: 8px;\n    font-size: 13px;\n    letter-spacing: 1.5px;\n    color: rgba(170, 245, 255, 0.72);\n    pointer-events: none;\n}\n\n.flappy-hud b {\n    color: #ffffff;\n    text-shadow: 0 0 10px rgba(0, 245, 255, 0.65);\n}\n\n.flappy-particle {\n    position: absolute;\n    z-index: 6;\n    width: 6px;\n    height: 6px;\n    border-radius: 50%;\n    pointer-events: none;\n    background: radial-gradient(circle, #ffffff, #00e5ff 55%, rgba(0, 229, 255, 0));\n    box-shadow: 0 0 12px rgba(0, 229, 255, 0.75);\n}\n\n.flappy-flash {\n    position: absolute;\n    inset: 0;\n    z-index: 18;\n    opacity: 0;\n    pointer-events: none;\n    background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.85), rgba(255, 43, 214, 0.35), transparent 68%);\n    mix-blend-mode: screen;\n    transition: opacity 0.18s ease;\n}\n\n.flappy-flash-active {\n    opacity: 0.72;\n    transition: opacity 0s;\n}\n\n.flappy-shake {\n    animation: flappyShake 0.34s ease;\n}\n\n@keyframes flappyShake {\n    0% { transform: translate(0, 0); }\n    18% { transform: translate(-10px, 4px) rotate(-0.6deg); }\n    36% { transform: translate(9px, -6px) rotate(0.8deg); }\n    58% { transform: translate(-6px, 3px); }\n    78% { transform: translate(4px, -2px); }\n    100% { transform: translate(0, 0); }\n}\n\n.flappy-overlay {\n    position: absolute;\n    inset: 0;\n    z-index: 30;\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    gap: 18px;\n    padding: 30px;\n    color: #ffffff;\n    text-align: center;\n    background:\n        radial-gradient(circle at 50% 42%, rgba(10, 24, 48, 0.76), rgba(0, 0, 0, 0.88));\n    backdrop-filter: blur(9px);\n    -webkit-backdrop-filter: blur(9px);\n    opacity: 1;\n    visibility: visible;\n    transition: opacity 0.28s ease, visibility 0.28s ease;\n}\n\n.flappy-hidden {\n    opacity: 0;\n    visibility: hidden;\n    pointer-events: none;\n}\n\n.flappy-title {\n    margin: 0;\n    font-size: 56px;\n    font-weight: 900;\n    letter-spacing: 8px;\n    background: linear-gradient(90deg, #00f5ff, #ff2bd6, #ffe259, #00f5ff);\n    background-size: 300% 100%;\n    -webkit-background-clip: text;\n    background-clip: text;\n    -webkit-text-fill-color: transparent;\n    color: #eafcff;\n    filter: drop-shadow(0 0 18px rgba(0, 245, 255, 0.45));\n    animation: flappyTitleFlow 4s linear infinite;\n}\n\n@keyframes flappyTitleFlow {\n    from { background-position: 0% 50%; }\n    to { background-position: 300% 50%; }\n}\n\n.flappy-subtitle {\n    font-size: 17px;\n    letter-spacing: 4px;\n    color: rgba(180, 255, 255, 0.82);\n    text-shadow: 0 0 14px rgba(0, 229, 255, 0.28);\n}\n\n.flappy-result {\n    font-size: 24px;\n    font-weight: 700;\n    letter-spacing: 2px;\n    color: #eaffff;\n    text-shadow: 0 0 16px rgba(255, 43, 214, 0.32);\n}\n\n.flappy-result b {\n    color: #ffe259;\n    text-shadow: 0 0 18px rgba(255, 226, 89, 0.55);\n}\n\n.flappy-btn {\n    position: relative;\n    isolation: isolate;\n    min-width: 190px;\n    padding: 16px 42px;\n    margin-top: 4px;\n    border: 1px solid rgba(0, 245, 255, 0.72);\n    border-radius: 999px;\n    outline: none;\n    cursor: pointer;\n    overflow: hidden;\n    color: #eaffff;\n    font-size: 18px;\n    font-weight: 800;\n    letter-spacing: 4px;\n    background:\n        linear-gradient(180deg, rgba(0, 245, 255, 0.20), rgba(255, 43, 214, 0.13));\n    box-shadow:\n        0 0 24px rgba(0, 245, 255, 0.18),\n        inset 0 0 18px rgba(255, 255, 255, 0.08);\n    transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;\n}\n\n.flappy-btn::before {\n    content: \"\";\n    position: absolute;\n    inset: -2px;\n    z-index: -1;\n    opacity: 0.55;\n    filter: blur(14px);\n    background: linear-gradient(90deg, #00f5ff, #ff2bd6, #ffe259, #00f5ff);\n    background-size: 300% 100%;\n    animation: flappyBtnGlow 4s linear infinite;\n}\n\n.flappy-btn::after {\n    content: \"\";\n    position: absolute;\n    inset: 0;\n    z-index: -1;\n    background: rgba(2, 8, 20, 0.72);\n    border-radius: inherit;\n}\n\n@keyframes flappyBtnGlow {\n    from { background-position: 0% 50%; }\n    to { background-position: 300% 50%; }\n}\n\n.flappy-btn:hover {\n    transform: translateY(-2px);\n    box-shadow:\n        0 0 38px rgba(0, 245, 255, 0.30),\n        0 0 80px rgba(255, 43, 214, 0.12),\n        inset 0 0 22px rgba(255, 255, 255, 0.10);\n    background:\n        linear-gradient(180deg, rgba(0, 245, 255, 0.28), rgba(255, 43, 214, 0.18));\n}\n\n.flappy-btn:active {\n    transform: translateY(1px) scale(0.98);\n}\n\n@media (max-width: 860px) {\n    .flappy-stage {\n        width: calc(100vw - 28px);\n        height: 66vh;\n        min-height: 520px;\n    }\n    .flappy-title {\n        font-size: 38px;\n        letter-spacing: 3px;\n    }\n    .flappy-score {\n        font-size: 38px;\n    }\n}\n`;\n\nif (!window.__flappyCssInjected) {\n    if (typeof Dog !== \"undefined\" && Dog.addStyle) {\n        Dog.addStyle(css);\n    } else {\n        const style = document.createElement(\"style\");\n        style.id = \"flappy-css\";\n        style.textContent = css;\n        document.head.appendChild(style);\n    }\n    window.__flappyCssInjected = true;\n}\n\nconst gameContainer = document.createElement(\"div\");\ngameContainer.className = \"flappy-stage\";\ngameContainer.id = \"flappy-game-container\";\n(document.body || document.documentElement).appendChild(gameContainer);\n\nconst bgLayer = document.createElement(\"div\");\nbgLayer.className = \"flappy-bg\";\ngameContainer.appendChild(bgLayer);\n\nconst gridLayer = document.createElement(\"div\");\ngridLayer.className = \"flappy-grid\";\ngameContainer.appendChild(gridLayer);\n\nconst horizon = document.createElement(\"div\");\nhorizon.className = \"flappy-horizon\";\ngameContainer.appendChild(horizon);\n\nfor (let i = 0; i < 7; i++) {\n    const cloud = document.createElement(\"div\");\n    cloud.className = \"flappy-cloud\";\n    cloud.style.width = (90 + Math.random() * 150) + \"px\";\n    cloud.style.height = (18 + Math.random() * 28) + \"px\";\n    cloud.style.left = (Math.random() * GAME_WIDTH) + \"px\";\n    cloud.style.top = (26 + Math.random() * 280) + \"px\";\n    cloud.style.opacity = (0.035 + Math.random() * 0.07).toFixed(2);\n    cloud.style.animationDuration = (18 + Math.random() * 28) + \"s\";\n    cloud.style.animationDelay = (-Math.random() * 40) + \"s\";\n    bgLayer.appendChild(cloud);\n}\n\nconst hud = document.createElement(\"div\");\nhud.className = \"flappy-hud\";\ngameContainer.appendChild(hud);\n\nconst bestDisplay = document.createElement(\"div\");\nbestDisplay.id = \"flappy-best\";\nbestDisplay.innerHTML = \"最佳 <b>0</b>\";\nhud.appendChild(bestDisplay);\n\nconst speedDisplay = document.createElement(\"div\");\nspeedDisplay.id = \"flappy-speed\";\nspeedDisplay.innerHTML = \"速度 <b>280</b>\";\nhud.appendChild(speedDisplay);\n\nconst bird = document.createElement(\"div\");\nbird.className = \"flappy-bird\";\nbird.innerHTML = `\n<svg viewBox=\"0 0 52 36\" width=\"100%\" height=\"100%\">\n    <defs>\n        <linearGradient id=\"flappyBirdGrad\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\">\n            <stop offset=\"0\" stop-color=\"#fff383\"/>\n            <stop offset=\"55%\" stop-color=\"#ffcf3a\"/>\n            <stop offset=\"100%\" stop-color=\"#ff9f2f\"/>\n        </linearGradient>\n        <filter id=\"flappyBirdGlow\" x=\"-70%\" y=\"-70%\" width=\"240%\" height=\"240%\">\n            <feDropShadow dx=\"0\" dy=\"0\" stdDeviation=\"3.2\" flood-color=\"#ffcf3a\" flood-opacity=\"0.82\"/>\n        </filter>\n    </defs>\n    <ellipse cx=\"24\" cy=\"19\" rx=\"19.5\" ry=\"14\" fill=\"url(#flappyBirdGrad)\" filter=\"url(#flappyBirdGlow)\"/>\n    <ellipse cx=\"32\" cy=\"25\" rx=\"14\" ry=\"7\" fill=\"#ff5f7e\" opacity=\"0.28\"/>\n    <path d=\"M13 20 Q22 34 36 24 Q26 29 13 20\" fill=\"#fff4b6\" opacity=\"0.62\"/>\n    <circle cx=\"34.2\" cy=\"13\" r=\"6.8\" fill=\"#ffffff\" stroke=\"#1a1a1a\" stroke-width=\"1.1\"/>\n    <circle cx=\"35.8\" cy=\"12.6\" r=\"2.5\" fill=\"#0f0f0f\"/>\n    <circle cx=\"36.8\" cy=\"11.4\" r=\"0.9\" fill=\"#ffffff\"/>\n    <path d=\"M43 16 L54.5 18.6 L43.5 23 Z\" fill=\"#ff6f00\"/>\n    <path d=\"M43 16 L54.5 18.6 L45.5 20.8 Z\" fill=\"#ffb300\"/>\n    <g class=\"flappy-wing\">\n        <path d=\"M19 19 Q26 30 35 23 Q27 24 19 19\" fill=\"#fff38c\" stroke=\"#d6a200\" stroke-width=\"0.6\"/>\n    </g>\n</svg>\n`;\ngameContainer.appendChild(bird);\n\nconst scoreDisplay = document.createElement(\"div\");\nscoreDisplay.className = \"flappy-score\";\nscoreDisplay.textContent = \"0\";\ngameContainer.appendChild(scoreDisplay);\n\nconst flash = document.createElement(\"div\");\nflash.className = \"flappy-flash\";\ngameContainer.appendChild(flash);\n\nconst overlay = document.createElement(\"div\");\noverlay.className = \"flappy-overlay\";\n\nconst overlayTitle = document.createElement(\"div\");\noverlayTitle.className = \"flappy-title\";\noverlayTitle.textContent = \"飞翔的小鸟\";\n\nconst overlayTip = document.createElement(\"div\");\noverlayTip.className = \"flappy-subtitle\";\noverlayTip.textContent = \"空格 / 点击跳跃，穿过霓虹管道\";\n\nconst overlayResult = document.createElement(\"div\");\noverlayResult.className = \"flappy-result\";\noverlayResult.textContent = \"\";\n\nconst startButton = document.createElement(\"button\");\nstartButton.className = \"flappy-btn\";\nstartButton.textContent = \"开始游戏\";\n\noverlay.appendChild(overlayTitle);\noverlay.appendChild(overlayTip);\noverlay.appendChild(overlayResult);\noverlay.appendChild(startButton);\ngameContainer.appendChild(overlay);\n\nfunction getBest() {\n    try {\n        if (typeof Dog !== \"undefined\" && Dog.getValue) {\n            const value = Dog.getValue(\"flappy-bird-best-score\", \"0\");\n            return parseInt(String(value), 10) || 0;\n        }\n    } catch (e) {\n        return 0;\n    }\n    return 0;\n}\n\nfunction saveBest(value) {\n    try {\n        if (typeof Dog !== \"undefined\" && Dog.setValue) {\n            Dog.setValue(\"flappy-bird-best-score\", String(value));\n        }\n    } catch (e) {\n        return;\n    }\n}\n\nconst gameState = {\n    score: 0,\n    best: getBest(),\n    isPlaying: false,\n    speed: 280,\n    gravity: 1750,\n    jumpForce: -520\n};\n\nconst birdPhysics = {\n    velocity: 0,\n    position: GAME_HEIGHT / 2 - BIRD_HEIGHT / 2\n};\n\nconst obstacles = [];\nconst particles = [];\n\nlet rafId = null;\nlet lastFrameTime = 0;\n\nfunction updateHUD() {\n    bestDisplay.innerHTML = \"最佳 <b>\" + gameState.best + \"</b>\";\n    speedDisplay.innerHTML = \"速度 <b>\" + Math.round(gameState.speed) + \"</b>\";\n}\n\nfunction updateScore() {\n    scoreDisplay.textContent = gameState.score;\n    scoreDisplay.classList.remove(\"flappy-pop\");\n    void scoreDisplay.offsetWidth;\n    scoreDisplay.classList.add(\"flappy-pop\");\n    gameState.speed = Math.min(470, 280 + gameState.score * 7);\n    updateHUD();\n}\n\nfunction clearObstacles() {\n    for (let i = obstacles.length - 1; i >= 0; i--) {\n        gameContainer.removeChild(obstacles[i].top);\n        gameContainer.removeChild(obstacles[i].bottom);\n    }\n    obstacles.length = 0;\n}\n\nfunction clearParticles() {\n    for (let i = particles.length - 1; i >= 0; i--) {\n        gameContainer.removeChild(particles[i].el);\n    }\n    particles.length = 0;\n}\n\nfunction createPipeCap() {\n    const cap = document.createElement(\"div\");\n    cap.className = \"flappy-pipe-cap\";\n    cap.style.width = (PIPE_WIDTH + 14) + \"px\";\n    cap.style.left = \"-7px\";\n    return cap;\n}\n\nfunction spawnObstacle() {\n    if (!gameState.isPlaying) return;\n\n    const minTop = 78;\n    const maxTop = GAME_HEIGHT - GAP - 92;\n    const topHeight = minTop + Math.random() * (maxTop - minTop);\n    const bottomTop = topHeight + GAP;\n    const bottomHeight = GAME_HEIGHT - bottomTop;\n    const x = GAME_WIDTH + PIPE_WIDTH / 2;\n\n    const topPipe = document.createElement(\"div\");\n    topPipe.className = \"flappy-pipe flappy-pipe-top\";\n    topPipe.style.left = x + \"px\";\n    topPipe.style.top = \"0\";\n    topPipe.style.height = topHeight + \"px\";\n    topPipe.appendChild(createPipeCap());\n\n    const bottomPipe = document.createElement(\"div\");\n    bottomPipe.className = \"flappy-pipe flappy-pipe-bottom\";\n    bottomPipe.style.left = x + \"px\";\n    bottomPipe.style.bottom = \"0\";\n    bottomPipe.style.height = bottomHeight + \"px\";\n    bottomPipe.appendChild(createPipeCap());\n\n    gameContainer.appendChild(topPipe);\n    gameContainer.appendChild(bottomPipe);\n\n    obstacles.push({\n        top: topPipe,\n        bottom: bottomPipe,\n        passed: false,\n        x: x,\n        topHeight: topHeight,\n        bottomTop: bottomTop\n    });\n}\n\nfunction createJumpParticles() {\n    const count = 7;\n    for (let i = 0; i < count; i++) {\n        const el = document.createElement(\"div\");\n        el.className = \"flappy-particle\";\n\n        const size = 3 + Math.random() * 5;\n        el.style.width = size + \"px\";\n        el.style.height = size + \"px\";\n\n        const x = BIRD_X + BIRD_WIDTH - 6;\n        const y = birdPhysics.position + BIRD_HEIGHT / 2;\n\n        particles.push({\n            el: el,\n            x: x,\n            y: y,\n            vx: -70 - Math.random() * 120,\n            vy: -25 + Math.random() * 130,\n            t: 0,\n            life: 0.42 + Math.random() * 0.35\n        });\n\n        gameContainer.appendChild(el);\n    }\n}\n\nfunction updateParticles(dt) {\n    for (let i = particles.length - 1; i >= 0; i--) {\n        const p = particles[i];\n        p.t += dt;\n\n        if (p.t >= p.life) {\n            gameContainer.removeChild(p.el);\n            particles.splice(i, 1);\n            continue;\n        }\n\n        p.x += p.vx * dt;\n        p.y += p.vy * dt + 45 * dt * dt;\n        p.el.style.left = p.x + \"px\";\n        p.el.style.top = p.y + \"px\";\n        p.el.style.opacity = Math.max(0, 1 - p.t / p.life).toFixed(2);\n        p.el.style.transform = \"scale(\" + Math.max(0.2, 1 - p.t / p.life).toFixed(2) + \")\";\n    }\n}\n\nfunction updateBird(dt) {\n    if (!gameState.isPlaying) return;\n\n    birdPhysics.velocity += gameState.gravity * dt;\n    birdPhysics.position += birdPhysics.velocity * dt;\n\n    if (birdPhysics.position < -BIRD_HEIGHT / 2) {\n        birdPhysics.position = -BIRD_HEIGHT / 2;\n        birdPhysics.velocity = 0;\n    }\n\n    if (birdPhysics.position > GAME_HEIGHT - BIRD_HEIGHT) {\n        birdPhysics.position = GAME_HEIGHT - BIRD_HEIGHT;\n        gameOver();\n        return;\n    }\n\n    bird.style.top = birdPhysics.position + \"px\";\n\n    const angle = Math.max(-18, Math.min(82, birdPhysics.velocity * 0.058));\n    bird.style.transform = \"rotate(\" + angle + \"deg)\";\n}\n\nfunction checkCollision(obstacle) {\n    const birdRect = {\n        left: BIRD_X + 7,\n        right: BIRD_X + BIRD_WIDTH - 7,\n        top: birdPhysics.position + 7,\n        bottom: birdPhysics.position + BIRD_HEIGHT - 7\n    };\n\n    const pipeLeft = obstacle.x;\n    const pipeRight = obstacle.x + PIPE_WIDTH;\n\n    const hasHorizontalOverlap =\n        birdRect.right > pipeLeft &&\n        birdRect.left < pipeRight;\n\n    if (!hasHorizontalOverlap) return false;\n\n    return birdRect.top < obstacle.topHeight || birdRect.bottom > obstacle.bottomTop;\n}\n\nfunction updateObstacles(dt) {\n    for (let i = obstacles.length - 1; i >= 0; i--) {\n        const obstacle = obstacles[i];\n        obstacle.x -= gameState.speed * dt;\n\n        obstacle.top.style.left = obstacle.x + \"px\";\n        obstacle.bottom.style.left = obstacle.x + \"px\";\n\n        if (checkCollision(obstacle)) {\n            gameOver();\n            return;\n        }\n\n        if (!obstacle.passed && obstacle.x + PIPE_WIDTH < BIRD_X + BIRD_WIDTH / 2) {\n            obstacle.passed = true;\n            gameState.score++;\n            updateScore();\n        }\n\n        if (obstacle.x + PIPE_WIDTH < -30) {\n            gameContainer.removeChild(obstacle.top);\n            gameContainer.removeChild(obstacle.bottom);\n            obstacles.splice(i, 1);\n        }\n    }\n\n    if (obstacles.length === 0 || obstacles[obstacles.length - 1].x < GAME_WIDTH - 255) {\n        spawnObstacle();\n    }\n}\n\nfunction gameLoop(timestamp) {\n    if (!gameState.isPlaying) return;\n\n    if (!lastFrameTime) lastFrameTime = timestamp;\n\n    const dt = Math.min((timestamp - lastFrameTime) / 1000, 0.05);\n    lastFrameTime = timestamp;\n\n    if (dt <= 0) {\n        rafId = requestAnimationFrame(gameLoop);\n        return;\n    }\n\n    updateBird(dt);\n    if (!gameState.isPlaying) return;\n\n    updateObstacles(dt);\n    if (!gameState.isPlaying) return;\n\n    updateParticles(dt);\n\n    rafId = requestAnimationFrame(gameLoop);\n}\n\nfunction startLoop() {\n    if (rafId) cancelAnimationFrame(rafId);\n    lastFrameTime = 0;\n    rafId = requestAnimationFrame(gameLoop);\n}\n\nfunction flap() {\n    if (!gameState.isPlaying) return;\n    birdPhysics.velocity = gameState.jumpForce;\n    createJumpParticles();\n}\n\nfunction startGame() {\n    if (gameState.isPlaying) return;\n\n    gameState.isPlaying = true;\n    gameState.score = 0;\n    gameState.speed = 280;\n\n    birdPhysics.velocity = 0;\n    birdPhysics.position = GAME_HEIGHT / 2 - BIRD_HEIGHT / 2;\n\n    scoreDisplay.textContent = \"0\";\n    bird.style.top = birdPhysics.position + \"px\";\n    bird.style.transform = \"rotate(0deg)\";\n\n    clearObstacles();\n    clearParticles();\n\n    overlay.classList.add(\"flappy-hidden\");\n    overlayResult.textContent = \"\";\n    startButton.textContent = \"重新开始\";\n\n    updateHUD();\n    spawnObstacle();\n    startLoop();\n}\n\nfunction gameOver() {\n    if (!gameState.isPlaying) return;\n\n    gameState.isPlaying = false;\n\n    if (rafId) {\n        cancelAnimationFrame(rafId);\n        rafId = null;\n    }\n\n    let isNewBest = false;\n    if (gameState.score > gameState.best) {\n        gameState.best = gameState.score;\n        isNewBest = true;\n        saveBest(gameState.best);\n    }\n\n    flash.classList.add(\"flappy-flash-active\");\n    gameContainer.classList.add(\"flappy-shake\");\n\n    setTimeout(function () {\n        flash.classList.remove(\"flappy-flash-active\");\n    }, 110);\n\n    setTimeout(function () {\n        gameContainer.classList.remove(\"flappy-shake\");\n    }, 360);\n\n    overlayTitle.textContent = isNewBest ? \"新纪录\" : \"游戏结束\";\n    overlayTip.textContent = isNewBest ? \"你刷新了最佳成绩，继续挑战\" : \"保持节奏，再试一次\";\n    overlayResult.innerHTML = \"得分 <b>\" + gameState.score + \"</b> · 最佳 <b>\" + gameState.best + \"</b>\";\n    startButton.textContent = \"重新开始\";\n    overlay.classList.remove(\"flappy-hidden\");\n\n    updateHUD();\n\n    try {\n        if (typeof Dog !== \"undefined\" && Dog.notification) {\n            Dog.notification(\"游戏结束！最终得分: \" + gameState.score + \"，最佳: \" + gameState.best, \"飞翔的小鸟\");\n        }\n    } catch (e) {\n        return;\n    }\n}\n\nstartButton.addEventListener(\"click\", function (e) {\n    e.stopPropagation();\n    startGame();\n});\n\ngameContainer.addEventListener(\"pointerdown\", function (e) {\n    if (e.target.closest(\".flappy-btn\")) return;\n\n    if (!gameState.isPlaying) {\n        startGame();\n    } else {\n        flap();\n    }\n\n    e.preventDefault();\n});\n\ndocument.addEventListener(\"keydown\", function (e) {\n    const isActionKey =\n        e.code === \"Space\" ||\n        e.code === \"Enter\" ||\n        e.code === \"ArrowUp\" ||\n        e.key === \" \" ||\n        e.key === \"Enter\" ||\n        e.key === \"ArrowUp\";\n\n    if (!isActionKey) return;\n\n    e.preventDefault();\n\n    if (!gameState.isPlaying) {\n        startGame();\n    } else {\n        flap();\n    }\n});\n\nbird.style.top = birdPhysics.position + \"px\";\nupdateHUD();","installTime":1758762754392,"author":"script dog","version":"1.0.0","enabled":true,"source":"","runAt":"document_idle","useDog":false,"templates":{},"requires":[],"resources":[],"window":{"icon":"","width":"830","height":"680"},"size":23923,"loading":false,"updateTime":1791618951234}