DeepSeek生成的网页小游戏 - 单人壁球挑战赛

单人壁球挑战赛

🎯 核心目标

用球拍控制小球,击中上方目标得分,尽可能获得高分。

🕹️ 基础操作

PC端控制:

  • ← → 箭头键A/D键:左右移动球拍

  • 空格键:发射球/暂停游戏

  • R键:重新开始游戏

移动端控制:

  • 左右箭头按钮:移动球拍

  • 发射按钮:发射球/暂停游戏

  • 滑动屏幕:直接移动球拍(触摸控制)

  • 点击画布:发射球

🎮 游戏机制

1. 球拍与球

  • 球初始停在球拍上(闪烁提示)

  • 按空格键或点击发射按钮将球射出

  • 球击中球拍会反弹,根据击中位置改变反弹角度

2. 目标系统

  • 屏幕上方有多行多列彩色目标

  • 不同颜色的目标有不同分数:

    • 普通目标:10分(蓝色系)

    • 金色目标:50分(金色,高分奖励)

    • 红色生命目标:10分 + 恢复1条生命

3. 得分与升级

  • 每次击中目标获得相应分数

  • 每得100分:触发花朵特效庆祝

  • 等级系统:每100分升1级,球速随等级提高

4. 生命与失败

  • 初始生命值:3条命

  • 损失生命:球掉落到底部

  • 生命恢复:击中红色生命目标

  • 最大生命值:最多5条命

  • 游戏结束:生命值为0

🌸 特效系统

1. 花朵特效

  • 每获得100分触发一次

  • 屏幕上方飘落彩色花朵

  • 花朵有不同形状和颜色

2. 得分动画

  • 每次击中目标显示"+"分数动画

  • 动画从击中位置向上飘散

⚙️ 游戏界面

1. 统计信息

  • 分数:当前得分

  • 生命值:剩余生命数

  • 等级:当前游戏等级

2. 控制区域

  • PC端:显示键盘控制提示和操作按钮

  • 移动端:显示触摸控制按钮

3. 特殊状态

  • 暂停状态:可以暂停和继续游戏

  • 游戏结束:显示最终得分和重玩按钮

🎵 音效系统

  • 背景音乐:放松的背景音乐(可开关)

  • 得分音效:击中目标时播放

  • 花朵特效音效:每100分时播放

📱 设备适配

PC端优化:

  • 键盘控制

  • 大尺寸目标

  • 完整控制面板

移动端优化:

  • 触摸控制按钮

  • 滑动控制

  • 自适应目标大小

  • 优化的画布尺寸

🏆 策略提示

  1. 控制反弹角度:球击中球拍的不同位置会改变反弹角度

  2. 优先击中特殊目标:金色目标(50分)和红色生命目标

  3. 节奏控制:不要急于发射,等待合适时机

  4. 生命管理:保持至少1条生命作为安全缓冲

  5. 利用墙壁反弹:让球从侧面墙壁反弹击中难以直接击中的目标

💡 游戏特色

  • 自适应难度:球速随等级提高,挑战性逐渐增加

  • 双重控制:同时支持键盘和触摸控制

  • 视觉反馈:丰富的动画和特效

  • 放松体验:柔和的背景音乐和视觉效果

  • 跨平台:在PC和移动设备上都能良好运行

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, viewport-fit=cover">
    <title>单人壁球挑战赛</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            -webkit-tap-highlight-color: transparent;
            -webkit-overflow-scrolling: touch;
        }
        
        html, body {
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
            background: #000;
            color: white;
            overflow-x: hidden;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 0;
            position: fixed;
            width: 100%;
            height: 100%;
            overscroll-behavior: none;
        }
        
        /* 防止iOS橡皮筋效果 */
        body {
            overflow: hidden;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
        }
        
        /* 背景图片 */
        #background-image {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-image: url('https://amitofo.icu/lianchi.jpg');
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            opacity: 0.7;
            z-index: -2;
        }
        
        /* 背景遮罩 */
        #background-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(10, 20, 40, 0.85);
            z-index: -1;
        }
        
        /* 更多游戏角标 */
        .more-games-corner {
            position: absolute;
            top: 15px;
            left: 15px;
            z-index: 100;
            padding: 8px 15px;
            background: linear-gradient(135deg, #ff3366, #ff6633);
            border-radius: 20px;
            box-shadow: 0 4px 12px rgba(255, 51, 102, 0.4);
            transition: all 0.3s ease;
        }
        
        .more-games-corner:hover, .more-games-corner:active {
            transform: translateY(-2px);
            box-shadow: 0 6px 16px rgba(255, 51, 102, 0.6);
        }
        
        .more-games-link {
            color: white;
            text-decoration: none;
            font-size: 14px;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        
        .more-games-link i {
            font-size: 16px;
        }
        
        /* 游戏容器 */
        .game-container {
            width: 100%;
            max-width: 900px;
            margin: 0 auto;
            padding: 20px;
            padding-top: 70px;
            display: flex;
            flex-direction: column;
            align-items: center;
            flex: 1;
            overflow: hidden;
        }
        
        /* 标题 */
        .header {
            text-align: center;
            margin-bottom: 25px;
            width: 100%;
        }
        
        h1 {
            font-size: 2.8rem;
            margin-bottom: 8px;
            text-shadow: 0 2px 10px rgba(0, 0, 0, 0.7);
            background: linear-gradient(90deg, #FFD700, #FFA500, #FF6347);
            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
            letter-spacing: 1px;
            font-weight: 800;
        }
        
        .subtitle {
            font-size: 1.1rem;
            opacity: 0.9;
            color: #e0e0ff;
            max-width: 600px;
            margin: 0 auto;
            line-height: 1.5;
        }
        
        /* 游戏UI */
        .game-ui {
            display: flex;
            justify-content: space-between;
            width: 100%;
            margin-bottom: 20px;
            flex-wrap: wrap;
            gap: 15px;
        }
        
        .stats {
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
            justify-content: center;
            width: 100%;
        }
        
        .stat-box {
            background: rgba(255, 255, 255, 0.12);
            padding: 15px 20px;
            border-radius: 12px;
            min-width: 120px;
            text-align: center;
            backdrop-filter: blur(8px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
        }
        
        .stat-label {
            font-size: 0.95rem;
            opacity: 0.8;
            margin-bottom: 5px;
            color: #b0b0ff;
        }
        
        .stat-value {
            font-size: 2.2rem;
            font-weight: 800;
            color: #FFD700;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        }
        
        /* 游戏画布容器 */
        .canvas-container {
            width: 100%;
            max-width: 800px;
            overflow: hidden;
            border-radius: 12px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
            border: 2px solid rgba(255, 215, 0, 0.3);
            position: relative;
            background-color: rgba(10, 15, 35, 0.85);
            touch-action: manipulation;
            height: 500px; /* 固定高度 */
            margin: 0 auto;
        }
        
        /* 游戏画布 */
        #gameCanvas {
            display: block;
            width: 100%;
            height: 100%;
        }
        
        /* 控制区域 - PC端 */
        .pc-controls {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-top: 25px;
            width: 100%;
            max-width: 800px;
        }
        
        .control-info {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 25px;
            margin-bottom: 20px;
            background: rgba(0, 0, 0, 0.3);
            padding: 18px;
            border-radius: 12px;
            width: 100%;
            border: 1px solid rgba(255, 255, 255, 0.1);
        }
        
        .control-item {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .key {
            background: rgba(255, 255, 255, 0.15);
            padding: 8px 16px;
            border-radius: 8px;
            font-weight: 700;
            border: 1px solid rgba(255, 255, 255, 0.3);
            min-width: 50px;
            text-align: center;
            color: #FFD700;
        }
        
        /* 按钮 */
        .buttons {
            display: flex;
            gap: 15px;
            margin-top: 10px;
            flex-wrap: wrap;
            justify-content: center;
        }
        
        button {
            background: linear-gradient(to bottom, #4a6ee0, #3a5ed0);
            color: white;
            border: none;
            padding: 14px 28px;
            border-radius: 10px;
            font-size: 1.05rem;
            cursor: pointer;
            transition: all 0.2s;
            font-weight: 600;
            letter-spacing: 0.5px;
            box-shadow: 0 4px 12px rgba(58, 94, 208, 0.4);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        button:hover {
            background: linear-gradient(to bottom, #5a7ef0, #4a6ee0);
            transform: translateY(-3px);
            box-shadow: 0 6px 18px rgba(58, 94, 208, 0.6);
        }
        
        button:active {
            transform: translateY(1px);
        }
        
        button#restartBtn {
            background: linear-gradient(to bottom, #FF9800, #F57C00);
            box-shadow: 0 4px 12px rgba(245, 124, 0, 0.4);
        }
        
        button#restartBtn:hover {
            background: linear-gradient(to bottom, #FFB74D, #FF9800);
            box-shadow: 0 6px 18px rgba(245, 124, 0, 0.6);
        }
        
        /* 花朵特效容器 */
        #flower-effects {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 10;
            overflow: hidden;
        }
        
        .flower {
            position: absolute;
            font-size: 24px;
            opacity: 0;
            animation: fall linear forwards;
        }
        
        @keyframes fall {
            0% {
                transform: translateY(-50px) rotate(0deg);
                opacity: 0;
            }
            10% {
                opacity: 1;
            }
            100% {
                transform: translateY(100vh) rotate(360deg);
                opacity: 0;
            }
        }
        
        /* 得分动画 */
        .score-popup {
            position: absolute;
            font-size: 28px;
            font-weight: 900;
            color: #FFD700;
            text-shadow: 0 2px 10px rgba(0, 0, 0, 0.8);
            z-index: 5;
            pointer-events: none;
            animation: scorePopup 1s ease-out forwards;
        }
        
        @keyframes scorePopup {
            0% {
                opacity: 0;
                transform: translateY(0) scale(0.5);
            }
            50% {
                opacity: 1;
                transform: translateY(-30px) scale(1.2);
            }
            100% {
                opacity: 0;
                transform: translateY(-60px) scale(0.8);
            }
        }
        
        /* 游戏结束界面 */
        .game-over {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.92);
            padding: 45px;
            border-radius: 16px;
            text-align: center;
            display: none;
            z-index: 100;
            width: 90%;
            max-width: 500px;
            border: 2px solid #FFD700;
            box-shadow: 0 0 50px rgba(255, 215, 0, 0.4);
            backdrop-filter: blur(10px);
        }
        
        .game-over h2 {
            font-size: 2.8rem;
            color: #FFD700;
            margin-bottom: 20px;
        }
        
        .game-over p {
            font-size: 1.4rem;
            margin-bottom: 35px;
            color: #e0e0ff;
        }
        
        /* 移动端控制按钮 */
        .mobile-controls {
            display: none;
            margin-top: 25px;
            width: 100%;
            max-width: 300px;
            justify-content: center;
            gap: 20px;
        }
        
        .mobile-btn {
            width: 80px;
            height: 80px;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.2);
            border: 2px solid rgba(255, 215, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 32px;
            color: white;
            cursor: pointer;
            user-select: none;
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
            touch-action: manipulation;
        }
        
        /* 音频控制 */
        .audio-control {
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 50;
            background: rgba(0, 0, 0, 0.7);
            border-radius: 50%;
            width: 50px;
            height: 50px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            border: 1px solid rgba(255, 255, 255, 0.3);
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
        }
        
        /* PC端专用样式 */
        @media (min-width: 769px) {
            .mobile-controls {
                display: none !important;
            }
            
            .pc-controls {
                display: flex !important;
            }
        }
        
        /* 移动端样式 */
        @media (max-width: 768px) {
            .pc-controls {
                display: none !important; /* 移动端隐藏控制区域 */
            }
            
            .mobile-controls {
                display: flex;
            }
            
            h1 {
                font-size: 2.2rem;
            }
            
            .subtitle {
                font-size: 1rem;
                padding: 0 10px;
            }
            
            .game-ui {
                flex-direction: column;
                align-items: center;
                gap: 15px;
            }
            
            .stats {
                width: 100%;
                justify-content: center;
            }
            
            .stat-box {
                min-width: 100px;
                padding: 12px 15px;
            }
            
            .stat-value {
                font-size: 1.8rem;
            }
            
            .more-games-corner {
                top: 10px;
                left: 10px;
                padding: 6px 12px;
            }
            
            .more-games-link {
                font-size: 13px;
            }
            
            /* 移动端调整画布高度 */
            .canvas-container {
                height: 400px;
            }
            
            /* 移动端游戏容器调整 */
            .game-container {
                padding: 15px;
                padding-top: 60px;
            }
        }
        
        @media (max-width: 480px) {
            .game-container {
                padding: 15px;
                padding-top: 60px;
            }
            
            .stat-box {
                min-width: 85px;
                padding: 10px 12px;
            }
            
            .stat-label {
                font-size: 0.85rem;
            }
            
            .stat-value {
                font-size: 1.6rem;
            }
            
            .game-over {
                padding: 30px 20px;
                width: 95%;
            }
            
            .game-over h2 {
                font-size: 2.2rem;
            }
            
            .game-over p {
                font-size: 1.2rem;
            }
            
            /* iPhone竖屏优化 */
            .canvas-container {
                height: 350px;
            }
            
            h1 {
                font-size: 1.8rem;
            }
            
            .subtitle {
                font-size: 0.9rem;
                margin-bottom: 10px;
            }
            
            .game-ui {
                margin-bottom: 10px;
            }
        }
        
        /* iPhone竖屏特殊优化 */
        @media (max-width: 480px) and (max-height: 850px) {
            .game-container {
                padding-top: 50px;
            }
            
            .canvas-container {
                height: 300px;
            }
            
            .header {
                margin-bottom: 15px;
            }
            
            .stat-box {
                padding: 8px 10px;
                min-width: 70px;
            }
            
            .stat-value {
                font-size: 1.4rem;
            }
            
            .mobile-controls {
                margin-top: 15px;
            }
            
            .mobile-btn {
                width: 70px;
                height: 70px;
                font-size: 28px;
            }
        }
        
        /* iPhone小屏幕特殊优化 */
        @media (max-width: 375px) and (max-height: 670px) {
            .canvas-container {
                height: 280px;
            }
            
            .game-container {
                padding-top: 40px;
                padding: 10px;
                padding-top: 40px;
            }
            
            h1 {
                font-size: 1.6rem;
            }
            
            .stat-box {
                padding: 6px 8px;
                min-width: 65px;
            }
            
            .stat-label {
                font-size: 0.75rem;
            }
            
            .stat-value {
                font-size: 1.2rem;
            }
            
            .mobile-btn {
                width: 65px;
                height: 65px;
                font-size: 24px;
            }
        }
        
        /* 横屏优化 */
        @media (orientation: landscape) and (max-height: 600px) {
            .game-container {
                padding-top: 15px;
            }
            
            .header {
                margin-bottom: 10px;
            }
            
            h1 {
                font-size: 1.8rem;
            }
            
            .subtitle {
                font-size: 0.9rem;
                margin-bottom: 10px;
            }
            
            .game-ui {
                margin-bottom: 10px;
            }
            
            .stat-box {
                padding: 8px 12px;
                min-width: 80px;
            }
            
            .stat-value {
                font-size: 1.4rem;
            }
            
            .canvas-container {
                height: 280px;
            }
            
            .mobile-controls {
                margin-top: 15px;
            }
        }
    </style>
</head>
<body>
    <!-- 背景图片 -->
    <div id="background-image"></div>
    <div id="background-overlay"></div>
    
    <!-- 花朵特效容器 -->
    <div id="flower-effects"></div>
    
    <!-- 更多游戏角标 -->
    <div class="more-games-corner">
        <a href="https://game.amitofo.icu" class="more-games-link">
            <i class="fas fa-gamepad"></i>
            <span>更多游戏</span>
        </a>
    </div>
    
    <!-- 音频控制 -->
    <div class="audio-control" id="audioToggle">
        <i class="fas fa-volume-up" id="audioIcon"></i>
    </div>
    
    <!-- 游戏主容器 -->
    <div class="game-container">
        <div class="header">
            <h1>单人壁球挑战赛</h1>
            <p class="subtitle">按空格键从球拍发射球,击中目标得分!每100分触发花朵特效。</p>
        </div>
        
        <div class="game-ui">
            <div class="stats">
                <div class="stat-box">
                    <div class="stat-label">分数</div>
                    <div id="score" class="stat-value">0</div>
                </div>
                <div class="stat-box">
                    <div class="stat-label">生命值</div>
                    <div id="lives" class="stat-value">3</div>
                </div>
                <div class="stat-box">
                    <div class="stat-label">等级</div>
                    <div id="level" class="stat-value">1</div>
                </div>
            </div>
        </div>
        
        <!-- 游戏画布容器 -->
        <div class="canvas-container">
            <canvas id="gameCanvas" width="800" height="500"></canvas>
        </div>
        
        <!-- 移动端控制按钮 -->
        <div class="mobile-controls">
            <div class="mobile-btn" id="mobileLeft">
                <i class="fas fa-arrow-left"></i>
            </div>
            <div class="mobile-btn" id="mobileSpace">
                <i class="fas fa-arrow-up"></i>
                <span style="font-size: 12px; margin-left: 5px;">发射</span>
            </div>
            <div class="mobile-btn" id="mobileRight">
                <i class="fas fa-arrow-right"></i>
            </div>
        </div>
        
        <!-- 游戏控制按钮 - PC端显示 -->
        <div class="pc-controls">
            <div class="control-info">
                <div class="control-item">
                    <div class="key">← →</div>
                    <span>移动球拍</span>
                </div>
                <div class="control-item">
                    <div class="key">空格</div>
                    <span>发射球/暂停</span>
                </div>
                <div class="control-item">
                    <div class="key">R</div>
                    <span>重新开始</span>
                </div>
            </div>
            
            <div class="buttons">
                <button id="startBtn">
                    <i class="fas fa-play"></i>
                    <span>开始游戏</span>
                </button>
                <button id="pauseBtn">
                    <i class="fas fa-pause"></i>
                    <span>暂停游戏</span>
                </button>
                <button id="restartBtn">
                    <i class="fas fa-redo"></i>
                    <span>重新开始</span>
                </button>
            </div>
        </div>
        
        <!-- 游戏结束界面 -->
        <div id="gameOver" class="game-over">
            <h2>游戏结束</h2>
            <p>最终得分: <span id="finalScore">0</span></p>
            <button id="playAgainBtn">
                <i class="fas fa-redo"></i>
                <span>再来一局</span>
            </button>
        </div>
    </div>
    
    <!-- 背景音乐 -->
    <audio id="backgroundMusic" loop>
        <source src="https://amitofo.icu/beijing.ogg" type="audio/ogg">
    </audio>
    
    <!-- 得分音效 -->
    <audio id="scoreSound">
        <source src="https://amitofo.icu/xiaochu.mp3" type="audio/mpeg">
    </audio>
    
    <!-- 新的击球得分音效 -->
    <audio id="winSound" preload="auto">
        <source src="https://amitofo.icu/win.mp3" type="audio/mpeg">
    </audio>

    <script>
        // 获取Canvas元素和上下文
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        // 游戏状态
        let gameRunning = false;
        let gamePaused = false;
        let score = 0;
        let lives = 3;
        let level = 1;
        let animationId = null;
        let ballOnPaddle = true; // 球是否在球拍上(等待发射)
        let lastScoreForEffect = 0; // 上次触发特效的分数
        let isMobile = false; // 是否是移动设备

        // 球拍属性
        const paddle = {
            width: 100,
            height: 15,
            x: canvas.width / 2 - 50,
            y: canvas.height - 30,
            speed: 8,
            color: '#4a6ee0',
            borderColor: '#5a7ef0'
        };

        // 球属性
        const ball = {
            x: canvas.width / 2,
            y: canvas.height - 45, // 初始位置在球拍上方
            radius: 10,
            speedX: 0, // 初始速度为0,等待发射
            speedY: 0,
            color: '#FFD700',
            borderColor: '#FFA500'
        };

        // 目标属性 - 根据设备类型调整
        let targets = [];
        let targetRows = 5;
        let targetCols = 10;
        let targetWidth = 70;
        let targetHeight = 20;
        let targetPadding = 5;
        let targetOffsetTop = 50;
        let targetOffsetLeft = 25;

        // 音频元素
        const backgroundMusic = document.getElementById('backgroundMusic');
        const scoreSound = document.getElementById('scoreSound');
        const winSound = document.getElementById('winSound');
        let musicEnabled = true;

        // 花朵颜色数组
        const flowerColors = ['#FF3366', '#FF6633', '#FF33CC', '#33FF99', '#33CCFF', '#FFCC00', '#9966FF'];
        const flowerIcons = ['❀', '✿', '❁', '🌸', '🌺', '🌼', '🌻'];

        // 检测设备类型
        function detectDevice() {
            isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
            return isMobile;
        }

        // 根据屏幕尺寸调整目标参数(优化版本)
        function adjustTargetParameters() {
            const canvasWidth = canvas.width;
            const canvasHeight = canvas.height;
            
            if (isMobile && window.innerWidth < 768) {
                // 移动端竖屏调整
                if (canvasWidth < 400) {
                    targetCols = 6;
                    targetRows = 4;
                    targetWidth = Math.max(40, (canvasWidth - targetOffsetLeft * 2 - targetPadding * (targetCols - 1)) / targetCols);
                    targetHeight = 15;
                    targetPadding = 3;
                    targetOffsetTop = 40;
                    targetOffsetLeft = (canvasWidth - (targetCols * targetWidth + (targetCols - 1) * targetPadding)) / 2;
                } else {
                    targetCols = 8;
                    targetRows = 5;
                    targetWidth = Math.max(45, (canvasWidth - targetOffsetLeft * 2 - targetPadding * (targetCols - 1)) / targetCols);
                    targetHeight = 18;
                    targetPadding = 4;
                    targetOffsetTop = 45;
                    targetOffsetLeft = (canvasWidth - (targetCols * targetWidth + (targetCols - 1) * targetPadding)) / 2;
                }
                
                // 确保目标不会太小或太大
                targetWidth = Math.min(Math.max(targetWidth, 40), 70);
                targetHeight = Math.min(Math.max(targetHeight, 12), 20);
                
                // 确保目标不会超出屏幕
                const totalWidth = targetCols * targetWidth + (targetCols - 1) * targetPadding;
                if (totalWidth > canvasWidth - 10) {
                    targetWidth = (canvasWidth - 10 - (targetCols - 1) * targetPadding) / targetCols;
                }
            } else {
                // PC端默认参数
                targetCols = 10;
                targetRows = 5;
                targetWidth = 70;
                targetHeight = 20;
                targetPadding = 5;
                targetOffsetTop = 50;
                targetOffsetLeft = 25;
                
                // 如果画布较小,适当调整
                if (canvasWidth < 600) {
                    targetCols = 8;
                    targetWidth = Math.max(50, (canvasWidth - targetOffsetLeft * 2 - targetPadding * (targetCols - 1)) / targetCols);
                }
            }
        }

        // 初始化目标
        function initTargets() {
            targets = [];
            adjustTargetParameters();
            
            for (let r = 0; r < targetRows; r++) {
                for (let c = 0; c < targetCols; c++) {
                    // 随机生成特殊目标
                    let isSpecial = Math.random() < 0.1; // 10%概率生成特殊目标
                    let color, points, isLife;
                    
                    if (isSpecial) {
                        // 随机选择特殊目标类型
                        if (Math.random() < 0.5) {
                            color = '#FFD700'; // 金色目标 - 高分
                            points = 50;
                            isLife = false;
                        } else {
                            color = '#FF5252'; // 红色目标 - 恢复生命
                            points = 10;
                            isLife = true;
                        }
                    } else {
                        // 普通目标
                        const hue = 200 + (r * 20); // 不同行的颜色不同
                        color = `hsl(${hue}, 70%, 60%)`;
                        points = 10;
                        isLife = false;
                    }
                    
                    targets.push({
                        x: c * (targetWidth + targetPadding) + targetOffsetLeft,
                        y: r * (targetHeight + targetPadding) + targetOffsetTop,
                        width: targetWidth,
                        height: targetHeight,
                        color: color,
                        points: points,
                        isLife: isLife,
                        visible: true
                    });
                }
            }
        }

        // 初始化游戏
        function initGame() {
            score = 0;
            lives = 3;
            level = 1;
            ballOnPaddle = true;
            lastScoreForEffect = 0;
            
            // 重置球拍位置
            paddle.x = canvas.width / 2 - paddle.width / 2;
            
            // 根据设备调整球拍大小
            if (isMobile) {
                paddle.width = Math.min(120, canvas.width * 0.2);
                paddle.speed = 6;
            } else {
                paddle.width = 100;
                paddle.speed = 8;
            }
            
            // 调整球的大小
            ball.radius = isMobile ? Math.min(10, canvas.width * 0.02) : 10;
            
            // 重置球位置和速度(在球拍上等待发射)
            ball.x = paddle.x + paddle.width / 2;
            ball.y = paddle.y - ball.radius;
            ball.speedX = 0;
            ball.speedY = 0;
            
            // 初始化目标
            initTargets();
            
            // 更新UI
            updateUI();
            
            // 隐藏游戏结束界面
            document.getElementById('gameOver').style.display = 'none';
            
            // 播放背景音乐
            if (musicEnabled) {
                backgroundMusic.volume = 0.5;
                backgroundMusic.play().catch(e => console.log("自动播放被阻止,需要用户交互"));
            }
        }

        // 绘制球拍
        function drawPaddle() {
            // 绘制球拍阴影
            ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
            ctx.shadowBlur = 5;
            ctx.shadowOffsetX = 2;
            ctx.shadowOffsetY = 2;
            
            // 绘制球拍主体
            ctx.fillStyle = paddle.color;
            ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
            
            // 绘制球拍边框
            ctx.strokeStyle = paddle.borderColor;
            ctx.lineWidth = 2;
            ctx.strokeRect(paddle.x, paddle.y, paddle.width, paddle.height);
            
            // 绘制球拍内部细节
            ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
            ctx.fillRect(paddle.x + 5, paddle.y + 3, paddle.width - 10, paddle.height - 6);
            
            // 重置阴影
            ctx.shadowColor = 'transparent';
            ctx.shadowBlur = 0;
            ctx.shadowOffsetX = 0;
            ctx.shadowOffsetY = 0;
        }

        // 绘制球
        function drawBall() {
            // 如果球在球拍上等待发射,绘制特殊效果
            if (ballOnPaddle) {
                // 绘制脉动效果
                const pulseSize = Math.sin(Date.now() / 200) * 2;
                
                // 绘制球阴影
                ctx.shadowColor = 'rgba(255, 215, 0, 0.5)';
                ctx.shadowBlur = 10 + pulseSize * 3;
                ctx.shadowOffsetX = 0;
                ctx.shadowOffsetY = 0;
                
                // 绘制球体
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ball.radius + pulseSize, 0, Math.PI * 2);
                ctx.fillStyle = '#FFD700';
                ctx.fill();
                
                // 绘制球边框
                ctx.strokeStyle = '#FFA500';
                ctx.lineWidth = 2;
                ctx.stroke();
                
                // 只在PC端显示提示文字
                if (!isMobile) {
                    ctx.font = "14px Arial";
                    ctx.fillStyle = "#FFFFFF";
                    ctx.textAlign = "center";
                    ctx.fillText("按空格发射", ball.x, ball.y - ball.radius - 15);
                }
                
                // 重置阴影
                ctx.shadowColor = 'transparent';
                ctx.shadowBlur = 0;
            } else {
                // 正常绘制球
                ctx.shadowColor = 'rgba(0, 0, 0, 0.4)';
                ctx.shadowBlur = 8;
                ctx.shadowOffsetX = 2;
                ctx.shadowOffsetY = 2;
                
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
                ctx.fillStyle = ball.color;
                ctx.fill();
                
                ctx.strokeStyle = ball.borderColor;
                ctx.lineWidth = 2;
                ctx.stroke();
                
                ctx.shadowColor = 'transparent';
                ctx.shadowBlur = 0;
            }
            
            // 绘制球高光
            ctx.beginPath();
            ctx.arc(ball.x - ball.radius/3, ball.y - ball.radius/3, ball.radius/3, 0, Math.PI * 2);
            ctx.fillStyle = 'rgba(255, 255, 255, 0.6)';
            ctx.fill();
        }

        // 绘制目标
        function drawTargets() {
            targets.forEach(target => {
                if (!target.visible) return;
                
                // 绘制目标阴影
                ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
                ctx.shadowBlur = 3;
                ctx.shadowOffsetX = 1;
                ctx.shadowOffsetY = 1;
                
                // 绘制目标主体
                ctx.fillStyle = target.color;
                ctx.fillRect(target.x, target.y, target.width, target.height);
                
                // 绘制目标边框
                ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
                ctx.lineWidth = 1;
                ctx.strokeRect(target.x, target.y, target.width, target.height);
                
                // 特殊目标添加额外效果
                if (target.points === 50) {
                    // 金色目标的特殊效果
                    ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
                    ctx.fillRect(target.x + 5, target.y + 3, target.width - 10, target.height - 6);
                } else if (target.isLife) {
                    // 生命目标的特殊效果
                    ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
                    ctx.beginPath();
                    ctx.arc(target.x + target.width/2, target.y + target.height/2, target.height/3, 0, Math.PI * 2);
                    ctx.fill();
                }
                
                // 重置阴影
                ctx.shadowColor = 'transparent';
                ctx.shadowBlur = 0;
                ctx.shadowOffsetX = 0;
                ctx.shadowOffsetY = 0;
            });
        }

        // 绘制背景
        function drawBackground() {
            // 清除画布,使用半透明黑色实现渐隐效果
            ctx.fillStyle = 'rgba(10, 15, 35, 0.2)';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // 绘制网格线
            ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
            ctx.lineWidth = 1;
            
            // 垂直线
            for (let x = 0; x < canvas.width; x += 40) {
                ctx.beginPath();
                ctx.moveTo(x, 0);
                ctx.lineTo(x, canvas.height);
                ctx.stroke();
            }
            
            // 水平线
            for (let y = 0; y < canvas.height; y += 40) {
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(canvas.width, y);
                ctx.stroke();
            }
        }

        // 创建得分动画
        function createScoreAnimation(x, y, points) {
            const canvasContainer = document.querySelector('.canvas-container');
            const scorePopup = document.createElement('div');
            scorePopup.className = 'score-popup';
            scorePopup.textContent = `+${points}`;
            
            // 根据设备调整字体大小
            const fontSize = isMobile ? '20px' : '28px';
            scorePopup.style.fontSize = fontSize;
            
            // 计算相对于容器的位置
            const rect = canvas.getBoundingClientRect();
            const containerRect = canvasContainer.getBoundingClientRect();
            const relativeX = x * (rect.width / canvas.width);
            const relativeY = y * (rect.height / canvas.height);
            
            scorePopup.style.left = `${relativeX}px`;
            scorePopup.style.top = `${relativeY}px`;
            
            canvasContainer.appendChild(scorePopup);
            
            // 动画结束后移除元素
            setTimeout(() => {
                if (scorePopup.parentNode) {
                    scorePopup.parentNode.removeChild(scorePopup);
                }
            }, 1000);
        }

        // 发射球
        function launchBall() {
            if (ballOnPaddle && gameRunning && !gamePaused) {
                ballOnPaddle = false;
                // 设置球的初始速度
                const baseSpeed = isMobile ? 4 : 5;
                ball.speedX = (Math.random() > 0.5 ? 1 : -1) * baseSpeed;
                ball.speedY = -baseSpeed;
            }
        }

        // 更新球的位置
        function updateBall() {
            if (ballOnPaddle) {
                // 球在球拍上,跟随球拍移动
                ball.x = paddle.x + paddle.width / 2;
                ball.y = paddle.y - ball.radius;
            } else {
                // 移动球
                ball.x += ball.speedX;
                ball.y += ball.speedY;
                
                // 检测与墙壁的碰撞
                if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
                    ball.speedX = -ball.speedX;
                }
                
                // 检测与天花板的碰撞
                if (ball.y - ball.radius < 0) {
                    ball.speedY = -ball.speedY;
                }
                
                // 检测与球拍的碰撞
                if (
                    ball.y + ball.radius > paddle.y &&
                    ball.y - ball.radius < paddle.y + paddle.height &&
                    ball.x > paddle.x &&
                    ball.x < paddle.x + paddle.width
                ) {
                    // 根据击中球拍的位置调整反弹角度
                    let hitPoint = (ball.x - paddle.x) / paddle.width;
                    const angleMultiplier = isMobile ? 8 : 10;
                    ball.speedX = (hitPoint - 0.5) * angleMultiplier;
                    ball.speedY = -Math.abs(ball.speedY); // 确保球向上反弹
                }
                
                // 检测球是否落到底部
                if (ball.y + ball.radius > canvas.height) {
                    lives--;
                    updateUI();
                    
                    if (lives <= 0) {
                        gameOver();
                    } else {
                        // 重置球的位置到球拍上
                        ballOnPaddle = true;
                        ball.x = paddle.x + paddle.width / 2;
                        ball.y = paddle.y - ball.radius;
                        ball.speedX = 0;
                        ball.speedY = 0;
                    }
                }
                
                // 检测与目标的碰撞
                targets.forEach(target => {
                    if (!target.visible) return;
                    
                    if (
                        ball.x + ball.radius > target.x &&
                        ball.x - ball.radius < target.x + target.width &&
                        ball.y + ball.radius > target.y &&
                        ball.y - ball.radius < target.y + target.height
                    ) {
                        // 击中目标
                        target.visible = false;
                        ball.speedY = -ball.speedY;
                        
                        // 更新分数
                        score += target.points;
                        
                        // 创建得分动画
                        createScoreAnimation(ball.x, ball.y - 20, target.points);
                        
                        // 播放击球得分音效
                        if (musicEnabled) {
                            winSound.currentTime = 0;
                            winSound.play().catch(e => console.log("得分音效播放失败"));
                        }
                        
                        // 检查是否需要触发花朵特效
                        if (Math.floor(score / 100) > Math.floor(lastScoreForEffect / 100)) {
                            createFlowerEffect();
                            lastScoreForEffect = score;
                            
                            // 播放额外的得分音效
                            if (musicEnabled) {
                                scoreSound.currentTime = 0;
                                scoreSound.play().catch(e => console.log("音效播放失败"));
                            }
                        }
                        
                        // 如果是生命目标,增加生命值
                        if (target.isLife) {
                            lives = Math.min(lives + 1, 5); // 最多5条命
                        }
                        
                        // 更新等级
                        let newLevel = Math.floor(score / 100) + 1;
                        if (newLevel > level) {
                            level = newLevel;
                            // 每升一级,球速增加
                            const speedIncrease = isMobile ? 1.05 : 1.1;
                            ball.speedX *= speedIncrease;
                            ball.speedY *= speedIncrease;
                        }
                        
                        updateUI();
                        
                        // 检查是否所有目标都被击中
                        if (targets.every(t => !t.visible)) {
                            // 所有目标被击中,重新生成
                            initTargets();
                            // 奖励额外生命
                            lives = Math.min(lives + 1, 5);
                            updateUI();
                        }
                    }
                });
            }
        }

        // 创建花朵特效
        function createFlowerEffect() {
            const flowerContainer = document.getElementById('flower-effects');
            const flowerCount = isMobile ? 20 : 30; // 移动端减少花朵数量
            
            for (let i = 0; i < flowerCount; i++) {
                const flower = document.createElement('div');
                flower.className = 'flower';
                
                // 随机选择花朵图标和颜色
                const iconIndex = Math.floor(Math.random() * flowerIcons.length);
                const colorIndex = Math.floor(Math.random() * flowerColors.length);
                
                flower.textContent = flowerIcons[iconIndex];
                flower.style.color = flowerColors[colorIndex];
                flower.style.left = Math.random() * 100 + 'vw';
                flower.style.fontSize = (isMobile ? 16 : 20) + Math.random() * (isMobile ? 15 : 20) + 'px';
                
                // 随机动画参数
                const duration = 3 + Math.random() * 4; // 3-7秒
                const delay = Math.random() * 2; // 0-2秒延迟
                const horizontalMove = (Math.random() - 0.5) * 100; // 水平移动距离
                
                flower.style.animation = `fall ${duration}s linear ${delay}s forwards`;
                flower.style.transform = `translateX(${horizontalMove}px)`;
                
                flowerContainer.appendChild(flower);
                
                // 动画结束后移除花朵元素
                setTimeout(() => {
                    if (flower.parentNode) {
                        flower.parentNode.removeChild(flower);
                    }
                }, (duration + delay) * 1000);
            }
        }

        // 更新UI
        function updateUI() {
            document.getElementById('score').textContent = score;
            document.getElementById('lives').textContent = lives;
            document.getElementById('level').textContent = level;
        }

        // 游戏结束
        function gameOver() {
            gameRunning = false;
            cancelAnimationFrame(animationId);
            
            document.getElementById('finalScore').textContent = score;
            document.getElementById('gameOver').style.display = 'block';
        }

        // 游戏主循环
        function gameLoop() {
            // 绘制游戏背景
            drawBackground();
            
            // 绘制游戏元素
            drawTargets();
            drawPaddle();
            drawBall();
            
            // 更新游戏状态
            if (!gamePaused && gameRunning) {
                updateBall();
            }
            
            // 继续游戏循环
            if (gameRunning) {
                animationId = requestAnimationFrame(gameLoop);
            }
        }

        // 键盘控制
        const keys = {};
        
        window.addEventListener('keydown', (e) => {
            keys[e.key] = true;
            
            // 空格键发射球或暂停游戏
            if (e.key === ' ' && gameRunning) {
                if (ballOnPaddle) {
                    launchBall();
                } else {
                    togglePause();
                }
                e.preventDefault(); // 防止空格键滚动页面
            }
            
            // R键重新开始
            if (e.key === 'r' || e.key === 'R') {
                restartGame();
            }
        });
        
        window.addEventListener('keyup', (e) => {
            keys[e.key] = false;
        });

        // 处理球拍移动
        function handlePaddleMovement() {
            if (keys['ArrowLeft'] || keys['Left'] || keys['a'] || keys['A']) {
                paddle.x = Math.max(0, paddle.x - paddle.speed);
            }
            
            if (keys['ArrowRight'] || keys['Right'] || keys['d'] || keys['D']) {
                paddle.x = Math.min(canvas.width - paddle.width, paddle.x + paddle.speed);
            }
            
            // 每帧调用
            if (gameRunning && !gamePaused) {
                requestAnimationFrame(handlePaddleMovement);
            }
        }

        // 切换暂停状态
        function togglePause() {
            gamePaused = !gamePaused;
            // PC端更新按钮文本
            if (!isMobile) {
                document.getElementById('pauseBtn').innerHTML = gamePaused ? 
                    '<i class="fas fa-play"></i><span>继续游戏</span>' : 
                    '<i class="fas fa-pause"></i><span>暂停游戏</span>';
            }
            
            if (!gamePaused && gameRunning) {
                handlePaddleMovement();
            }
        }

        // 开始游戏
        function startGame() {
            if (!gameRunning) {
                initGame();
                gameRunning = true;
                gamePaused = false;
                if (!isMobile) {
                    document.getElementById('pauseBtn').innerHTML = '<i class="fas fa-pause"></i><span>暂停游戏</span>';
                }
                gameLoop();
                handlePaddleMovement();
            }
        }

        // 暂停游戏
        function pauseGame() {
            if (gameRunning) {
                togglePause();
            }
        }

        // 重新开始游戏
        function restartGame() {
            gameRunning = false;
            gamePaused = false;
            cancelAnimationFrame(animationId);
            startGame();
        }

        // 音频控制
        document.getElementById('audioToggle').addEventListener('click', function() {
            musicEnabled = !musicEnabled;
            const icon = document.getElementById('audioIcon');
            
            if (musicEnabled) {
                icon.className = 'fas fa-volume-up';
                backgroundMusic.volume = 0.5;
                backgroundMusic.play().catch(e => console.log("音频播放需要用户交互"));
            } else {
                icon.className = 'fas fa-volume-mute';
                backgroundMusic.pause();
            }
        });

        // 移动端控制
        document.getElementById('mobileLeft').addEventListener('touchstart', function(e) {
            e.preventDefault();
            keys['ArrowLeft'] = true;
        });
        
        document.getElementById('mobileLeft').addEventListener('touchend', function(e) {
            e.preventDefault();
            keys['ArrowLeft'] = false;
        });
        
        document.getElementById('mobileRight').addEventListener('touchstart', function(e) {
            e.preventDefault();
            keys['ArrowRight'] = true;
        });
        
        document.getElementById('mobileRight').addEventListener('touchend', function(e) {
            e.preventDefault();
            keys['ArrowRight'] = false;
        });
        
        document.getElementById('mobileSpace').addEventListener('touchstart', function(e) {
            e.preventDefault();
            if (gameRunning) {
                if (ballOnPaddle) {
                    launchBall();
                } else {
                    togglePause();
                }
            }
        });

        // 事件监听 - PC端按钮
        document.getElementById('startBtn').addEventListener('click', startGame);
        document.getElementById('pauseBtn').addEventListener('click', pauseGame);
        document.getElementById('restartBtn').addEventListener('click', restartGame);
        document.getElementById('playAgainBtn').addEventListener('click', restartGame);

        // 窗口调整大小时调整Canvas
        function resizeCanvas() {
            const container = document.querySelector('.canvas-container');
            const containerWidth = Math.min(container.clientWidth, 800);
            const containerHeight = container.clientHeight;
            
            // 设置Canvas尺寸
            canvas.width = containerWidth;
            canvas.height = containerHeight;
            
            // 重新调整球拍位置
            paddle.y = canvas.height - 30;
            
            // 根据设备调整球拍宽度
            if (isMobile) {
                paddle.width = Math.min(120, containerWidth * 0.2);
                paddle.speed = 6;
            } else {
                paddle.width = 100;
                paddle.speed = 8;
            }
            
            // 调整球的大小
            ball.radius = isMobile ? Math.min(10, containerWidth * 0.02) : 10;
            
            // 如果球在球拍上,调整球的位置
            if (ballOnPaddle) {
                ball.x = paddle.x + paddle.width / 2;
                ball.y = paddle.y - ball.radius;
            }
            
            // 如果游戏运行中,重新初始化目标以适应新尺寸
            if (gameRunning) {
                initTargets();
            }
        }

        // 初始调整Canvas大小
        window.addEventListener('load', () => {
            // 检测设备类型
            detectDevice();
            
            // 初始化Canvas
            resizeCanvas();
            
            // 自动开始游戏
            setTimeout(() => {
                startGame();
            }, 500);
            
            // 预加载音频
            winSound.load();
            
            // 尝试播放背景音乐(需要用户交互)
            document.addEventListener('click', function initAudio() {
                if (musicEnabled) {
                    backgroundMusic.volume = 0.5;
                    backgroundMusic.play().catch(e => console.log("音频播放需要用户交互"));
                }
                document.removeEventListener('click', initAudio);
            });
        });
        
        window.addEventListener('resize', resizeCanvas);
        
        // 触摸设备支持
        let touchStartX = 0;
        
        canvas.addEventListener('touchstart', (e) => {
            if (!gameRunning || gamePaused) return;
            
            e.preventDefault();
            const touch = e.touches[0];
            const rect = canvas.getBoundingClientRect();
            touchStartX = touch.clientX - rect.left;
        }, { passive: false });
        
        canvas.addEventListener('touchmove', (e) => {
            if (!gameRunning || gamePaused) return;
            
            e.preventDefault();
            const touch = e.touches[0];
            const rect = canvas.getBoundingClientRect();
            const touchX = touch.clientX - rect.left;
            
            // 计算移动距离并更新球拍位置
            const deltaX = touchX - touchStartX;
            paddle.x += deltaX;
            
            // 限制球拍在画布内
            if (paddle.x < 0) paddle.x = 0;
            if (paddle.x + paddle.width > canvas.width) paddle.x = canvas.width - paddle.width;
            
            // 更新起始触摸位置
            touchStartX = touchX;
            
            // 如果球在球拍上,更新球的位置
            if (ballOnPaddle) {
                ball.x = paddle.x + paddle.width / 2;
            }
        }, { passive: false });
        
        // 点击画布发射球(移动端)
        canvas.addEventListener('touchend', (e) => {
            if (!gameRunning || gamePaused) return;
            
            e.preventDefault();
            // 移动端点击发射球
            if (ballOnPaddle) {
                launchBall();
            }
        }, { passive: false });
        
        // 防止页面滚动
        document.addEventListener('touchmove', function(e) {
            if (gameRunning) {
                e.preventDefault();
            }
        }, { passive: false });
        
        // 防止双击缩放
        let lastTouchEnd = 0;
        document.addEventListener('touchend', function(event) {
            const now = (new Date()).getTime();
            if (now - lastTouchEnd <= 300) {
                event.preventDefault();
            }
            lastTouchEnd = now;
        }, false);
    </script>
</body>
</html>
相关推荐
萧曵 丶5 小时前
Vue 中父子组件之间最常用的业务交互场景
javascript·vue.js·交互
银烛木5 小时前
黑马程序员前端h5+css3
前端·css·css3
听海边涛声5 小时前
CSS3 图片模糊处理
前端·css·css3
Amumu121386 小时前
Vue3扩展(二)
前端·javascript·vue.js
NEXT066 小时前
JavaScript进阶:深度剖析函数柯里化及其在面试中的底层逻辑
前端·javascript·面试
牛奶8 小时前
你不知道的 JS(上):原型与行为委托
前端·javascript·编译原理
牛奶8 小时前
你不知道的JS(上):this指向与对象基础
前端·javascript·编译原理
牛奶8 小时前
你不知道的JS(上):作用域与闭包
前端·javascript·电子书
pas1369 小时前
45-mini-vue 实现代码生成三种联合类型
前端·javascript·vue.js
颜酱10 小时前
数组双指针部分指南 (快慢·左右·倒序)
javascript·后端·算法