🎮ArcadeLab

Neon FPS

by RocketOwl77
7796 lines244.0 KB🛠️ Three.js (3D graphics)
▶ Play
<!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>Neon FPS - 赛博朋克第一人称射击</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            overflow: hidden;
            background: #0a0a1a;
            font-family: 'Courier New', monospace;
            user-select: none;
            -webkit-user-select: none;
        }
        
        #game-container {
            width: 100vw;
            height: 100vh;
            position: relative;
        }
        
        canvas {
            display: block;
            cursor: crosshair;
        }
        
        /* 加载画面 */
        #loading-screen {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: #0a0a1a;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 1000;
            transition: opacity 0.5s;
        }
        
        #loading-screen h1 {
            color: #00ffff;
            font-size: 48px;
            text-shadow: 0 0 20px rgba(0, 255, 255, 0.8);
            margin-bottom: 20px;
            animation: pulse 2s infinite;
        }
        
        #loading-screen p {
            color: #888;
            font-size: 14px;
        }
        
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.6; }
        }
        
        /* 伤害闪烁 */
        #damage-flash {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 90;
            opacity: 0;
            transition: opacity 0.1s;
        }
        
        /* 商店遮罩 */
        #shopOverlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(10, 10, 26, 0.95);
            display: none;
            align-items: center;
            justify-content: center;
            z-index: 200;
            overflow-y: auto;
        }
        
        #shopContent {
            max-width: 900px;
            width: 90%;
            max-height: 90vh;
            overflow-y: auto;
            padding: 30px;
            background: linear-gradient(135deg, rgba(0, 255, 255, 0.1), rgba(255, 0, 255, 0.1));
            border: 2px solid #00ffff;
            border-radius: 15px;
            box-shadow: 0 0 30px rgba(0, 255, 255, 0.3);
        }
        
        .shop-header {
            text-align: center;
            margin-bottom: 25px;
            padding-bottom: 15px;
            border-bottom: 1px solid rgba(0, 255, 255, 0.3);
        }
        
        .shop-header h2 {
            color: #00ffff;
            font-size: 32px;
            text-shadow: 0 0 15px rgba(0, 255, 255, 0.6);
            margin-bottom: 10px;
        }
        
        .coins-display {
            color: #ffdd00;
            font-size: 20px;
            font-weight: bold;
            text-shadow: 0 0 10px rgba(255, 221, 0, 0.5);
        }
        
        .shop-section {
            margin-bottom: 25px;
        }
        
        .shop-section h3 {
            color: #ff00ff;
            font-size: 20px;
            margin-bottom: 15px;
            text-shadow: 0 0 10px rgba(255, 0, 255, 0.4);
        }
        
        .weapon-upgrades {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 15px;
        }
        
        .weapon-upgrade-card {
            background: rgba(0, 0, 0, 0.4);
            border: 2px solid;
            border-radius: 10px;
            padding: 15px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        
        .weapon-upgrade-card:hover {
            transform: translateY(-3px);
            box-shadow: 0 5px 20px rgba(0, 255, 255, 0.2);
        }
        
        .weapon-upgrade-card h4 {
            color: #fff;
            font-size: 16px;
            margin-bottom: 8px;
        }
        
        .weapon-stats {
            display: flex;
            gap: 15px;
            margin-bottom: 12px;
            font-size: 12px;
            color: #aaa;
        }
        
        .upgrade-btn {
            width: 100%;
            padding: 8px 12px;
            margin-bottom: 6px;
            background: linear-gradient(135deg, #1a1a2e, #16213e);
            border: 1px solid #00ffff;
            color: #00ffff;
            border-radius: 6px;
            cursor: pointer;
            font-size: 12px;
            font-family: inherit;
            transition: all 0.2s;
        }
        
        .upgrade-btn:hover:not(.disabled) {
            background: linear-gradient(135deg, #00ffff33, #ff00ff33);
            transform: scale(1.02);
        }
        
        .upgrade-btn.disabled {
            opacity: 0.4;
            cursor: not-allowed;
            border-color: #666;
            color: #666;
        }
        
        .general-upgrades {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
        }
        
        .general-upgrade-card {
            background: rgba(0, 0, 0, 0.4);
            border: 2px solid #ffaa00;
            border-radius: 10px;
            padding: 15px;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        
        .upgrade-icon {
            font-size: 32px;
            text-align: center;
        }
        
        .upgrade-info h4 {
            color: #fff;
            font-size: 15px;
            margin-bottom: 4px;
        }
        
        .upgrade-info p {
            color: #aaa;
            font-size: 12px;
        }
        
        .upgrade-level {
            color: #ffaa00 !important;
            font-weight: bold;
        }
        
        .shop-footer {
            text-align: center;
            margin-top: 20px;
            padding-top: 20px;
            border-top: 1px solid rgba(0, 255, 255, 0.3);
        }
        
        .start-wave-btn {
            padding: 15px 40px;
            font-size: 18px;
            background: linear-gradient(135deg, #ff0066, #ff00ff);
            border: none;
            color: white;
            border-radius: 8px;
            cursor: pointer;
            font-family: inherit;
            font-weight: bold;
            text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
            box-shadow: 0 5px 20px rgba(255, 0, 102, 0.4);
            transition: all 0.2s;
        }
        
        .start-wave-btn:hover {
            transform: scale(1.05);
            box-shadow: 0 8px 30px rgba(255, 0, 102, 0.6);
        }
        
        /* HUD 金币显示 */
        #hud-coins {
            position: fixed;
            top: 20px;
            right: 20px;
            color: #ffdd00;
            font-size: 24px;
            font-weight: bold;
            text-shadow: 0 0 15px rgba(255, 221, 0, 0.6);
            z-index: 50;
        }
    </style>
<style>
/* base.css */

        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { 
            overflow: hidden; 
            background: #000;
            font-family: 'Courier New', monospace;
            color: #fff;
        }
        #gameContainer {
            width: 100vw;
            height: 100vh;
            position: relative;
        }
        #crosshair {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 20px;
            height: 20px;
            pointer-events: none;
            z-index: 100;
        }
        #crosshair::before, #crosshair::after {
            content: '';
            position: absolute;
            background: #0ff;
            box-shadow: 0 0 10px #0ff, 0 0 20px #0ff;
        }
        #crosshair::before {
            width: 2px; height: 20px; left: 9px; top: 0;
        }
        #crosshair::after {
            width: 20px; height: 2px; left: 0; top: 9px;
        }
        #hud {
            position: fixed;
            bottom: 20px;
            left: 20px;
            right: 20px;
            display: flex;
            justify-content: space-between;
            z-index: 100;
            pointer-events: none;
        }
        .hud-panel {
            background: rgba(0, 255, 255, 0.1);
            border: 1px solid #0ff;
            box-shadow: 0 0 10px rgba(0, 255, 255, 0.3), inset 0 0 10px rgba(0, 255, 255, 0.1);
            padding: 10px 20px;
            font-size: 16px;
            text-shadow: 0 0 10px #0ff;
        }
        .hud-panel.health {
            color: #f0f;
            border-color: #f0f;
            box-shadow: 0 0 10px rgba(255, 0, 255, 0.3), inset 0 0 10px rgba(255, 0, 255, 0.1);
            text-shadow: 0 0 10px #f0f;
        }
        .hud-panel.score {
            color: #ff0;
            border-color: #ff0;
            box-shadow: 0 0 10px rgba(255, 255, 0, 0.3), inset 0 0 10px rgba(255, 255, 0, 0.1);
            text-shadow: 0 0 10px #ff0;
        }
        .hud-panel.wave {
            color: #0f0;
            border-color: #0f0;
            box-shadow: 0 0 10px rgba(0, 255, 0, 0.3), inset 0 0 10px rgba(0, 255, 0, 0.1);
            text-shadow: 0 0 10px #0f0;
        }
        #startScreen {
            position: fixed;
            top: 0; left: 0; right: 0; bottom: 0;
            background: rgba(0, 0, 0, 0.85);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 200;
            text-align: center;
        }
        #startScreen h1 {
            font-size: 72px;
            color: #0ff;
            text-shadow: 0 0 20px #0ff, 0 0 40px #0ff, 0 0 60px #0ff;
            margin-bottom: 20px;
            letter-spacing: 8px;
            animation: glow 2s ease-in-out infinite alternate;
        }
        @keyframes glow {
            from { text-shadow: 0 0 20px #0ff, 0 0 40px #0ff; }
            to { text-shadow: 0 0 30px #f0f, 0 0 60px #f0f, 0 0 80px #f0f; }
        }
        #startScreen p {
            font-size: 18px;
            color: #aaa;
            margin-bottom: 10px;
        }
        #startScreen .controls {
            margin: 30px 0;
            color: #666;
            line-height: 1.8;
        }
        #startBtn {
            padding: 15px 50px;
            font-size: 24px;
            background: transparent;
            border: 2px solid #0ff;
            color: #0ff;
            cursor: pointer;
            font-family: 'Courier New', monospace;
            text-shadow: 0 0 10px #0ff;
            box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
            transition: all 0.3s;
            margin-top: 20px;
        }
        #startBtn:hover {
            background: rgba(0, 255, 255, 0.2);
            box-shadow: 0 0 40px rgba(0, 255, 255, 0.5);
            transform: scale(1.05);
        }
        #gameOver {
            display: none;
            position: fixed;
            top: 0; left: 0; right: 0; bottom: 0;
            background: rgba(0, 0, 0, 0.9);
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 300;
            text-align: center;
        }
        #gameOver h2 {
            font-size: 64px;
            color: #f00;
            text-shadow: 0 0 20px #f00, 0 0 40px #f00;
            margin-bottom: 20px;
        }
        #gameOver .final-score {
            font-size: 32px;
            color: #ff0;
            text-shadow: 0 0 15px #ff0;
            margin: 20px 0;
        }
        .neon-text {
            color: #0ff;
            text-shadow: 0 0 10px currentColor;
        }
        #weaponDisplay {
            position: fixed;
            bottom: 20px;
            right: 50%;
            transform: translateX(50%);
            z-index: 100;
            pointer-events: none;
        }

        /* Mobile Controls */
        .mobile-controls {
            display: none;
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            height: 200px;
            z-index: 200;
            pointer-events: none;
        }
        
        .joystick-container {
            position: absolute;
            bottom: 30px;
            left: 30px;
            width: 120px;
            height: 120px;
            background: rgba(0, 255, 255, 0.1);
            border: 2px solid rgba(0, 255, 255, 0.3);
            border-radius: 50%;
            pointer-events: auto;
            touch-action: none;
        }
        
        .joystick-knob {
            position: absolute;
            width: 50px;
            height: 50px;
            background: rgba(0, 255, 255, 0.4);
            border: 2px solid rgba(0, 255, 255, 0.6);
            border-radius: 50%;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            box-shadow: 0 0 15px rgba(0, 255, 255, 0.5);
        }
        
        .fire-btn {
            position: absolute;
            bottom: 50px;
            right: 40px;
            width: 80px;
            height: 80px;
            background: rgba(255, 0, 100, 0.3);
            border: 3px solid rgba(255, 0, 100, 0.6);
            border-radius: 50%;
            pointer-events: auto;
            touch-action: none;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #ff0064;
            font-weight: bold;
            font-size: 14px;
            text-shadow: 0 0 10px #ff0064;
            box-shadow: 0 0 20px rgba(255, 0, 100, 0.3);
            user-select: none;
        }
        
        .fire-btn:active {
            background: rgba(255, 0, 100, 0.5);
            transform: scale(0.95);
        }
        
        .jump-btn {
            position: absolute;
            bottom: 140px;
            right: 60px;
            width: 60px;
            height: 60px;
            background: rgba(0, 255, 255, 0.2);
            border: 2px solid rgba(0, 255, 255, 0.5);
            border-radius: 50%;
            pointer-events: auto;
            touch-action: none;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #0ff;
            font-size: 12px;
            font-weight: bold;
            user-select: none;
        }
        
        .weapon-buttons {
            position: absolute;
            bottom: 30px;
            right: 140px;
            display: flex;
            gap: 8px;
            pointer-events: auto;
        }
        
        .weapon-btn {
            width: 45px;
            height: 45px;
            background: rgba(255, 255, 0, 0.2);
            border: 2px solid rgba(255, 255, 0, 0.5);
            border-radius: 8px;
            color: #ff0;
            font-size: 11px;
            font-weight: bold;
            display: flex;
            align-items: center;
            justify-content: center;
            touch-action: none;
            user-select: none;
        }
        
        .weapon-btn.active {
            background: rgba(255, 255, 0, 0.5);
            box-shadow: 0 0 15px rgba(255, 255, 0, 0.5);
        }
        
        .touch-look-zone {
            position: fixed;
            top: 0;
            right: 0;
            width: 50%;
            height: 100%;
            z-index: 50;
            pointer-events: auto;
            touch-action: none;
            display: none;
        }
        
        @media (max-width: 768px) {
            .mobile-controls {
                display: block;
            }
            .touch-look-zone {
                display: block;
            }
            #startScreen h1 {
                font-size: 36px;
            }
            #startScreen .controls {
                font-size: 12px;
                margin: 15px 0;
            }
            #startBtn {
                padding: 12px 30px;
                font-size: 18px;
            }
            .hud-panel {
                font-size: 14px;
                padding: 8px 12px;
            }
            #gameOver h2 {
                font-size: 36px;
            }
            #gameOver .final-score {
                font-size: 24px;
            }
        }
        
        @media (hover: none) and (pointer: coarse) {
            .mobile-controls { display: block; }
            .touch-look-zone { display: block; }
        }

    

/* hud.css */
/* hud.css */

/* menu.css */
/* menu.css */

/* mobile.css */
/* mobile.css */

/* effects.css */
/* effects.css */


</style>
</head>
<body>
    <div id="game-container"></div>
    <div id="damage-flash"></div>
    <div id="hud-coins" style="display:none;">💰 0</div>
    
    <!-- 商店界面 -->
    <div id="shopOverlay">
        <div id="shopContent"></div>
    </div>
    
    <!-- Three.js CDN -->
    
    
    <!-- 基础工具 -->
    
    <!-- 核心系统 -->
    
    <!-- UI系统 -->
    
    <!-- 游戏系统 -->
    
    <!-- 移动端 -->
    
    <!-- 自动演示 -->
    
    <!-- 游戏主循环 -->
    
    <!-- 入口 -->
    
    <script>
        // 页面加载完成后初始化
        window.addEventListener('load', () => {
            // 隐藏加载画面
            const loading = document.getElementById('loading-screen');
            if (loading) {
                setTimeout(() => {
                    loading.style.opacity = '0';
                    setTimeout(() => loading.style.display = 'none', 500);
                }, 500);
            }
        });
        
        // 点击画布锁定指针(PC端)
        document.addEventListener('click', (e) => {
            if (gameState && gameState.isPlaying && !input.isMobile) {
                input.requestPointerLock(renderer.domElement || renderer.renderer.domElement);
            }
        });
        
        // 首次交互时初始化音频(浏览器策略)
        const initAudioOnFirstInteraction = () => {
            if (audio && audio.init) {
                audio.init();
            }
            document.removeEventListener('click', initAudioOnFirstInteraction);
            document.removeEventListener('touchstart', initAudioOnFirstInteraction);
        };
        
        document.addEventListener('click', initAudioOnFirstInteraction);
        document.addEventListener('touchstart', initAudioOnFirstInteraction);
    </script>
<script>
// utils.js
// 工具函数
const Utils = {
    // 随机数
    randomRange(min, max) {
        return Math.random() * (max - min) + min;
    },
    
    // 随机整数
    randomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    },
    
    // 限制值范围
    clamp(value, min, max) {
        return Math.max(min, Math.min(max, value));
    },
    
    // 线性插值
    lerp(a, b, t) {
        return a + (b - a) * t;
    },
    
    // 距离计算
    distance(x1, y1, x2, y2) {
        const dx = x2 - x1;
        const dy = y2 - y1;
        return Math.sqrt(dx * dx + dy * dy);
    },
    
    // 角度转弧度
    degToRad(degrees) {
        return degrees * Math.PI / 180;
    },
    
    // 弧度转角度
    radToDeg(radians) {
        return radians * 180 / Math.PI;
    },
    
    // 随机颜色
    randomColor() {
        return Math.floor(Math.random() * 0xffffff);
    },
    
    // HSL转RGB(用于生成霓虹色)
    hslToHex(h, s, l) {
        const c = (1 - Math.abs(2 * l - 1)) * s;
        const x = c * (1 - Math.abs((h / 60) % 2 - 1));
        const m = l - c / 2;
        let r, g, b;
        
        if (h < 60) { r = c; g = x; b = 0; }
        else if (h < 120) { r = x; g = c; b = 0; }
        else if (h < 180) { r = 0; g = c; b = x; }
        else if (h < 240) { r = 0; g = x; b = c; }
        else if (h < 300) { r = x; g = 0; b = c; }
        else { r = c; g = 0; b = x; }
        
        return Math.round((r + m) * 255) << 16 | 
               Math.round((g + m) * 255) << 8 | 
               Math.round((b + m) * 255);
    },
    
    // 生成霓虹色
    neonColor(hue) {
        return this.hslToHex(hue, 1, 0.5);
    },
    
    // 格式化数字
    formatNumber(num) {
        if (num >= 1000000) {
            return (num / 1000000).toFixed(1) + 'M';
        }
        if (num >= 1000) {
            return (num / 1000).toFixed(1) + 'K';
        }
        return num.toString();
    },
    
    // 简单的 UUID 生成
    uuid() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            const r = Math.random() * 16 | 0;
            const v = c === 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    },
    
    // 检测移动设备
    isMobile() {
        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
            || ('ontouchstart' in window)
            || (navigator.maxTouchPoints > 0);
    },
    
    // 创建 THREE.js 材质的快捷方式
    createNeonMaterial(color, emissiveIntensity = 0.5) {
        return new THREE.MeshStandardMaterial({
            color: color,
            emissive: color,
            emissiveIntensity: emissiveIntensity,
            metalness: 0.3,
            roughness: 0.7
        });
    }
};

// 旧版兼容 - 全局函数
function createLaserBeam(start, end, color) {
    if (particles) {
        return particles.createLaserBeam(start, end, color);
    }
    return null;
}

function playShootSound() {
    if (audio) {
        audio.playShoot('pistol');
    }
}


// config.js
// 游戏配置
const CONFIG = {
    // 渲染
    FOV: 75,
    NEAR: 0.1,
    FAR: 1000,
    FOG_COLOR: 0x0a0a1a,
    FOG_DENSITY: 0.02,
    
    // 玩家
    PLAYER_SPEED: 8,
    PLAYER_SPRINT_SPEED: 14,
    PLAYER_JUMP_FORCE: 12,
    PLAYER_GRAVITY: 25,
    PLAYER_MOUSE_SENSITIVITY: 0.002,
    PLAYER_MAX_HEALTH: 100,
    
    // 竞技场
    ARENA_SIZE: 40,
    
    // 波次
    WAVE_BREAK_TIME: 5,
    ENEMIES_PER_WAVE_BASE: 5,
    ENEMIES_PER_WAVE_INCREMENT: 3,
    BOSS_WAVE_INTERVAL: 5,  // 每5波出现Boss
    
    // Boss配置
    BOSSES: {
        cyberTitan: {
            name: '赛博泰坦',
            health: 1000,
            speed: 1.2,
            damage: 40,
            score: 1000,
            color: 0xff0066,
            size: 3,
            phase2Health: 0.5, // 50%血量进入第二阶段
            abilities: ['slam', 'summon', 'laser']
        },
        voidWalker: {
            name: '虚空行者',
            health: 800,
            speed: 3,
            damage: 35,
            score: 800,
            color: 0x8800ff,
            size: 2,
            phase2Health: 0.4,
            abilities: ['teleport', 'shadowClones', 'voidBlast']
        },
        plasmaCore: {
            name: '等离子核心',
            health: 1200,
            speed: 0.5,
            damage: 50,
            score: 1200,
            color: 0x00ffff,
            size: 2.5,
            phase2Health: 0.3,
            abilities: ['plasmaRain', 'shield', 'overload']
        }
    },
    
    // 武器配置
    WEAPONS: {
        pistol: {
            name: '脉冲手枪',
            damage: 15,
            fireRate: 250,
            bulletSpeed: 60,
            color: 0x00ffff,
            ammo: Infinity,
            spread: 0.02,
            price: 0,
            unlocked: true,
            description: '基础武器,平衡的射速和伤害'
        },
        shotgun: {
            name: '等离子霰弹',
            damage: 8,
            pellets: 8,
            fireRate: 800,
            bulletSpeed: 45,
            color: 0xff6600,
            ammo: Infinity,
            spread: 0.15,
            price: 200,
            unlocked: false,
            description: '近距离毁灭性武器,8发弹丸扇形射出'
        },
        laser: {
            name: '光束激光',
            damage: 50,
            fireRate: 600,
            color: 0xff00ff,
            ammo: Infinity,
            hitscan: true,
            price: 300,
            unlocked: false,
            description: '瞬时命中的高精度激光,无视距离'
        },
        smg: {
            name: '霓虹冲锋枪',
            damage: 6,
            fireRate: 80,
            bulletSpeed: 55,
            color: 0x00ff88,
            ammo: Infinity,
            spread: 0.08,
            price: 250,
            unlocked: false,
            description: '超高射速的冲锋枪,弹幕压制神器'
        },
        rocket: {
            name: '爆裂火箭筒',
            damage: 80,
            splashRadius: 5,
            splashDamage: 40,
            fireRate: 1500,
            bulletSpeed: 25,
            color: 0xff4400,
            ammo: Infinity,
            spread: 0.01,
            price: 400,
            unlocked: false,
            description: '范围伤害武器,爆炸溅射伤害敌人'
        },
        plasma: {
            name: '等离子步枪',
            damage: 25,
            fireRate: 350,
            bulletSpeed: 50,
            color: 0x00ffaa,
            ammo: Infinity,
            spread: 0.03,
            burnDamage: 5,
            burnDuration: 3,
            price: 350,
            unlocked: false,
            description: '中等射速,命中造成持续灼烧伤害'
        },
        sword: {
            name: '能量武士刀',
            damage: 40,
            fireRate: 500,
            range: 2.5,
            color: 0x00ff88,
            price: 150,
            unlocked: false,
            description: '强大的近战武器,攻速快,伤害高'
        }
    },
    
    // 敌人配置
    ENEMY_TYPES: {
        drone: {
            name: '无人机',
            health: 20,
            speed: 4,
            damage: 5,
            score: 10,
            color: 0x00ff00,
            size: 0.6
        },
        grunt: {
            name: '步兵',
            health: 40,
            speed: 2.5,
            damage: 10,
            score: 25,
            color: 0xffff00,
            size: 1
        },
        tank: {
            name: '重装',
            health: 150,
            speed: 1.5,
            damage: 25,
            score: 100,
            color: 0xff0000,
            size: 1.8,
            knockbackResist: 0.7
        },
        bomber: {
            name: '爆破手',
            health: 30,
            speed: 2,
            damage: 30,
            score: 50,
            color: 0xff8800,
            size: 0.9,
            range: 12,
            projectileSpeed: 8
        },
        pouncer: {
            name: '突击者',
            health: 35,
            speed: 5,
            damage: 20,
            score: 75,
            color: 0x8800ff,
            size: 0.8,
            leapForce: 15
        }
    },
    
    // 可玩角色
    CHARACTERS: {
        soldier: {
            name: '战士 - 雷克斯',
            description: '经验丰富的老兵,擅长使用各种武器',
            healthBonus: 50,
            speedBonus: 0,
            damageBonus: 0.1,
            special: '狂暴 - 短时间内伤害翻倍',
            color: 0xff4444
        },
        ninja: {
            name: '忍者 - 影',
            description: '敏捷的刺客,近战无敌',
            healthBonus: -20,
            speedBonus: 3,
            damageBonus: 0.3,
            special: '疾风步 - 短暂无敌并加速',
            color: 0x8844ff
        },
        engineer: {
            name: '工程师 - 齿轮',
            description: '技术天才,能召唤炮塔辅助',
            healthBonus: 20,
            speedBonus: -1,
            damageBonus: 0,
            special: '召唤炮塔 - 自动攻击敌人',
            color: 0xffaa00
        },
        medic: {
            name: '医疗兵 - 曙光',
            description: '团队的守护者,持续回复生命',
            healthBonus: 30,
            speedBonus: 1,
            damageBonus: -0.1,
            special: '治疗脉冲 - 瞬间回复大量生命',
            color: 0x44ff88
        }
    },
    
    // 音效
    SOUND_ENABLED: true,
    
    // 移动端
    MOBILE_JOYSTICK_SIZE: 80,
    MOBILE_SENSITIVITY: 0.005,
    
    // 武器升级
    WEAPON_UPGRADES: {
        damage: { name: '伤害提升', maxLevel: 5, bonusPerLevel: 0.15 },
        fireRate: { name: '射速提升', maxLevel: 5, bonusPerLevel: 0.12 },
        speed: { name: '子弹速度', maxLevel: 3, bonusPerLevel: 0.2 }
    },
    
    // 拾取物
    PICKUPS: {
        health: { name: '生命包', color: 0x00ff00, healAmount: 30, spawnChance: 0.15 },
        damageBoost: { name: '伤害加成', color: 0xff0000, duration: 10, multiplier: 1.5, spawnChance: 0.08 },
        speedBoost: { name: '速度加成', color: 0xffff00, duration: 10, multiplier: 1.5, spawnChance: 0.08 },
        shield: { name: '护盾', color: 0x00ffff, shieldAmount: 50, spawnChance: 0.05 },
        coin: { name: '能量核心', color: 0xffdd00, scoreValue: 50, spawnChance: 0.3 }
    },
    
    // 成就系统
    ACHIEVEMENTS: {
        first_blood: { name: '初次击杀', description: '击杀第一个敌人', icon: '💀' },
        wave_5: { name: '小有成就', description: '坚持到第5波', icon: '🎯' },
        wave_10: { name: '生存专家', description: '坚持到第10波', icon: '🏆' },
        wave_20: { name: '传奇战士', description: '坚持到第20波', icon: '👑' },
        boss_killer: { name: '屠龙勇士', description: '击败第一个Boss', icon: '🐉' },
        combo_10: { name: '连击大师', description: '连续击杀10个敌人', icon: '⚡' },
        perfect_wave: { name: '完美闪避', description: '一波内不受任何伤害', icon: '✨' },
        melee_master: { name: '近战大师', description: '用武士刀击杀50个敌人', icon: '🗡️' },
        speedrunner: { name: '极速通关', description: '5分钟内达到第10波', icon: '⏱️' },
        collector: { name: '收集者', description: '拾取20个能量核心', icon: '💎' }
    }
};

if (typeof module !== 'undefined' && module.exports) {
    module.exports = CONFIG;
}


// audio.js
// 音频系统 - 使用 Web Audio API 生成音效,无需外部文件
class AudioSystem {
    constructor() {
        this.audioContext = null;
        this.masterGain = null;
        this.enabled = true;
        this.initialized = false;
    }
    
    init() {
        if (this.initialized) return this;
        
        try {
            this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
            this.masterGain = this.audioContext.createGain();
            this.masterGain.gain.value = 0.3;
            this.masterGain.connect(this.audioContext.destination);
            this.initialized = true;
        } catch (e) {
            console.log('Audio not supported:', e);
            this.enabled = false;
        }
        
        return this;
    }
    
    ensureContext() {
        if (!this.audioContext) {
            this.init();
        }
        // 恢复被浏览器挂起的音频上下文
        if (this.audioContext && this.audioContext.state === 'suspended') {
            this.audioContext.resume();
        }
    }
    
    playTone(frequency, duration, type = 'square', volume = 0.3) {
        if (!this.enabled || !this.audioContext) return;
        
        this.ensureContext();
        
        const oscillator = this.audioContext.createOscillator();
        const gainNode = this.audioContext.createGain();
        
        oscillator.type = type;
        oscillator.frequency.setValueAtTime(frequency, this.audioContext.currentTime);
        
        gainNode.gain.setValueAtTime(volume, this.audioContext.currentTime);
        gainNode.gain.exponentialRampToValueAtTime(0.001, this.audioContext.currentTime + duration);
        
        oscillator.connect(gainNode);
        gainNode.connect(this.masterGain);
        
        oscillator.start();
        oscillator.stop(this.audioContext.currentTime + duration);
    }
    
    playNoise(duration, volume = 0.2, filterFreq = 1000) {
        if (!this.enabled || !this.audioContext) return;
        
        this.ensureContext();
        
        const bufferSize = this.audioContext.sampleRate * duration;
        const buffer = this.audioContext.createBuffer(1, bufferSize, this.audioContext.sampleRate);
        const data = buffer.getChannelData(0);
        
        for (let i = 0; i < bufferSize; i++) {
            data[i] = Math.random() * 2 - 1;
        }
        
        const noise = this.audioContext.createBufferSource();
        noise.buffer = buffer;
        
        const filter = this.audioContext.createBiquadFilter();
        filter.type = 'lowpass';
        filter.frequency.value = filterFreq;
        
        const gainNode = this.audioContext.createGain();
        gainNode.gain.setValueAtTime(volume, this.audioContext.currentTime);
        gainNode.gain.exponentialRampToValueAtTime(0.001, this.audioContext.currentTime + duration);
        
        noise.connect(filter);
        filter.connect(gainNode);
        gainNode.connect(this.masterGain);
        
        noise.start();
    }
    
    // 射击音效
    playShoot(weaponType = 'pistol') {
        if (!this.enabled) return;
        
        switch (weaponType) {
            case 'pistol':
                this.playTone(800, 0.08, 'square', 0.15);
                this.playNoise(0.05, 0.1, 2000);
                break;
            case 'shotgun':
                this.playNoise(0.15, 0.25, 500);
                this.playTone(150, 0.1, 'sawtooth', 0.15);
                break;
            case 'laser':
                this.playTone(1200, 0.15, 'sine', 0.1);
                this.playTone(600, 0.1, 'sine', 0.08);
                break;
            case 'sword':
                this.playNoise(0.08, 0.15, 3000);
                break;
        }
    }
    
    // 命中音效
    playHit() {
        if (!this.enabled) return;
        this.playTone(200, 0.1, 'square', 0.2);
        this.playNoise(0.05, 0.1, 800);
    }
    
    // 击杀音效
    playKill() {
        if (!this.enabled) return;
        this.playTone(300, 0.15, 'square', 0.15);
        this.playTone(150, 0.2, 'sine', 0.1);
    }
    
    // 玩家受伤
    playHurt() {
        if (!this.enabled) return;
        this.playTone(100, 0.2, 'sawtooth', 0.2);
        this.playNoise(0.1, 0.15, 400);
    }
    
    // 跳跃
    playJump() {
        if (!this.enabled) return;
        this.playTone(200, 0.1, 'sine', 0.1);
    }
    
    // 翻滚/闪避
    playDodge() {
        if (!this.enabled) return;
        this.playNoise(0.1, 0.1, 1500);
    }
    
    // 波次开始
    playWaveStart() {
        if (!this.enabled) return;
        this.playTone(440, 0.15, 'sine', 0.15);
        setTimeout(() => this.playTone(550, 0.15, 'sine', 0.15), 100);
        setTimeout(() => this.playTone(660, 0.2, 'sine', 0.15), 200);
    }
    
    // 波次完成
    playWaveComplete() {
        if (!this.enabled) return;
        this.playTone(523, 0.1, 'sine', 0.15);
        setTimeout(() => this.playTone(659, 0.1, 'sine', 0.15), 100);
        setTimeout(() => this.playTone(784, 0.15, 'sine', 0.15), 200);
        setTimeout(() => this.playTone(1047, 0.3, 'sine', 0.15), 300);
    }
    
    // 游戏结束
    playGameOver() {
        if (!this.enabled) return;
        this.playTone(400, 0.3, 'sawtooth', 0.2);
        setTimeout(() => this.playTone(300, 0.3, 'sawtooth', 0.2), 200);
        setTimeout(() => this.playTone(200, 0.5, 'sawtooth', 0.2), 400);
    }
    
    // 切换武器
    playWeaponSwitch() {
        if (!this.enabled) return;
        this.playTone(600, 0.05, 'square', 0.1);
    }
    
    // 治疗
    playHeal() {
        if (!this.enabled) return;
        this.playTone(523, 0.1, 'sine', 0.1);
        setTimeout(() => this.playTone(659, 0.1, 'sine', 0.1), 80);
        setTimeout(() => this.playTone(784, 0.15, 'sine', 0.1), 160);
    }
    
    // 特殊技能
    playSpecial() {
        if (!this.enabled) return;
        // 上升音效
        for (let i = 0; i < 5; i++) {
            setTimeout(() => {
                this.playTone(200 + i * 100, 0.1, 'sine', 0.1 - i * 0.01);
            }, i * 30);
        }
    }
    
    // 拾取物
    playPickup() {
        if (!this.enabled) return;
        this.playTone(880, 0.08, 'sine', 0.12);
        setTimeout(() => this.playTone(1100, 0.08, 'sine', 0.12), 50);
        setTimeout(() => this.playTone(1320, 0.12, 'sine', 0.1), 100);
    }
    
    // 成就解锁
    playAchievement() {
        if (!this.enabled) return;
        // 欢快的上升音阶
        const notes = [523, 659, 784, 1047, 1319];
        notes.forEach((freq, i) => {
            setTimeout(() => {
                this.playTone(freq, 0.15, 'sine', 0.12);
            }, i * 60);
        });
    }
    
    // Boss技能
    playBossAbility() {
        if (!this.enabled) return;
        this.playTone(80, 0.3, 'sawtooth', 0.2);
        this.playNoise(0.2, 0.15, 200);
    }
    
    // Boss阶段转换
    playBossPhase() {
        if (!this.enabled) return;
        // 警报声
        for (let i = 0; i < 3; i++) {
            setTimeout(() => {
                this.playTone(400, 0.15, 'square', 0.15);
                setTimeout(() => this.playTone(600, 0.15, 'square', 0.15), 100);
            }, i * 300);
        }
    }
    
    // Boss死亡
    playBossDeath() {
        if (!this.enabled) return;
        // 低沉的爆炸音效
        this.playTone(100, 0.5, 'sawtooth', 0.25);
        this.playNoise(0.5, 0.2, 100);
        setTimeout(() => {
            this.playTone(50, 0.6, 'sine', 0.2);
        }, 100);
    }
    
    // 商店打开
    playShopOpen() {
        if (!this.enabled) return;
        // 清脆的开门音效
        const notes = [392, 523, 659, 784];
        notes.forEach((freq, i) => {
            setTimeout(() => {
                this.playTone(freq, 0.12, 'sine', 0.12);
            }, i * 50);
        });
    }
    
    // 升级购买
    playUpgrade() {
        if (!this.enabled) return;
        // 金币+升级的音效
        this.playTone(880, 0.08, 'square', 0.1);
        setTimeout(() => this.playTone(1100, 0.1, 'sine', 0.12), 50);
        setTimeout(() => this.playTone(1320, 0.15, 'sine', 0.1), 100);
    }
    
    toggle() {
        this.enabled = !this.enabled;
        if (this.masterGain) {
            this.masterGain.gain.value = this.enabled ? 0.3 : 0;
        }
        return this.enabled;
    }
}

const audio = new AudioSystem();


// particles.js
// 粒子系统
class ParticleSystem {
    constructor() {
        this.particles = [];
        this.effects = []; // 特效对象(激光束等)
    }
    
    init() {
        this.particles = [];
        this.effects = [];
        return this;
    }
    
    createExplosion(position, color, count = 20, size = 1) {
        for (let i = 0; i < count; i++) {
            const particle = new THREE.Mesh(
                new THREE.SphereGeometry(0.1 * size, 4, 4),
                new THREE.MeshBasicMaterial({ 
                    color: color, 
                    transparent: true, 
                    opacity: 1 
                })
            );
            particle.position.copy(position);
            particle.userData = {
                velocity: new THREE.Vector3(
                    (Math.random() - 0.5) * 8 * size,
                    Math.random() * 6 * size,
                    (Math.random() - 0.5) * 8 * size
                ),
                life: 1 + Math.random() * 0.5,
                maxLife: 1.5,
                gravity: -15
            };
            renderer.scene.add(particle);
            this.particles.push(particle);
        }
    }
    
    createHitEffect(position, color) {
        for (let i = 0; i < 8; i++) {
            const particle = new THREE.Mesh(
                new THREE.SphereGeometry(0.05, 4, 4),
                new THREE.MeshBasicMaterial({ 
                    color: color, 
                    transparent: true, 
                    opacity: 1 
                })
            );
            particle.position.copy(position);
            particle.userData = {
                velocity: new THREE.Vector3(
                    (Math.random() - 0.5) * 5,
                    Math.random() * 3,
                    (Math.random() - 0.5) * 5
                ),
                life: 0.3 + Math.random() * 0.2,
                maxLife: 0.5,
                gravity: -5
            };
            renderer.scene.add(particle);
            this.particles.push(particle);
        }
    }
    
    createMuzzleFlash(position, color, intensity = 1) {
        const flash = new THREE.Mesh(
            new THREE.SphereGeometry(0.2 * intensity, 8, 8),
            new THREE.MeshBasicMaterial({ 
                color: color, 
                transparent: true, 
                opacity: 0.8 
            })
        );
        flash.position.copy(position);
        flash.userData = {
            life: 0.05,
            maxLife: 0.05,
            isFlash: true,
            growSpeed: 5 * intensity
        };
        renderer.scene.add(flash);
        this.particles.push(flash);
    }
    
    createLaserBeam(start, end, color) {
        const points = [start, end];
        const geometry = new THREE.BufferGeometry().setFromPoints(points);
        const material = new THREE.LineBasicMaterial({ 
            color: color, 
            linewidth: 2,
            transparent: true,
            opacity: 1
        });
        const line = new THREE.Line(geometry, material);
        line.userData = { 
            life: 0.1, 
            maxLife: 0.1,
            isLaser: true 
        };
        renderer.scene.add(line);
        this.effects.push(line);
        return line;
    }
    
    createDamageNumber(position, amount, isCrit = false) {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 64;
        canvas.height = 32;
        
        ctx.font = 'bold 24px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        
        if (isCrit) {
            ctx.fillStyle = '#ff4444';
            ctx.font = 'bold 28px Arial';
        } else {
            ctx.fillStyle = '#ffff00';
        }
        
        ctx.fillText(amount.toString(), 32, 16);
        
        const texture = new THREE.CanvasTexture(canvas);
        const material = new THREE.SpriteMaterial({ 
            map: texture, 
            transparent: true 
        });
        const sprite = new THREE.Sprite(material);
        sprite.position.copy(position);
        sprite.scale.set(1, 0.5, 1);
        sprite.userData = {
            life: 1,
            maxLife: 1,
            velocity: new THREE.Vector3(0, 2, 0),
            isDamageNumber: true
        };
        
        renderer.scene.add(sprite);
        this.particles.push(sprite);
    }
    
    update(deltaTime) {
        // 更新粒子
        for (let i = this.particles.length - 1; i >= 0; i--) {
            const p = this.particles[i];
            const data = p.userData;
            
            data.life -= deltaTime;
            
            if (data.life <= 0) {
                renderer.scene.remove(p);
                this.particles.splice(i, 1);
                continue;
            }
            
            // 物理更新
            if (data.velocity) {
                if (data.gravity !== undefined) {
                    data.velocity.y += data.gravity * deltaTime;
                }
                p.position.addScaledVector(data.velocity, deltaTime);
            }
            
            // 透明度衰减
            if (p.material && p.material.opacity !== undefined) {
                p.material.opacity = (data.life / data.maxLife) * (data.baseOpacity || 1);
            }
            
            // 放大(枪口火焰)
            if (data.isFlash && data.growSpeed) {
                const scale = 1 + (1 - data.life / data.maxLife) * data.growSpeed;
                p.scale.setScalar(scale);
            }
        }
        
        // 更新特效
        for (let i = this.effects.length - 1; i >= 0; i--) {
            const effect = this.effects[i];
            const data = effect.userData;
            
            data.life -= deltaTime;
            
            if (data.life <= 0) {
                renderer.scene.remove(effect);
                this.effects.splice(i, 1);
                continue;
            }
            
            // 淡出
            if (effect.material && effect.material.opacity !== undefined) {
                effect.material.opacity = data.life / data.maxLife;
            }
        }
    }
    
    clear() {
        for (const p of this.particles) {
            renderer.scene.remove(p);
        }
        for (const e of this.effects) {
            renderer.scene.remove(e);
        }
        this.particles = [];
        this.effects = [];
    }
}

const particles = new ParticleSystem();


// effects.js
// 视觉特效系统
class Effects {
    constructor() {
        this.screenShakeAmount = 0;
        this.screenShakeDecay = 0.92;
        this.damageFlashAlpha = 0;
        this.hitStopFrames = 0;
        this.slowMotionFactor = 1;
        this.slowMotionDuration = 0;
        this.screenGlow = null;
    }
    
    init() {
        // 创建屏幕光晕
        this.createScreenGlow();
        return this;
    }
    
    createScreenGlow() {
        // 可以通过CSS实现全屏光晕
        const glow = document.createElement('div');
        glow.id = 'screen-glow';
        glow.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 50;
            opacity: 0;
            transition: opacity 0.1s;
            mix-blend-mode: screen;
        `;
        document.body.appendChild(glow);
        this.screenGlow = glow;
    }
    
    shake(amount, duration = 0.1) {
        this.screenShakeAmount = Math.max(this.screenShakeAmount, amount);
    }
    
    updateScreenShake(deltaTime) {
        if (this.screenShakeAmount > 0.001 && renderer && renderer.camera) {
            const shakeX = (Math.random() - 0.5) * this.screenShakeAmount;
            const shakeY = (Math.random() - 0.5) * this.screenShakeAmount;
            
            renderer.camera.position.x += shakeX;
            renderer.camera.position.y += shakeY;
            
            this.screenShakeAmount *= Math.pow(this.screenShakeDecay, deltaTime * 60);
        }
    }
    
    showDamageFlash(alpha = 0.5) {
        this.damageFlashAlpha = alpha;
        
        // CSS伤害闪红
        const flash = document.getElementById('damage-flash');
        if (flash) {
            flash.style.background = 'radial-gradient(ellipse at center, transparent 40%, rgba(255, 0, 0, 0.5) 100%)';
            flash.style.opacity = alpha;
            setTimeout(() => {
                flash.style.opacity = 0;
            }, 100);
        }
    }
    
    hitStop(frames = 3) {
        this.hitStopFrames = frames;
    }
    
    slowMotion(factor, duration) {
        this.slowMotionFactor = factor;
        this.slowMotionDuration = duration;
    }
    
    updateSlowMotion(deltaTime) {
        if (this.slowMotionDuration > 0) {
            this.slowMotionDuration -= deltaTime;
            if (this.slowMotionDuration <= 0) {
                this.slowMotionFactor = 1;
            }
        }
    }
    
    showScreenGlow(color, intensity = 0.3) {
        if (this.screenGlow) {
            const hex = '#' + color.toString(16).padStart(6, '0');
            this.screenGlow.style.background = `radial-gradient(ellipse at center, ${hex}40 0%, transparent 70%)`;
            this.screenGlow.style.opacity = intensity;
        }
    }
    
    hideScreenGlow() {
        if (this.screenGlow) {
            this.screenGlow.style.opacity = 0;
        }
    }
    
    // 包装粒子系统的方法
    createExplosion(position, color, size = 1) {
        if (particles) {
            particles.createExplosion(position, color, Math.floor(20 * size), size);
        }
    }
    
    createHitEffect(position, color) {
        if (particles) {
            particles.createHitEffect(position, color);
        }
    }
    
    createMuzzleFlash(position, color, intensity = 1) {
        if (particles) {
            particles.createMuzzleFlash(position, color, intensity);
        }
    }
    
    createLaserBeam(start, end, color) {
        if (particles) {
            particles.createLaserBeam(start, end, color);
        }
    }
    
    createDamageNumber(position, amount, isCrit = false) {
        if (particles) {
            particles.createDamageNumber(position, amount, isCrit);
        }
    }
    
    update(deltaTime) {
        // 更新屏幕震动
        this.updateScreenShake(deltaTime);
        
        // 更新慢动作
        // this.updateSlowMotion(deltaTime); // 在gameLoop中处理
        
        // 更新粒子
        if (particles) {
            particles.update(deltaTime);
        }
    }
}

const effects = new Effects();


// gameState.js
// 游戏状态管理
class GameState {
    constructor() {
        this.state = 'menu'; // menu, playing, paused, gameover, characterSelect
        this.score = 0;
        this.wave = 0;
        this.kills = 0;
        this.selectedCharacter = 'soldier';
        this.difficulty = 'normal';
    }
    
    setState(newState) {
        const oldState = this.state;
        this.state = newState;
        
        // 触发状态变化事件
        document.dispatchEvent(new CustomEvent('gameStateChange', {
            detail: { oldState, newState }
        }));
        
        console.log(`Game state: ${oldState} -> ${newState}`);
    }
    
    isPlaying() {
        return this.state === 'playing';
    }
    
    isPaused() {
        return this.state === 'paused';
    }
    
    isGameOver() {
        return this.state === 'gameover';
    }
    
    addScore(points) {
        this.score += points;
        document.dispatchEvent(new CustomEvent('scoreUpdate', { detail: { score: this.score } }));
    }
    
    addKill() {
        this.kills++;
        document.dispatchEvent(new CustomEvent('killUpdate', { detail: { kills: this.kills } }));
    }
    
    nextWave() {
        this.wave++;
        document.dispatchEvent(new CustomEvent('waveUpdate', { detail: { wave: this.wave } }));
    }
    
    reset() {
        this.score = 0;
        this.wave = 0;
        this.kills = 0;
        this.state = 'menu';
    }
}

const gameState = new GameState();


// renderer.js
// 渲染器模块
class Renderer {
    constructor() {
        this.renderer = null;
        this.scene = null;
        this.camera = null;
        this.container = null;
    }
    
    init(containerId = 'game-container') {
        this.container = document.getElementById(containerId) || document.body;
        
        // 创建场景
        this.scene = new THREE.Scene();
        this.scene.background = new THREE.Color(CONFIG.FOG_COLOR);
        this.scene.fog = new THREE.FogExp2(CONFIG.FOG_COLOR, CONFIG.FOG_DENSITY);
        
        // 创建相机
        this.camera = new THREE.PerspectiveCamera(
            CONFIG.FOV,
            window.innerWidth / window.innerHeight,
            CONFIG.NEAR,
            CONFIG.FAR
        );
        this.camera.position.set(0, 1.6, 0);
        this.scene.add(this.camera);
        
        // 创建渲染器
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        this.renderer.shadowMap.enabled = true;
        this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        this.container.appendChild(this.renderer.domElement);
        
        // 添加光照
        this.setupLights();
        
        // 窗口大小变化
        window.addEventListener('resize', () => this.onResize());
        
        return this;
    }
    
    setupLights() {
        // 环境光
        const ambientLight = new THREE.AmbientLight(0x404080, 0.4);
        this.scene.add(ambientLight);
        
        // 主方向光
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight.position.set(10, 20, 10);
        directionalLight.castShadow = true;
        directionalLight.shadow.mapSize.width = 2048;
        directionalLight.shadow.mapSize.height = 2048;
        directionalLight.shadow.camera.near = 0.5;
        directionalLight.shadow.camera.far = 100;
        directionalLight.shadow.camera.left = -30;
        directionalLight.shadow.camera.right = 30;
        directionalLight.shadow.camera.top = 30;
        directionalLight.shadow.camera.bottom = -30;
        this.scene.add(directionalLight);
        
        // 霓虹补光
        const neonLight1 = new THREE.PointLight(0x00ffff, 1, 30);
        neonLight1.position.set(-15, 5, -15);
        this.scene.add(neonLight1);
        
        const neonLight2 = new THREE.PointLight(0xff00ff, 1, 30);
        neonLight2.position.set(15, 5, 15);
        this.scene.add(neonLight2);
        
        const neonLight3 = new THREE.PointLight(0xffff00, 0.8, 25);
        neonLight3.position.set(0, 8, 0);
        this.scene.add(neonLight3);
    }
    
    onResize() {
        if (!this.camera || !this.renderer) return;
        this.camera.aspect = window.innerWidth / window.innerHeight;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
    }
    
    render() {
        if (this.renderer && this.scene && this.camera) {
            this.renderer.render(this.scene, this.camera);
        }
    }
    
    get domElement() {
        return this.renderer ? this.renderer.domElement : null;
    }
}

// 全局渲染器实例
const renderer = new Renderer();


// input.js
// 输入系统
class InputManager {
    constructor() {
        this.keys = {};
        this.mouse = { x: 0, y: 0, dx: 0, dy: 0, locked: false };
        this.mouseButtons = { left: false, right: false, middle: false };
        this.touch = { active: false, startX: 0, startY: 0, currentX: 0, currentY: 0 };
        
        this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
    }
    
    init() {
        // 键盘事件
        document.addEventListener('keydown', (e) => {
            this.keys[e.code] = true;
            this.keys[e.key.toLowerCase()] = true;
            
            // ESC暂停
            if (e.code === 'Escape' && gameState.isPlaying()) {
                gameState.setState('paused');
            }
        });
        
        document.addEventListener('keyup', (e) => {
            this.keys[e.code] = false;
            this.keys[e.key.toLowerCase()] = false;
        });
        
        // 鼠标移动
        document.addEventListener('mousemove', (e) => {
            if (this.mouse.locked) {
                this.mouse.dx = e.movementX;
                this.mouse.dy = e.movementY;
            }
        });
        
        // 鼠标按钮
        document.addEventListener('mousedown', (e) => {
            if (e.button === 0) this.mouseButtons.left = true;
            if (e.button === 2) this.mouseButtons.right = true;
            if (e.button === 1) this.mouseButtons.middle = true;
        });
        
        document.addEventListener('mouseup', (e) => {
            if (e.button === 0) this.mouseButtons.left = false;
            if (e.button === 2) this.mouseButtons.right = false;
            if (e.button === 1) this.mouseButtons.middle = false;
        });
        
        // 防止右键菜单
        document.addEventListener('contextmenu', (e) => e.preventDefault());
        
        // 指针锁定
        document.addEventListener('pointerlockchange', () => {
            this.mouse.locked = document.pointerLockElement !== null;
        });
        
        // 触摸事件(移动端)
        if (this.isMobile) {
            this.setupTouchControls();
        }
        
        return this;
    }
    
    setupTouchControls() {
        // 触屏视角控制
        let lastTouchX = 0;
        let lastTouchY = 0;
        
        document.addEventListener('touchstart', (e) => {
            if (e.touches.length > 0) {
                const touch = e.touches[0];
                lastTouchX = touch.clientX;
                lastTouchY = touch.clientY;
            }
        });
        
        document.addEventListener('touchmove', (e) => {
            if (e.touches.length > 0 && gameState.isPlaying()) {
                const touch = e.touches[0];
                const dx = touch.clientX - lastTouchX;
                const dy = touch.clientY - lastTouchY;
                
                // 右半屏控制视角
                if (touch.clientX > window.innerWidth / 2) {
                    this.mouse.dx = dx * CONFIG.MOBILE_SENSITIVITY * 100;
                    this.mouse.dy = dy * CONFIG.MOBILE_SENSITIVITY * 100;
                }
                
                lastTouchX = touch.clientX;
                lastTouchY = touch.clientY;
            }
        });
        
        document.addEventListener('touchend', () => {
            this.mouse.dx = 0;
            this.mouse.dy = 0;
        });
    }
    
    requestPointerLock(element) {
        if (element && element.requestPointerLock) {
            element.requestPointerLock();
        }
    }
    
    isKeyPressed(key) {
        return this.keys[key.toLowerCase()] || this.keys[key] || false;
    }
    
    getAxis(horizontal = true) {
        let value = 0;
        if (horizontal) {
            if (this.isKeyPressed('a') || this.isKeyPressed('arrowleft')) value -= 1;
            if (this.isKeyPressed('d') || this.isKeyPressed('arrowright')) value += 1;
        } else {
            if (this.isKeyPressed('w') || this.isKeyPressed('arrowup')) value += 1;
            if (this.isKeyPressed('s') || this.isKeyPressed('arrowdown')) value -= 1;
        }
        return value;
    }
    
    // 每帧后调用,重置增量
    lateUpdate() {
        this.mouse.dx = 0;
        this.mouse.dy = 0;
    }
}

const input = new InputManager();


// hud.js
// HUD - 抬头显示
class HUD {
    constructor() {
        this.healthBar = null;
        this.healthText = null;
        this.scoreText = null;
        this.waveText = null;
        this.weaponName = null;
        this.crosshair = null;
        this.damageFlash = null;
        this.waveAnnouncement = null;
        this.bossHealthBar = null;
        this.bossHealthContainer = null;
        this.bossAnnouncement = null;
    }
    
    init() {
        // 创建HUD容器
        const hud = document.createElement('div');
        hud.id = 'hud';
        hud.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 100;
            font-family: 'Orbitron', 'Courier New', monospace;
        `;
        
        // 生命值条
        const healthContainer = document.createElement('div');
        healthContainer.style.cssText = `
            position: absolute;
            bottom: 30px;
            left: 50%;
            transform: translateX(-50%);
            width: 300px;
            height: 20px;
            background: rgba(0, 0, 0, 0.7);
            border: 2px solid #00ffff;
            border-radius: 10px;
            overflow: hidden;
        `;
        
        this.healthBar = document.createElement('div');
        this.healthBar.style.cssText = `
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, #00ff00, #88ff00);
            transition: width 0.2s ease;
            box-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
        `;
        
        this.healthText = document.createElement('div');
        this.healthText.style.cssText = `
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            font-size: 12px;
            font-weight: bold;
            text-shadow: 0 0 5px #000;
        `;
        this.healthText.textContent = '100 / 100';
        
        healthContainer.appendChild(this.healthBar);
        healthContainer.appendChild(this.healthText);
        hud.appendChild(healthContainer);
        
        // 分数
        this.scoreText = document.createElement('div');
        this.scoreText.style.cssText = `
            position: absolute;
            top: 20px;
            right: 30px;
            color: #00ffff;
            font-size: 24px;
            font-weight: bold;
            text-shadow: 0 0 10px rgba(0, 255, 255, 0.8);
        `;
        this.scoreText.textContent = '分数: 0';
        hud.appendChild(this.scoreText);
        
        // 金币
        this.coinText = document.createElement('div');
        this.coinText.style.cssText = `
            position: absolute;
            top: 55px;
            right: 30px;
            color: #ffdd00;
            font-size: 20px;
            font-weight: bold;
            text-shadow: 0 0 10px rgba(255, 221, 0, 0.6);
        `;
        this.coinText.textContent = '💰 0';
        hud.appendChild(this.coinText);
        
        // 波次
        this.waveText = document.createElement('div');
        this.waveText.style.cssText = `
            position: absolute;
            top: 90px;
            right: 30px;
            color: #ff00ff;
            font-size: 18px;
            font-weight: bold;
            text-shadow: 0 0 10px rgba(255, 0, 255, 0.8);
        `;
        this.waveText.textContent = '波次: 0';
        hud.appendChild(this.waveText);
        
        // 武器名称
        this.weaponName = document.createElement('div');
        this.weaponName.style.cssText = `
            position: absolute;
            bottom: 70px;
            left: 30px;
            color: #ffff00;
            font-size: 16px;
            font-weight: bold;
            text-shadow: 0 0 10px rgba(255, 255, 0, 0.8);
        `;
        this.weaponName.textContent = '脉冲手枪';
        hud.appendChild(this.weaponName);
        
        // 准星
        this.crosshair = document.createElement('div');
        this.crosshair.style.cssText = `
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 20px;
            height: 20px;
            pointer-events: none;
        `;
        this.crosshair.innerHTML = `
            <div style="position: absolute; top: 50%; left: 0; width: 100%; height: 2px; background: rgba(0, 255, 255, 0.8); transform: translateY(-50%);"></div>
            <div style="position: absolute; left: 50%; top: 0; width: 2px; height: 100%; background: rgba(0, 255, 255, 0.8); transform: translateX(-50%);"></div>
            <div style="position: absolute; top: 50%; left: 50%; width: 6px; height: 6px; border: 1px solid rgba(0, 255, 255, 0.8); border-radius: 50%; transform: translate(-50%, -50%);"></div>
        `;
        hud.appendChild(this.crosshair);
        
        // 伤害闪烁
        this.damageFlash = document.createElement('div');
        this.damageFlash.style.cssText = `
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: radial-gradient(ellipse at center, transparent 40%, rgba(255, 0, 0, 0.5) 100%);
            opacity: 0;
            transition: opacity 0.1s;
            pointer-events: none;
        `;
        hud.appendChild(this.damageFlash);
        
        // 波次公告
        this.waveAnnouncement = document.createElement('div');
        this.waveAnnouncement.style.cssText = `
            position: absolute;
            top: 30%;
            left: 50%;
            transform: translateX(-50%);
            color: #ff00ff;
            font-size: 48px;
            font-weight: bold;
            text-shadow: 0 0 20px rgba(255, 0, 255, 0.9);
            opacity: 0;
            transition: opacity 0.5s;
            text-align: center;
        `;
        hud.appendChild(this.waveAnnouncement);
        
        // Boss血条
        this.bossHealthContainer = document.createElement('div');
        this.bossHealthContainer.style.cssText = `
            position: absolute;
            top: 80px;
            left: 50%;
            transform: translateX(-50%);
            width: 400px;
            display: none;
            text-align: center;
        `;
        
        const bossName = document.createElement('div');
        bossName.style.cssText = `
            color: #ff0066;
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 5px;
            text-shadow: 0 0 10px rgba(255, 0, 102, 0.8);
        `;
        bossName.textContent = 'BOSS';
        this.bossHealthContainer.appendChild(bossName);
        
        const bossHealthBg = document.createElement('div');
        bossHealthBg.style.cssText = `
            width: 100%;
            height: 20px;
            background: rgba(0, 0, 0, 0.8);
            border: 2px solid #ff0066;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 0 15px rgba(255, 0, 102, 0.5);
        `;
        
        this.bossHealthBar = document.createElement('div');
        this.bossHealthBar.style.cssText = `
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, #ff0066, #ff4400);
            transition: width 0.3s ease;
            box-shadow: 0 0 10px rgba(255, 0, 102, 0.8);
        `;
        
        bossHealthBg.appendChild(this.bossHealthBar);
        this.bossHealthContainer.appendChild(bossHealthBg);
        hud.appendChild(this.bossHealthContainer);
        
        // Boss公告
        this.bossAnnouncement = document.createElement('div');
        this.bossAnnouncement.style.cssText = `
            position: absolute;
            top: 25%;
            left: 50%;
            transform: translateX(-50%);
            color: #ff0066;
            font-size: 36px;
            font-weight: bold;
            text-shadow: 0 0 20px rgba(255, 0, 102, 0.9);
            opacity: 0;
            transition: opacity 0.3s;
            text-align: center;
            white-space: nowrap;
        `;
        hud.appendChild(this.bossAnnouncement);
        
        document.body.appendChild(hud);
        
        // 监听事件更新
        document.addEventListener('scoreUpdate', (e) => {
            this.scoreText.textContent = `分数: ${e.detail.score}`;
        });
        
        document.addEventListener('coinsUpdate', (e) => {
            if (this.coinText) {
                this.coinText.textContent = `💰 ${e.detail.coins}`;
            }
        });
        
        document.addEventListener('waveUpdate', (e) => {
            this.waveText.textContent = `波次: ${e.detail.wave}`;
            this.showWaveAnnouncement(`第 ${e.detail.wave} 波`);
        });
        
        return this;
    }
    
    updateHealth(current, max) {
        const percent = (current / max) * 100;
        this.healthBar.style.width = `${percent}%`;
        this.healthText.textContent = `${Math.ceil(current)} / ${max}`;
        
        // 根据血量变色
        if (percent > 60) {
            this.healthBar.style.background = 'linear-gradient(90deg, #00ff00, #88ff00)';
        } else if (percent > 30) {
            this.healthBar.style.background = 'linear-gradient(90deg, #ffaa00, #ff6600)';
        } else {
            this.healthBar.style.background = 'linear-gradient(90deg, #ff0000, #ff4444)';
        }
    }
    
    updateWeapon(name) {
        this.weaponName.textContent = name;
    }
    
    showDamage(amount = 0.5) {
        this.damageFlash.style.opacity = amount;
        setTimeout(() => {
            this.damageFlash.style.opacity = 0;
        }, 100);
    }
    
    showWaveAnnouncement(text) {
        this.waveAnnouncement.textContent = text;
        this.waveAnnouncement.style.opacity = 1;
        setTimeout(() => {
            this.waveAnnouncement.style.opacity = 0;
        }, 2000);
    }
    
    showBossHealthBar(show) {
        if (this.bossHealthContainer) {
            this.bossHealthContainer.style.display = show ? 'block' : 'none';
        }
    }
    
    updateBossHealth(current, max) {
        if (this.bossHealthBar) {
            const percent = (current / max) * 100;
            this.bossHealthBar.style.width = `${percent}%`;
        }
    }
    
    showBossAnnouncement(text) {
        if (!this.bossAnnouncement) return;
        this.bossAnnouncement.textContent = text;
        this.bossAnnouncement.style.opacity = 1;
        this.bossAnnouncement.style.transform = 'translateX(-50%) scale(1.2)';
        
        setTimeout(() => {
            this.bossAnnouncement.style.transform = 'translateX(-50%) scale(1)';
        }, 200);
        
        setTimeout(() => {
            this.bossAnnouncement.style.opacity = 0;
        }, 2500);
    }
    
    // 显示浮动文字(用于奖励提示等)
    showFloatingText(text, x = 0, y = 2, color = 0xffff00) {
        // 使用CSS创建屏幕中央浮动文字
        const floatEl = document.createElement('div');
        floatEl.style.cssText = `
            position: fixed;
            top: 40%;
            left: 50%;
            transform: translateX(-50%);
            color: #${color.toString(16).padStart(6, '0')};
            font-size: 28px;
            font-weight: bold;
            text-shadow: 0 0 15px #${color.toString(16).padStart(6, '0')};
            pointer-events: none;
            z-index: 150;
            animation: floatUp 1.5s ease-out forwards;
            font-family: 'Orbitron', 'Courier New', monospace;
        `;
        floatEl.textContent = text;
        
        // 添加动画样式
        if (!document.getElementById('floatAnimation')) {
            const style = document.createElement('style');
            style.id = 'floatAnimation';
            style.textContent = `
                @keyframes floatUp {
                    0% { opacity: 1; transform: translateX(-50%) translateY(0); }
                    100% { opacity: 0; transform: translateX(-50%) translateY(-50px); }
                }
            `;
            document.head.appendChild(style);
        }
        
        document.body.appendChild(floatEl);
        
        setTimeout(() => {
            if (floatEl.parentNode) {
                floatEl.parentNode.removeChild(floatEl);
            }
        }, 1500);
    }
    
    show() {
        document.getElementById('hud').style.display = 'block';
    }
    
    hide() {
        const hud = document.getElementById('hud');
        if (hud) hud.style.display = 'none';
    }
}

const hud = new HUD();


// ui.js
// UI系统 - 菜单、暂停、游戏结束等
class UIManager {
    constructor() {
        this.menus = {};
        this.currentMenu = null;
    }
    
    init() {
        this.createMainMenu();
        this.createCharacterSelect();
        this.createPauseMenu();
        this.createGameOverMenu();
        
        // 监听游戏状态变化
        document.addEventListener('gameStateChange', (e) => {
            this.handleStateChange(e.detail.oldState, e.detail.newState);
        });
        
        return this;
    }
    
    createMainMenu() {
        const menu = document.createElement('div');
        menu.id = 'main-menu';
        menu.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: radial-gradient(ellipse at center, #1a1a3a 0%, #0a0a1a 100%);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 200;
            font-family: 'Orbitron', 'Courier New', monospace;
        `;
        
        menu.innerHTML = `
            <h1 style="color: #00ffff; font-size: 64px; margin-bottom: 10px; text-shadow: 0 0 30px rgba(0, 255, 255, 0.8); letter-spacing: 4px;">
                NEON FPS
            </h1>
            <p style="color: #ff00ff; font-size: 18px; margin-bottom: 50px; text-shadow: 0 0 10px rgba(255, 0, 255, 0.6);">
                赛博朋克 · 末日求生
            </p>
            
            <button id="start-btn" style="
                padding: 15px 50px;
                font-size: 20px;
                background: linear-gradient(135deg, #00ffff, #0088ff);
                color: #000;
                border: none;
                border-radius: 8px;
                cursor: pointer;
                margin: 10px;
                font-weight: bold;
                box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
                transition: all 0.3s;
                font-family: inherit;
            ">开始游戏</button>
            
            <button id="character-btn" style="
                padding: 12px 40px;
                font-size: 16px;
                background: transparent;
                color: #ff00ff;
                border: 2px solid #ff00ff;
                border-radius: 8px;
                cursor: pointer;
                margin: 10px;
                font-weight: bold;
                box-shadow: 0 0 15px rgba(255, 0, 255, 0.3);
                transition: all 0.3s;
                font-family: inherit;
            ">选择角色</button>
            
            <div style="margin-top: 50px; color: #888; font-size: 12px; text-align: center;">
                <p>WASD - 移动 | 鼠标 - 视角 | 左键 - 射击</p>
                <p>空格 - 跳跃 | Shift - 冲刺 | Ctrl - 翻滚 | F - 近战</p>
                <p>1/2/3/4 - 切换武器 | ESC - 暂停</p>
            </div>
            
            <div style="position: absolute; bottom: 20px; color: #444; font-size: 10px;">
                KouziTech Presents · v1.0
            </div>
        `;
        
        document.body.appendChild(menu);
        this.menus.main = menu;
        
        // 按钮事件
        document.getElementById('start-btn').addEventListener('click', () => {
            this.startGame();
        });
        
        document.getElementById('character-btn').addEventListener('click', () => {
            this.showMenu('characterSelect');
        });
    }
    
    createCharacterSelect() {
        const menu = document.createElement('div');
        menu.id = 'character-select';
        menu.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: radial-gradient(ellipse at center, #1a1a3a 0%, #0a0a1a 100%);
            display: none;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 200;
            font-family: 'Orbitron', 'Courier New', monospace;
        `;
        
        const characters = CONFIG.CHARACTERS;
        let cardsHtml = '';
        
        for (const [key, char] of Object.entries(characters)) {
            const hexColor = '#' + char.color.toString(16).padStart(6, '0');
            cardsHtml += `
                <div class="char-card" data-char="${key}" style="
                    width: 200px;
                    padding: 20px;
                    background: rgba(0, 0, 0, 0.5);
                    border: 2px solid ${hexColor};
                    border-radius: 12px;
                    margin: 10px;
                    cursor: pointer;
                    transition: all 0.3s;
                    text-align: center;
                    box-shadow: 0 0 15px ${hexColor}40;
                ">
                    <div style="width: 80px; height: 80px; margin: 0 auto 15px; border-radius: 50%; 
                         background: radial-gradient(circle, ${hexColor}40 0%, ${hexColor}10 100%);
                         border: 3px solid ${hexColor}; display: flex; align-items: center; justify-content: center;">
                        <span style="font-size: 32px;">${this.getCharacterEmoji(key)}</span>
                    </div>
                    <h3 style="color: ${hexColor}; margin: 0 0 8px 0; font-size: 14px;">${char.name}</h3>
                    <p style="color: #aaa; font-size: 11px; margin: 0 0 10px 0; line-height: 1.4;">${char.description}</p>
                    <div style="font-size: 10px; color: #888; line-height: 1.6;">
                        ${char.healthBonus > 0 ? '+' : ''}${char.healthBonus} 生命<br>
                        ${char.speedBonus > 0 ? '+' : ''}${char.speedBonus} 速度<br>
                        ${char.damageBonus > 0 ? '+' : ''}${Math.round(char.damageBonus * 100)}% 伤害
                    </div>
                    <p style="color: #ffd700; font-size: 10px; margin-top: 10px; font-style: italic;">
                        ${char.special}
                    </p>
                </div>
            `;
        }
        
        menu.innerHTML = `
            <h2 style="color: #ff00ff; font-size: 36px; margin-bottom: 30px; text-shadow: 0 0 20px rgba(255, 0, 255, 0.6);">
                选择角色
            </h2>
            
            <div style="display: flex; flex-wrap: wrap; justify-content: center; max-width: 900px;">
                ${cardsHtml}
            </div>
            
            <button id="back-btn" style="
                margin-top: 30px;
                padding: 10px 30px;
                font-size: 14px;
                background: transparent;
                color: #888;
                border: 1px solid #666;
                border-radius: 6px;
                cursor: pointer;
                font-family: inherit;
            ">返回主菜单</button>
        `;
        
        document.body.appendChild(menu);
        this.menus.characterSelect = menu;
        
        // 卡片点击事件
        const cards = menu.querySelectorAll('.char-card');
        cards.forEach(card => {
            card.addEventListener('click', () => {
                const charKey = card.dataset.char;
                gameState.selectedCharacter = charKey;
                
                // 视觉反馈
                cards.forEach(c => c.style.transform = 'scale(1)');
                card.style.transform = 'scale(1.05)';
                
                // 短暂延迟后开始游戏
                setTimeout(() => this.startGame(), 300);
            });
        });
        
        document.getElementById('back-btn').addEventListener('click', () => {
            this.showMenu('main');
        });
    }
    
    getCharacterEmoji(key) {
        const emojis = {
            soldier: '⚔️',
            ninja: '🗡️',
            engineer: '🔧',
            medic: '💚'
        };
        return emojis[key] || '🤖';
    }
    
    createPauseMenu() {
        const menu = document.createElement('div');
        menu.id = 'pause-menu';
        menu.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            display: none;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 300;
            font-family: 'Orbitron', 'Courier New', monospace;
        `;
        
        menu.innerHTML = `
            <h2 style="color: #ffff00; font-size: 48px; margin-bottom: 40px; text-shadow: 0 0 20px rgba(255, 255, 0, 0.6);">
                游戏暂停
            </h2>
            
            <button id="resume-btn" style="
                padding: 15px 40px;
                font-size: 18px;
                background: linear-gradient(135deg, #00ff00, #00aa00);
                color: #000;
                border: none;
                border-radius: 8px;
                cursor: pointer;
                margin: 10px;
                font-weight: bold;
                font-family: inherit;
            ">继续游戏</button>
            
            <button id="restart-btn" style="
                padding: 12px 35px;
                font-size: 16px;
                background: transparent;
                color: #ffaa00;
                border: 2px solid #ffaa00;
                border-radius: 8px;
                cursor: pointer;
                margin: 10px;
                font-weight: bold;
                font-family: inherit;
            ">重新开始</button>
            
            <button id="quit-btn" style="
                padding: 10px 30px;
                font-size: 14px;
                background: transparent;
                color: #ff4444;
                border: 1px solid #ff4444;
                border-radius: 6px;
                cursor: pointer;
                margin: 10px;
                font-family: inherit;
            ">返回主菜单</button>
        `;
        
        document.body.appendChild(menu);
        this.menus.pause = menu;
        
        document.getElementById('resume-btn').addEventListener('click', () => this.resumeGame());
        document.getElementById('restart-btn').addEventListener('click', () => this.restartGame());
        document.getElementById('quit-btn').addEventListener('click', () => this.quitToMenu());
    }
    
    createGameOverMenu() {
        const menu = document.createElement('div');
        menu.id = 'gameover-menu';
        menu.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.9);
            display: none;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 300;
            font-family: 'Orbitron', 'Courier New', monospace;
        `;
        
        menu.innerHTML = `
            <h2 style="color: #ff0000; font-size: 56px; margin-bottom: 20px; text-shadow: 0 0 30px rgba(255, 0, 0, 0.8);">
                游戏结束
            </h2>
            
            <div style="text-align: center; margin: 30px 0;">
                <p style="color: #00ffff; font-size: 24px; margin: 10px 0;">最终分数: <span id="final-score">0</span></p>
                <p style="color: #ff00ff; font-size: 20px; margin: 10px 0;">到达波次: <span id="final-wave">0</span></p>
                <p style="color: #ffff00; font-size: 18px; margin: 10px 0;">击杀数: <span id="final-kills">0</span></p>
            </div>
            
            <button id="retry-btn" style="
                padding: 15px 40px;
                font-size: 18px;
                background: linear-gradient(135deg, #00ffff, #0088ff);
                color: #000;
                border: none;
                border-radius: 8px;
                cursor: pointer;
                margin: 10px;
                font-weight: bold;
                font-family: inherit;
                box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
            ">再来一局</button>
            
            <button id="menu-btn" style="
                padding: 12px 35px;
                font-size: 16px;
                background: transparent;
                color: #888;
                border: 1px solid #666;
                border-radius: 8px;
                cursor: pointer;
                margin: 10px;
                font-family: inherit;
            ">返回主菜单</button>
        `;
        
        document.body.appendChild(menu);
        this.menus.gameOver = menu;
        
        document.getElementById('retry-btn').addEventListener('click', () => this.restartGame());
        document.getElementById('menu-btn').addEventListener('click', () => this.quitToMenu());
    }
    
    showMenu(menuName) {
        // 隐藏所有菜单
        for (const key in this.menus) {
            this.menus[key].style.display = 'none';
        }
        
        // 显示指定菜单
        if (this.menus[menuName]) {
            this.menus[menuName].style.display = 'flex';
            this.currentMenu = menuName;
        }
    }
    
    hideAllMenus() {
        for (const key in this.menus) {
            this.menus[key].style.display = 'none';
        }
        this.currentMenu = null;
    }
    
    startGame() {
        this.hideAllMenus();
        hud.show();
        gameState.setState('playing');
        
        // 请求指针锁定
        if (!input.isMobile && renderer.domElement) {
            input.requestPointerLock(renderer.domElement);
        }
        
        // 重置并开始游戏
        game.reset();
        game.start();
    }
    
    resumeGame() {
        this.hideAllMenus();
        gameState.setState('playing');
        if (!input.isMobile && renderer.domElement) {
            input.requestPointerLock(renderer.domElement);
        }
    }
    
    restartGame() {
        this.hideAllMenus();
        hud.show();
        gameState.setState('playing');
        game.reset();
        game.start();
    }
    
    quitToMenu() {
        gameState.setState('menu');
        hud.hide();
        this.showMenu('main');
        game.reset();
    }
    
    handleStateChange(oldState, newState) {
        if (newState === 'paused') {
            document.exitPointerLock();
            this.showMenu('pause');
        } else if (newState === 'gameover') {
            document.exitPointerLock();
            document.getElementById('final-score').textContent = gameState.score;
            document.getElementById('final-wave').textContent = gameState.wave;
            document.getElementById('final-kills').textContent = gameState.kills;
            this.showMenu('gameOver');
        } else if (newState === 'playing') {
            this.hideAllMenus();
        }
    }
}

const ui = new UIManager();


// weapons.js
// 武器系统
class WeaponSystem {
    constructor() {
        this.currentWeapon = 'pistol';
        this.lastFireTime = 0;
        this.weapons = {};
        this.upgrades = {}; // 各武器升级等级
        this.unlockedWeapons = new Set(['pistol', 'sword']); // 初始解锁手枪和剑
    }
    
    init() {
        // 初始化武器配置
        for (const [key, config] of Object.entries(CONFIG.WEAPONS)) {
            this.weapons[key] = {
                ...config,
                name: key,
                baseDamage: config.damage,
                baseFireRate: config.fireRate,
                baseBulletSpeed: config.bulletSpeed
            };
            this.upgrades[key] = { damage: 0, fireRate: 0, speed: 0 };
        }
        
        return this;
    }
    
    unlockWeapon(weaponKey) {
        if (this.weapons[weaponKey]) {
            this.unlockedWeapons.add(weaponKey);
            return true;
        }
        return false;
    }
    
    isUnlocked(weaponKey) {
        return this.unlockedWeapons.has(weaponKey);
    }
    
    upgradeWeapon(weaponKey, upgradeType) {
        const weapon = this.weapons[weaponKey];
        const upgradeConfig = CONFIG.WEAPON_UPGRADES[upgradeType];
        if (!weapon || !upgradeConfig) return false;
        
        const currentLevel = this.upgrades[weaponKey][upgradeType];
        if (currentLevel >= upgradeConfig.maxLevel) return false;
        
        this.upgrades[weaponKey][upgradeType]++;
        
        // 应用升级效果
        if (upgradeType === 'damage') {
            weapon.damage = weapon.baseDamage * (1 + upgradeConfig.bonusPerLevel * this.upgrades[weaponKey][upgradeType]);
        } else if (upgradeType === 'fireRate') {
            weapon.fireRate = weapon.baseFireRate * (1 - upgradeConfig.bonusPerLevel * this.upgrades[weaponKey][upgradeType]);
        } else if (upgradeType === 'speed') {
            weapon.bulletSpeed = weapon.baseBulletSpeed * (1 + upgradeConfig.bonusPerLevel * this.upgrades[weaponKey][upgradeType]);
        }
        
        return true;
    }
    
    getUpgradeLevel(weaponKey, upgradeType) {
        return this.upgrades[weaponKey]?.[upgradeType] || 0;
    }
    
    getUpgradeCost(weaponKey, upgradeType) {
        const level = this.getUpgradeLevel(weaponKey, upgradeType);
        const baseCost = 50;
        return Math.floor(baseCost * Math.pow(1.5, level));
    }
    
    switchWeapon(weaponKey) {
        if (this.weapons[weaponKey] && weaponKey !== this.currentWeapon) {
            this.currentWeapon = weaponKey;
            if (audio) audio.playWeaponSwitch();
            return true;
        }
        return false;
    }
    
    fire(player, targets) {
        const weapon = this.weapons[this.currentWeapon];
        if (!weapon) return;
        
        const now = performance.now();
        if (now - this.lastFireTime < weapon.fireRate) return;
        
        this.lastFireTime = now;
        
        // 根据武器类型处理
        switch (this.currentWeapon) {
            case 'pistol':
                this.firePistol(weapon, player);
                break;
            case 'shotgun':
                this.fireShotgun(weapon, player);
                break;
            case 'laser':
                this.fireLaser(weapon, player, targets);
                break;
            case 'smg':
                this.fireSMG(weapon, player);
                break;
            case 'rocket':
                this.fireRocket(weapon, player);
                break;
            case 'plasma':
                this.firePlasma(weapon, player);
                break;
            case 'sword':
                // 剑在player.js的meleeAttack中处理
                return;
        }
        
        // 后坐力
        if (player && player.viewModel) {
            player.recoilAmount = 0.15;
        }
        
        // 音效
        if (audio) {
            audio.playShoot(this.currentWeapon);
        }
    }
    
    firePistol(weapon, player) {
        const direction = new THREE.Vector3();
        renderer.camera.getWorldDirection(direction);
        
        // 轻微散射
        const spread = weapon.spread || 0.02;
        direction.x += (Math.random() - 0.5) * spread;
        direction.y += (Math.random() - 0.5) * spread;
        direction.z += (Math.random() - 0.5) * spread * 0.5;
        direction.normalize();
        
        const bullet = this.createBullet(
            player.mesh.position.clone(),
            direction,
            weapon.bulletSpeed,
            weapon.damage,
            weapon.color,
            true
        );
        
        game.bullets.push(bullet);
        
        // 枪口火焰
        if (effects) {
            const muzzlePos = player.mesh.position.clone();
            muzzlePos.y = 1.4;
            const camDir = new THREE.Vector3();
            renderer.camera.getWorldDirection(camDir);
            muzzlePos.addScaledVector(camDir, 0.5);
            effects.createMuzzleFlash(muzzlePos, weapon.color);
        }
    }
    
    fireShotgun(weapon, player) {
        const direction = new THREE.Vector3();
        renderer.camera.getWorldDirection(direction);
        
        const pelletCount = weapon.pellets || 8;
        const spread = weapon.spread || 0.15;
        
        for (let i = 0; i < pelletCount; i++) {
            const pelletDir = direction.clone();
            pelletDir.x += (Math.random() - 0.5) * spread;
            pelletDir.y += (Math.random() - 0.5) * spread * 0.7;
            pelletDir.z += (Math.random() - 0.5) * spread * 0.3;
            pelletDir.normalize();
            
            const bullet = this.createBullet(
                player.mesh.position.clone(),
                pelletDir,
                weapon.bulletSpeed,
                weapon.damage,
                weapon.color,
                true,
                0.8 // 霰弹子弹更小
            );
            
            game.bullets.push(bullet);
        }
        
        // 枪口火焰
        if (effects) {
            const muzzlePos = player.mesh.position.clone();
            muzzlePos.y = 1.4;
            const camDir = new THREE.Vector3();
            renderer.camera.getWorldDirection(camDir);
            muzzlePos.addScaledVector(camDir, 0.5);
            effects.createMuzzleFlash(muzzlePos, weapon.color, 1.5);
        }
        
        // 后坐力
        if (player && player.viewModel) {
            player.recoilAmount = 0.3;
        }
    }
    
    fireLaser(weapon, player, targets) {
        // 激光是 hitscan(瞬时命中)
        const raycaster = new THREE.Raycaster();
        const direction = new THREE.Vector3();
        renderer.camera.getWorldDirection(direction);
        
        raycaster.set(player.mesh.position.clone().add(new THREE.Vector3(0, 1.4, 0)), direction);
        raycaster.far = 100;
        
        // 检测敌人命中
        let hitPoint = null;
        let hitEnemy = null;
        let minDist = Infinity;
        
        for (const enemy of targets) {
            if (enemy.dead || !enemy.mesh) continue;
            
            const dist = raycaster.ray.distanceToPoint(enemy.mesh.position);
            if (dist < (enemy.size || 1) && dist < minDist) {
                // 检查是否在射线方向上
                const toEnemy = new THREE.Vector3();
                toEnemy.subVectors(enemy.mesh.position, raycaster.ray.origin);
                const dot = toEnemy.dot(direction);
                if (dot > 0) {
                    minDist = dist;
                    hitEnemy = enemy;
                    hitPoint = enemy.mesh.position.clone();
                }
            }
        }
        
        // 创建激光束视觉效果
        const beamStart = player.mesh.position.clone();
        beamStart.y = 1.4;
        
        const beamEnd = hitPoint || 
            raycaster.ray.origin.clone().add(direction.multiplyScalar(80));
        
        if (effects) {
            effects.createLaserBeam(beamStart, beamEnd, weapon.color);
        }
        
        // 造成伤害
        if (hitEnemy) {
            const damage = weapon.damage * (1 + player.damageBonus);
            hitEnemy.takeDamage(damage, direction);
            
            if (effects) {
                effects.createHitEffect(hitPoint, weapon.color);
                effects.shake(0.15, 0.05);
            }
        }
        
        // 后坐力
        if (player && player.viewModel) {
            player.recoilAmount = 0.1;
        }
    }
    
    fireSMG(weapon, player) {
        const direction = new THREE.Vector3();
        renderer.camera.getWorldDirection(direction);
        
        // 比手枪稍大的散射
        const spread = weapon.spread || 0.08;
        direction.x += (Math.random() - 0.5) * spread;
        direction.y += (Math.random() - 0.5) * spread * 0.6;
        direction.z += (Math.random() - 0.5) * spread * 0.3;
        direction.normalize();
        
        const bullet = this.createBullet(
            player.mesh.position.clone(),
            direction,
            weapon.bulletSpeed,
            weapon.damage,
            weapon.color,
            true,
            0.6
        );
        
        game.bullets.push(bullet);
        
        // 枪口火焰
        if (effects) {
            const muzzlePos = player.mesh.position.clone();
            muzzlePos.y = 1.4;
            const camDir = new THREE.Vector3();
            renderer.camera.getWorldDirection(camDir);
            muzzlePos.addScaledVector(camDir, 0.5);
            effects.createMuzzleFlash(muzzlePos, weapon.color, 0.8);
        }
        
        // 后坐力
        if (player && player.viewModel) {
            player.recoilAmount = 0.08;
        }
    }
    
    fireRocket(weapon, player) {
        const direction = new THREE.Vector3();
        renderer.camera.getWorldDirection(direction);
        
        const rocket = this.createBullet(
            player.mesh.position.clone(),
            direction,
            weapon.bulletSpeed,
            weapon.damage,
            weapon.color,
            true,
            2.5
        );
        
        // 火箭弹特殊属性
        rocket.isRocket = true;
        rocket.splashRadius = weapon.splashRadius;
        rocket.splashDamage = weapon.splashDamage;
        
        // 添加烟雾拖尾
        rocket.trail = [];
        
        game.bullets.push(rocket);
        
        // 大枪口火焰
        if (effects) {
            const muzzlePos = player.mesh.position.clone();
            muzzlePos.y = 1.4;
            const camDir = new THREE.Vector3();
            renderer.camera.getWorldDirection(camDir);
            muzzlePos.addScaledVector(camDir, 0.5);
            effects.createMuzzleFlash(muzzlePos, weapon.color, 2);
            effects.shake(0.2, 0.1);
        }
        
        // 后坐力
        if (player && player.viewModel) {
            player.recoilAmount = 0.5;
        }
    }
    
    firePlasma(weapon, player) {
        const direction = new THREE.Vector3();
        renderer.camera.getWorldDirection(direction);
        
        const spread = weapon.spread || 0.03;
        direction.x += (Math.random() - 0.5) * spread;
        direction.y += (Math.random() - 0.5) * spread * 0.5;
        direction.normalize();
        
        const bullet = this.createBullet(
            player.mesh.position.clone(),
            direction,
            weapon.bulletSpeed,
            weapon.damage,
            weapon.color,
            true,
            1.2
        );
        
        // 等离子弹特殊属性
        bullet.isPlasma = true;
        bullet.burnDamage = weapon.burnDamage;
        bullet.burnDuration = weapon.burnDuration;
        
        // 发光效果更强
        bullet.mesh.children[0].scale.setScalar(2);
        bullet.mesh.children[0].material.opacity = 0.5;
        
        game.bullets.push(bullet);
        
        // 枪口火焰
        if (effects) {
            const muzzlePos = player.mesh.position.clone();
            muzzlePos.y = 1.4;
            const camDir = new THREE.Vector3();
            renderer.camera.getWorldDirection(camDir);
            muzzlePos.addScaledVector(camDir, 0.5);
            effects.createMuzzleFlash(muzzlePos, weapon.color, 1.2);
        }
        
        // 后坐力
        if (player && player.viewModel) {
            player.recoilAmount = 0.15;
        }
    }
    
    createBullet(position, direction, speed, damage, color, isPlayerBullet = true, size = 1) {
        const geometry = new THREE.SphereGeometry(0.05 * size, 6, 6);
        const material = new THREE.MeshBasicMaterial({ 
            color: color,
            transparent: true,
            opacity: 0.9
        });
        
        const mesh = new THREE.Mesh(geometry, material);
        mesh.position.copy(position);
        mesh.position.y = 1.4; // 从枪口高度发射
        
        // 添加发光效果
        const glowGeometry = new THREE.SphereGeometry(0.1 * size, 6, 6);
        const glowMaterial = new THREE.MeshBasicMaterial({
            color: color,
            transparent: true,
            opacity: 0.3
        });
        const glow = new THREE.Mesh(glowGeometry, glowMaterial);
        mesh.add(glow);
        
        renderer.scene.add(mesh);
        
        return {
            mesh: mesh,
            velocity: direction.clone().multiplyScalar(speed),
            damage: damage,
            life: 3, // 3秒后消失
            color: color,
            isPlayerBullet: isPlayerBullet
        };
    }
    
    getCurrentWeapon() {
        return this.weapons[this.currentWeapon];
    }
}

const weapons = new WeaponSystem();


// enemies.js
// 敌人系统
class Enemy {
    constructor(type, position) {
        this.type = type;
        this.config = CONFIG.ENEMY_TYPES[type] || CONFIG.ENEMY_TYPES.drone;
        this.health = this.config.health;
        this.maxHealth = this.config.health;
        this.speed = this.config.speed;
        this.damage = this.config.damage;
        this.scoreValue = this.config.score;
        this.size = this.config.size || 1;
        this.color = this.config.color;
        this.height = this.size * 2;
        
        this.mesh = null;
        this.dead = false;
        this.dying = false;
        this.deathTime = 0;
        
        this.velocity = new THREE.Vector3();
        this.isAttacking = false;
        this.attackCooldown = 0;
        this.staggerTime = 0;
        this.knockback = new THREE.Vector3();
        
        // 状态效果
        this.burning = false;
        this.burnDamage = 0;
        this.burnDuration = 0;
        this.burnTickTimer = 0;
        this.slowAmount = 0;
        this.slowDuration = 0;
        
        // 特殊敌人属性
        if (type === 'bomber') {
            this.range = this.config.range || 12;
            this.projectileSpeed = this.config.projectileSpeed || 8;
        }
        if (type === 'pouncer') {
            this.leapForce = this.config.leapForce || 15;
            this.isPouncing = false;
            this.pounceCooldown = 0;
        }
        
        this.position = position || new THREE.Vector3();
        this.createMesh();
    }
    
    createMesh() {
        const group = new THREE.Group();
        
        // 主体
        const bodyGeo = new THREE.BoxGeometry(this.size, this.size * 1.5, this.size);
        const bodyMat = new THREE.MeshStandardMaterial({ 
            color: this.color,
            emissive: this.color,
            emissiveIntensity: 0.2,
            metalness: 0.3,
            roughness: 0.7
        });
        const body = new THREE.Mesh(bodyGeo, bodyMat);
        body.position.y = this.size * 0.75;
        body.castShadow = true;
        group.add(body);
        
        // 头部
        const headGeo = new THREE.SphereGeometry(this.size * 0.4, 8, 6);
        const headMat = new THREE.MeshStandardMaterial({ 
            color: this.color,
            emissive: this.color,
            emissiveIntensity: 0.3
        });
        const head = new THREE.Mesh(headGeo, headMat);
        head.position.y = this.size * 1.5;
        group.add(head);
        
        // 眼睛
        const eyeGeo = new THREE.SphereGeometry(this.size * 0.12, 6, 4);
        const eyeMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });
        const leftEye = new THREE.Mesh(eyeGeo, eyeMat);
        leftEye.position.set(-this.size * 0.15, this.size * 1.55, this.size * 0.35);
        group.add(leftEye);
        
        const rightEye = new THREE.Mesh(eyeGeo, eyeMat);
        rightEye.position.set(this.size * 0.15, this.size * 1.55, this.size * 0.35);
        group.add(rightEye);
        
        // 血条背景
        const healthBarBg = new THREE.Mesh(
            new THREE.PlaneGeometry(this.size * 1.5, 0.1),
            new THREE.MeshBasicMaterial({ color: 0x333333, side: THREE.DoubleSide })
        );
        healthBarBg.position.y = this.size * 2.2;
        healthBarBg.name = 'healthBarBg';
        group.add(healthBarBg);
        
        // 血条
        const healthBar = new THREE.Mesh(
            new THREE.PlaneGeometry(this.size * 1.5, 0.1),
            new THREE.MeshBasicMaterial({ color: 0x00ff00, side: THREE.DoubleSide })
        );
        healthBar.position.y = this.size * 2.2;
        healthBar.position.z = 0.01;
        healthBar.name = 'healthBar';
        group.add(healthBar);
        
        group.position.copy(this.position);
        group.position.y = 0;
        
        this.mesh = group;
        renderer.scene.add(group);
    }
    
    update(deltaTime, playerPos) {
        if (this.dead) {
            this.updateDeath(deltaTime);
            return;
        }
        
        // 硬直
        if (this.staggerTime > 0) {
            this.staggerTime -= deltaTime;
            // 击退效果
            this.mesh.position.addScaledVector(this.knockback, deltaTime * 5);
            this.knockback.multiplyScalar(0.9);
            return;
        }
        
        // 攻击冷却
        if (this.attackCooldown > 0) {
            this.attackCooldown -= deltaTime;
        }
        
        // 状态效果 - 灼烧
        if (this.burning && this.burnDuration > 0) {
            this.burnDuration -= deltaTime;
            this.burnTickTimer -= deltaTime;
            
            if (this.burnTickTimer <= 0) {
                this.health -= this.burnDamage;
                this.burnTickTimer = 0.5; // 每0.5秒一跳
                
                // 跳字
                if (effects && effects.createDamageNumber) {
                    effects.createDamageNumber(
                        this.mesh.position.clone().add(new THREE.Vector3(0, this.size * 2, 0)),
                        Math.round(this.burnDamage),
                        0xff6600
                    );
                }
                
                if (this.health <= 0) {
                    this.die();
                    return;
                }
                
                this.updateHealthBar();
            }
            
            // 灼烧结束
            if (this.burnDuration <= 0) {
                this.burning = false;
                this.burnDamage = 0;
                // 恢复原来的发光颜色
                if (this.mesh) {
                    this.mesh.traverse((child) => {
                        if (child.isMesh && child.material && child.material.emissive) {
                            child.material.emissive.setHex(this.color);
                            child.material.emissiveIntensity = 0.2;
                        }
                    });
                }
            }
        }
        
        // 状态效果 - 减速
        let speedMultiplier = 1;
        if (this.slowDuration > 0) {
            this.slowDuration -= deltaTime;
            speedMultiplier = 1 - this.slowAmount;
            if (this.slowDuration <= 0) {
                this.slowAmount = 0;
            }
        }
        
        // 移动向玩家
        const direction = new THREE.Vector3();
        direction.subVectors(playerPos, this.mesh.position);
        direction.y = 0;
        const distance = direction.length();
        direction.normalize();
        
        // 根据敌人类型行为
        switch (this.type) {
            case 'drone':
                // 无人机:快速接近,撞击
                this.mesh.position.addScaledVector(direction, this.speed * deltaTime);
                // 上下浮动
                this.mesh.position.y = Math.sin(performance.now() * 0.003 + this.mesh.position.x) * 0.3 + 1;
                
                if (distance < 1.5) {
                    this.attack(playerPos);
                }
                break;
                
            case 'grunt':
                // 步兵:稳定接近,近战攻击
                this.mesh.position.addScaledVector(direction, this.speed * deltaTime);
                
                if (distance < 2) {
                    this.attack(playerPos);
                }
                break;
                
            case 'tank':
                // 重装:缓慢但血厚伤害高
                this.mesh.position.addScaledVector(direction, this.speed * deltaTime);
                
                if (distance < 2.5) {
                    this.attack(playerPos);
                }
                break;
                
            case 'bomber':
                // 爆破手:远程投掷炸弹
                if (distance > this.range * 0.8) {
                    // 接近到射程内
                    this.mesh.position.addScaledVector(direction, this.speed * deltaTime);
                } else if (distance < this.range * 0.5) {
                    // 太近了后撤
                    this.mesh.position.addScaledVector(direction, -this.speed * 0.5 * deltaTime);
                }
                
                if (distance < this.range && this.attackCooldown <= 0) {
                    this.throwBomb(playerPos);
                    this.attackCooldown = 2;
                }
                break;
                
            case 'pouncer':
                // 突击者:间歇性跳跃攻击
                if (this.pounceCooldown > 0) {
                    this.pounceCooldown -= deltaTime;
                }
                
                if (!this.isPouncing) {
                    if (distance < 8 && this.pounceCooldown <= 0) {
                        // 开始跳跃
                        this.isPouncing = true;
                        this.velocity.y = this.leapForce * 0.5;
                        this.velocity.x = direction.x * this.speed * 3;
                        this.velocity.z = direction.z * this.speed * 3;
                        this.pounceCooldown = 3;
                    } else {
                        this.mesh.position.addScaledVector(direction, this.speed * deltaTime);
                    }
                } else {
                    // 跳跃中
                    this.velocity.y -= 20 * deltaTime;
                    this.mesh.position.x += this.velocity.x * deltaTime;
                    this.mesh.position.z += this.velocity.z * deltaTime;
                    this.mesh.position.y = Math.max(0, this.mesh.position.y + this.velocity.y * deltaTime);
                    
                    if (this.mesh.position.y <= 0) {
                        this.isPouncing = false;
                        this.mesh.position.y = 0;
                        // 落地时如果在玩家附近造成伤害
                        if (distance < 2) {
                            this.attack(playerPos);
                        }
                    }
                }
                break;
        }
        
        // 边界
        const boundary = CONFIG.ARENA_SIZE - 1;
        this.mesh.position.x = Math.max(-boundary, Math.min(boundary, this.mesh.position.x));
        this.mesh.position.z = Math.max(-boundary, Math.min(boundary, this.mesh.position.z));
        
        // 面向玩家
        this.mesh.lookAt(playerPos.x, this.mesh.position.y, playerPos.z);
        
        // 更新血条朝向
        this.updateHealthBar();
    }
    
    attack(playerPos) {
        if (this.attackCooldown > 0) return;
        
        this.attackCooldown = 1;
        this.isAttacking = true;
        
        // 攻击动画
        const originalScale = this.mesh.scale.x;
        this.mesh.scale.x = originalScale * 1.1;
        setTimeout(() => {
            if (this.mesh) this.mesh.scale.x = originalScale;
        }, 100);
        
        // 造成伤害(交给碰撞检测)
        setTimeout(() => {
            if (!this.dead && player) {
                const dist = this.mesh.position.distanceTo(player.mesh.position);
                if (dist < 2.5) {
                    player.takeDamage(this.damage);
                }
            }
            this.isAttacking = false;
        }, 200);
    }
    
    throwBomb(playerPos) {
        // 创建投掷物
        const bomb = {
            mesh: new THREE.Mesh(
                new THREE.SphereGeometry(0.15, 8, 6),
                new THREE.MeshBasicMaterial({ color: 0xff4400 })
            ),
            velocity: new THREE.Vector3(),
            damage: this.damage,
            life: 3,
            isPlayerBullet: false,
            isBomb: true,
            explosionRadius: 3
        };
        
        bomb.mesh.position.copy(this.mesh.position);
        bomb.mesh.position.y = 1;
        
        // 计算抛物线
        const direction = new THREE.Vector3();
        direction.subVectors(playerPos, this.mesh.position);
        const distance = direction.length();
        direction.normalize();
        
        const time = distance / this.projectileSpeed;
        bomb.velocity.x = direction.x * this.projectileSpeed;
        bomb.velocity.z = direction.z * this.projectileSpeed;
        bomb.velocity.y = 8; // 向上的初始速度
        
        renderer.scene.add(bomb.mesh);
        game.bullets.push(bomb);
    }
    
    applyBurn(damage, duration) {
        if (this.dead) return;
        
        this.burning = true;
        this.burnDamage = Math.max(this.burnDamage, damage);
        this.burnDuration = Math.max(this.burnDuration, duration);
        
        // 灼烧视觉效果 - 微微发红
        if (this.mesh) {
            this.mesh.traverse((child) => {
                if (child.isMesh && child.material && child.material.emissive) {
                    child.material.emissive.setHex(0xff4400);
                    child.material.emissiveIntensity = 0.5;
                }
            });
        }
    }
    
    takeDamage(amount, direction) {
        if (this.dead) return;
        
        this.health -= amount;
        this.staggerTime = 0.1;
        
        // 击退
        if (direction) {
            const knockbackForce = (this.config.knockbackResist) ? 
                2 * (1 - this.config.knockbackResist) : 2;
            this.knockback.copy(direction).multiplyScalar(knockbackForce);
            this.knockback.y = 0;
        }
        
        // 闪白
        this.hitFlash();
        
        // 更新血条
        this.updateHealthBar();
        
        // 伤害数字
        if (effects && effects.createDamageNumber) {
            effects.createDamageNumber(this.mesh.position.clone().add(new THREE.Vector3(0, this.size * 2, 0)), Math.round(amount));
        }
        
        if (this.health <= 0) {
            this.die();
        }
    }
    
    hitFlash() {
        const body = this.mesh.children[0];
        if (body && body.material) {
            const originalEmissive = body.material.emissive.getHex();
            body.material.emissive.setHex(0xffffff);
            body.material.emissiveIntensity = 1;
            
            setTimeout(() => {
                if (body.material) {
                    body.material.emissive.setHex(originalEmissive);
                    body.material.emissiveIntensity = 0.2;
                }
            }, 50);
        }
    }
    
    updateHealthBar() {
        const healthBar = this.mesh.getObjectByName('healthBar');
        const healthBarBg = this.mesh.getObjectByName('healthBarBg');
        
        if (healthBar) {
            const healthPercent = this.health / this.maxHealth;
            healthBar.scale.x = healthPercent;
            
            // 根据血量变色
            if (healthPercent > 0.6) {
                healthBar.material.color.setHex(0x00ff00);
            } else if (healthPercent > 0.3) {
                healthBar.material.color.setHex(0xffff00);
            } else {
                healthBar.material.color.setHex(0xff0000);
            }
            
            // 血条面向相机
            healthBar.lookAt(renderer.camera.position);
        }
        
        if (healthBarBg) {
            healthBarBg.lookAt(renderer.camera.position);
        }
    }
    
    die() {
        this.dead = true;
        this.dying = true;
        this.deathTime = 0;
        
        // 加分
        gameState.addScore(this.scoreValue);
        gameState.addKill();
        
        // 死亡特效
        if (effects && effects.createExplosion) {
            effects.createExplosion(this.mesh.position.clone(), this.color, this.size);
        }
        
        if (audio) audio.playKill();
        
        // 概率掉落拾取物
        if (pickups && pickups.trySpawnOnEnemyDeath) {
            pickups.trySpawnOnEnemyDeath(this);
        }
        
        // 移除网格(延迟一点让特效播放)
        setTimeout(() => {
            if (this.mesh) {
                renderer.scene.remove(this.mesh);
                this.mesh = null;
            }
        }, 300);
    }
    
    updateDeath(deltaTime) {
        this.deathTime += deltaTime;
        if (this.mesh) {
            this.mesh.scale.multiplyScalar(1 - deltaTime * 3);
            this.mesh.rotation.y += deltaTime * 5;
        }
    }
}

class EnemyManager {
    constructor() {
        this.list = [];
        this.spawnTimer = 0;
    }
    
    init() {
        this.list = [];
        return this;
    }
    
    spawnEnemy(type, position) {
        const enemy = new Enemy(type, position);
        this.list.push(enemy);
        return enemy;
    }
    
    spawnWave(waveNumber) {
        const baseCount = 3 + waveNumber * 2;
        const types = ['drone', 'grunt'];
        
        if (waveNumber >= 3) types.push('pouncer');
        if (waveNumber >= 5) types.push('bomber');
        if (waveNumber >= 7) types.push('tank');
        
        for (let i = 0; i < baseCount; i++) {
            const type = types[Math.floor(Math.random() * types.length)];
            
            // 在竞技场边缘生成
            const angle = Math.random() * Math.PI * 2;
            const distance = CONFIG.ARENA_SIZE - 2;
            const position = new THREE.Vector3(
                Math.cos(angle) * distance,
                0,
                Math.sin(angle) * distance
            );
            
            // 延迟生成,避免同时出现
            setTimeout(() => {
                if (gameState.isPlaying()) {
                    this.spawnEnemy(type, position);
                }
            }, i * 300);
        }
    }
    
    update(deltaTime, playerPos) {
        for (let i = this.list.length - 1; i >= 0; i--) {
            const enemy = this.list[i];
            enemy.update(deltaTime, playerPos);
            
            if (enemy.dead && enemy.deathTime > 0.5) {
                this.list.splice(i, 1);
            }
        }
        
        // 检查波次是否完成
        if (this.list.length === 0 && gameState.isPlaying() && gameState.wave > 0) {
            // 波次完成,通知波次管理器
            if (waveManager && waveManager.onWaveComplete) {
                waveManager.onWaveComplete();
            }
        }
    }
    
    clear() {
        for (const enemy of this.list) {
            if (enemy.mesh) {
                renderer.scene.remove(enemy.mesh);
            }
        }
        this.list = [];
    }
    
    get aliveCount() {
        return this.list.filter(e => !e.dead).length;
    }
}

const enemies = new EnemyManager();


// boss.js
// Boss系统
class Boss {
    constructor(type, position) {
        this.type = type;
        this.config = CONFIG.BOSSES[type];
        this.maxHealth = this.config.health;
        this.health = this.config.health;
        this.speed = this.config.speed;
        this.damage = this.config.damage;
        this.score = this.config.score;
        this.color = this.config.color;
        this.size = this.config.size;
        this.dead = false;
        this.isBoss = true;
        
        this.phase = 1;
        this.phase2Threshold = this.config.phase2Health;
        this.abilities = this.config.abilities;
        this.abilityCooldown = {};
        this.lastAttackTime = 0;
        this.attackCooldown = 2000; // 毫秒
        
        this.mesh = null;
        this.targetPosition = new THREE.Vector3();
        this.velocity = new THREE.Vector3();
        
        this.hitFlashTime = 0;
        this.staggerTime = 0;
        
        // 特殊效果
        this.shieldActive = false;
        this.shieldAmount = 0;
        this.isCharging = false;
        this.chargeDirection = new THREE.Vector3();
        
        this.createMesh(position);
        this.initAbilities();
    }
    
    createMesh(position) {
        this.mesh = new THREE.Group();
        this.mesh.position.copy(position);
        this.mesh.position.y = this.size * 0.5;
        
        // Boss主体
        const bodyGeo = new THREE.BoxGeometry(this.size * 0.8, this.size, this.size * 0.6);
        const bodyMat = new THREE.MeshStandardMaterial({ 
            color: this.color, 
            emissive: this.color, 
            emissiveIntensity: 0.3,
            metalness: 0.7,
            roughness: 0.3
        });
        const body = new THREE.Mesh(bodyGeo, bodyMat);
        body.position.y = 0;
        this.mesh.add(body);
        
        // 头部/核心
        const headGeo = new THREE.IcosahedronGeometry(this.size * 0.35, 1);
        const headMat = new THREE.MeshStandardMaterial({ 
            color: 0xffffff, 
            emissive: this.color,
            emissiveIntensity: 0.5,
            metalness: 0.9,
            roughness: 0.1
        });
        const head = new THREE.Mesh(headGeo, headMat);
        head.position.y = this.size * 0.5;
        this.mesh.add(head);
        
        // 眼睛
        for (let i = -1; i <= 1; i += 2) {
            const eyeGeo = new THREE.SphereGeometry(this.size * 0.08, 8, 8);
            const eyeMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });
            const eye = new THREE.Mesh(eyeGeo, eyeMat);
            eye.position.set(i * this.size * 0.15, this.size * 0.55, this.size * 0.25);
            this.mesh.add(eye);
        }
        
        // 手臂/武器
        for (let i = -1; i <= 1; i += 2) {
            const armGeo = new THREE.CylinderGeometry(this.size * 0.1, this.size * 0.15, this.size * 0.8, 8);
            const armMat = new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.8 });
            const arm = new THREE.Mesh(armGeo, armMat);
            arm.position.set(i * this.size * 0.5, 0, 0);
            arm.rotation.z = i * 0.3;
            this.mesh.add(arm);
            
            // 武器端
            const weaponGeo = new THREE.ConeGeometry(this.size * 0.2, this.size * 0.4, 8);
            const weaponMat = new THREE.MeshStandardMaterial({ 
                color: this.color, 
                emissive: this.color, 
                emissiveIntensity: 0.4 
            });
            const weapon = new THREE.Mesh(weaponGeo, weaponMat);
            weapon.position.set(i * this.size * 0.5, -this.size * 0.5, 0);
            weapon.rotation.x = Math.PI;
            this.mesh.add(weapon);
        }
        
        // 护盾(初始隐藏)
        this.shieldMesh = new THREE.Mesh(
            new THREE.SphereGeometry(this.size * 1.2, 16, 16),
            new THREE.MeshBasicMaterial({ 
                color: 0x00ffff, 
                transparent: true, 
                opacity: 0.3,
                side: THREE.DoubleSide
            })
        );
        this.shieldMesh.visible = false;
        this.mesh.add(this.shieldMesh);
        
        // 血条
        this.createHealthBar();
        
        renderer.scene.add(this.mesh);
    }
    
    createHealthBar() {
        // 世界空间血条 - 在Boss头顶
        this.healthBarGroup = new THREE.Group();
        this.healthBarGroup.position.y = this.size + 0.5;
        
        const bgGeo = new THREE.PlaneGeometry(this.size * 1.5, 0.3);
        const bgMat = new THREE.MeshBasicMaterial({ color: 0x333333, side: THREE.DoubleSide });
        const bg = new THREE.Mesh(bgGeo, bgMat);
        this.healthBarGroup.add(bg);
        
        const fillGeo = new THREE.PlaneGeometry(this.size * 1.5, 0.3);
        const fillMat = new THREE.MeshBasicMaterial({ color: 0x00ff00, side: THREE.DoubleSide });
        this.healthBarFill = new THREE.Mesh(fillGeo, fillMat);
        this.healthBarFill.position.z = 0.01;
        this.healthBarGroup.add(this.healthBarFill);
        
        // Boss名字
        const canvas = document.createElement('canvas');
        canvas.width = 256;
        canvas.height = 64;
        const ctx = canvas.getContext('2d');
        ctx.fillStyle = '#ffffff';
        ctx.font = 'bold 28px Arial';
        ctx.textAlign = 'center';
        ctx.fillText(this.config.name, 128, 40);
        
        const texture = new THREE.CanvasTexture(canvas);
        const nameMat = new THREE.MeshBasicMaterial({ map: texture, transparent: true, side: THREE.DoubleSide });
        const nameMesh = new THREE.Mesh(new THREE.PlaneGeometry(this.size * 2, 0.5), nameMat);
        nameMesh.position.y = 0.5;
        this.healthBarGroup.add(nameMesh);
        
        this.mesh.add(this.healthBarGroup);
    }
    
    initAbilities() {
        for (const ability of this.abilities) {
            this.abilityCooldown[ability] = 0;
        }
    }
    
    update(deltaTime, playerPos) {
        if (this.dead) return;
        
        // 更新冷却
        for (const ability in this.abilityCooldown) {
            if (this.abilityCooldown[ability] > 0) {
                this.abilityCooldown[ability] -= deltaTime * 1000;
            }
        }
        
        if (this.hitFlashTime > 0) this.hitFlashTime -= deltaTime;
        if (this.staggerTime > 0) {
            this.staggerTime -= deltaTime;
            return; // 硬直中不行动
        }
        
        // 阶段转换
        if (this.phase === 1 && this.health <= this.maxHealth * this.phase2Threshold) {
            this.enterPhase2();
        }
        
        // 血条朝向玩家
        this.healthBarGroup.lookAt(playerPos);
        
        // AI行为
        const toPlayer = new THREE.Vector3();
        toPlayer.subVectors(playerPos, this.mesh.position);
        const distance = toPlayer.length();
        toPlayer.y = 0;
        toPlayer.normalize();
        
        // 面向玩家
        this.mesh.lookAt(playerPos.x, this.mesh.position.y, playerPos.z);
        
        // 移动
        if (distance > 5) {
            this.mesh.position.x += toPlayer.x * this.speed * deltaTime;
            this.mesh.position.z += toPlayer.z * this.speed * deltaTime;
        }
        
        // 普通攻击
        const now = Date.now();
        if (distance < 8 && now - this.lastAttackTime > this.attackCooldown) {
            this.basicAttack(playerPos);
            this.lastAttackTime = now;
        }
        
        // 技能使用
        this.useAbilities(deltaTime, playerPos, distance);
        
        // 碰撞伤害
        if (distance < this.size * 0.8 && player) {
            player.takeDamage(this.damage * deltaTime * 0.5);
        }
        
        // 边界限制
        const boundary = CONFIG.ARENA_SIZE - 3;
        this.mesh.position.x = Math.max(-boundary, Math.min(boundary, this.mesh.position.x));
        this.mesh.position.z = Math.max(-boundary, Math.min(boundary, this.mesh.position.z));
    }
    
    basicAttack(playerPos) {
        // 发射投射物
        const direction = new THREE.Vector3();
        direction.subVectors(playerPos, this.mesh.position);
        direction.normalize();
        
        if (particles) {
            particles.createEnemyBullet(this.mesh.position.clone(), direction, this.damage, this.color, 15);
        }
    }
    
    useAbilities(deltaTime, playerPos, distance) {
        const now = Date.now();
        
        // 根据Boss类型使用不同技能
        switch (this.type) {
            case 'cyberTitan':
                this.cyberTitanAbilities(playerPos, distance, now);
                break;
            case 'voidWalker':
                this.voidWalkerAbilities(playerPos, distance, now);
                break;
            case 'plasmaCore':
                this.plasmaCoreAbilities(playerPos, distance, now);
                break;
        }
    }
    
    cyberTitanAbilities(playerPos, distance, now) {
        // 地震波
        if (this.abilityCooldown['slam'] <= 0 && distance < 10) {
            this.abilityCooldown['slam'] = this.phase === 2 ? 6000 : 10000;
            this.slamAttack();
        }
        
        // 召唤小怪
        if (this.abilityCooldown['summon'] <= 0) {
            this.abilityCooldown['summon'] = this.phase === 2 ? 8000 : 15000;
            this.summonMinions();
        }
        
        // 激光
        if (this.abilityCooldown['laser'] <= 0 && distance > 8) {
            this.abilityCooldown['laser'] = this.phase === 2 ? 4000 : 7000;
            this.laserAttack(playerPos);
        }
    }
    
    voidWalkerAbilities(playerPos, distance, now) {
        // 传送
        if (this.abilityCooldown['teleport'] <= 0 && distance < 5) {
            this.abilityCooldown['teleport'] = this.phase === 2 ? 4000 : 8000;
            this.teleport(playerPos);
        }
        
        // 影子分身
        if (this.abilityCooldown['shadowClones'] <= 0) {
            this.abilityCooldown['shadowClones'] = this.phase === 2 ? 12000 : 20000;
            this.shadowClones();
        }
        
        // 虚空冲击
        if (this.abilityCooldown['voidBlast'] <= 0) {
            this.abilityCooldown['voidBlast'] = this.phase === 2 ? 5000 : 10000;
            this.voidBlast();
        }
    }
    
    plasmaCoreAbilities(playerPos, distance, now) {
        // 等离子雨
        if (this.abilityCooldown['plasmaRain'] <= 0) {
            this.abilityCooldown['plasmaRain'] = this.phase === 2 ? 8000 : 15000;
            this.plasmaRain();
        }
        
        // 护盾
        if (this.abilityCooldown['shield'] <= 0 && this.health < this.maxHealth * 0.6) {
            this.abilityCooldown['shield'] = this.phase === 2 ? 15000 : 25000;
            this.activateShield();
        }
        
        // 过载(全屏AOE)
        if (this.abilityCooldown['overload'] <= 0 && this.phase === 2) {
            this.abilityCooldown['overload'] = 20000;
            this.overload();
        }
    }
    
    slamAttack() {
        // 地震波 - 地面扩散的冲击波
        if (effects) {
            effects.createShockwave(this.mesh.position.clone(), this.color, 15, 0.5);
        }
        
        // 延迟伤害
        setTimeout(() => {
            if (this.dead || !player) return;
            const dist = this.mesh.position.distanceTo(player.mesh.position);
            if (dist < 10) {
                const damage = this.damage * (1 - dist / 12);
                player.takeDamage(damage);
            }
        }, 500);
        
        if (audio) audio.playBossAbility();
    }
    
    summonMinions() {
        // 召唤2-3个小怪
        const count = this.phase === 2 ? 3 : 2;
        for (let i = 0; i < count; i++) {
            const angle = (Math.PI * 2 / count) * i + Math.random() * 0.5;
            const spawnPos = this.mesh.position.clone();
            spawnPos.x += Math.cos(angle) * 3;
            spawnPos.z += Math.sin(angle) * 3;
            
            if (enemies) {
                const enemy = enemies.spawnEnemy('drone', spawnPos);
                if (enemy) {
                    enemy.health *= 1.5; // 强化小怪
                    enemy.maxHealth *= 1.5;
                }
            }
        }
        
        hud.showBossAnnouncement('召唤了援军!');
    }
    
    laserAttack(playerPos) {
        // 激光攻击 - 追踪玩家的持续激光
        if (effects) {
            effects.createLaserBeam(this.mesh.position.clone(), playerPos.clone(), this.color, 1);
        }
        
        setTimeout(() => {
            if (this.dead || !player) return;
            player.takeDamage(this.damage * 0.8);
        }, 300);
    }
    
    teleport(playerPos) {
        // 传送到玩家背后
        const direction = new THREE.Vector3();
        direction.subVectors(this.mesh.position, playerPos);
        direction.normalize();
        
        const newPos = playerPos.clone();
        newPos.addScaledVector(direction, 5);
        newPos.y = this.size * 0.5;
        
        // 传送特效
        if (particles) {
            particles.createExplosion(this.mesh.position.clone(), this.color, 20);
            particles.createExplosion(newPos.clone(), this.color, 20);
        }
        
        this.mesh.position.copy(newPos);
        
        if (audio) audio.playBossAbility();
    }
    
    shadowClones() {
        // 影子分身 - 创建两个假身
        hud.showBossAnnouncement('召唤了影子分身!');
        
        if (enemies) {
            for (let i = 0; i < 2; i++) {
                const angle = i * Math.PI + Math.PI / 2;
                const spawnPos = this.mesh.position.clone();
                spawnPos.x += Math.cos(angle) * 4;
                spawnPos.z += Math.sin(angle) * 4;
                
                const clone = enemies.spawnEnemy('grunt', spawnPos);
                if (clone) {
                    clone.health = this.health * 0.2;
                    clone.maxHealth = clone.health;
                    clone.mesh.scale.setScalar(0.7);
                    clone.isClone = true;
                }
            }
        }
    }
    
    voidBlast() {
        // 虚空冲击 - 范围AOE
        if (effects) {
            effects.createShockwave(this.mesh.position.clone(), 0x8800ff, 20, 0.8);
        }
        
        setTimeout(() => {
            if (this.dead || !player) return;
            const dist = this.mesh.position.distanceTo(player.mesh.position);
            if (dist < 15) {
                player.takeDamage(this.damage * 0.7);
            }
        }, 400);
        
        if (audio) audio.playBossAbility();
    }
    
    plasmaRain() {
        // 等离子雨 - 从天而降的等离子弹
        hud.showBossAnnouncement('等离子雨来袭!');
        
        for (let i = 0; i < 8; i++) {
            setTimeout(() => {
                if (this.dead) return;
                
                const targetPos = new THREE.Vector3(
                    (Math.random() - 0.5) * CONFIG.ARENA_SIZE * 1.5,
                    20,
                    (Math.random() - 0.5) * CONFIG.ARENA_SIZE * 1.5
                );
                
                if (particles) {
                    const direction = new THREE.Vector3(0, -1, 0);
                    particles.createEnemyBullet(targetPos, direction, this.damage * 0.5, 0x00ffff, 20);
                }
            }, i * 200);
        }
        
        if (audio) audio.playBossAbility();
    }
    
    activateShield() {
        // 激活护盾
        this.shieldActive = true;
        this.shieldAmount = this.maxHealth * 0.3;
        this.shieldMesh.visible = true;
        
        hud.showBossAnnouncement('激活了能量护盾!');
        
        // 护盾持续10秒
        setTimeout(() => {
            this.shieldActive = false;
            this.shieldMesh.visible = false;
        }, 10000);
    }
    
    overload() {
        // 过载 - 全屏大爆炸
        hud.showBossAnnouncement('警告:Boss即将过载!');
        
        // 蓄力2秒
        if (effects) {
            effects.showScreenGlow(this.color, 0.5);
        }
        
        setTimeout(() => {
            if (this.dead || !player) return;
            
            // 全屏伤害
            player.takeDamage(this.damage * 1.5);
            
            if (effects) {
                effects.createShockwave(this.mesh.position.clone(), this.color, 30, 1);
                effects.shake(1, 0.3);
                effects.hideScreenGlow();
            }
        }, 2000);
    }
    
    enterPhase2() {
        this.phase = 2;
        this.speed *= 1.5;
        this.attackCooldown *= 0.7;
        
        // 阶段转换特效
        if (effects) {
            effects.createShockwave(this.mesh.position.clone(), this.color, 20, 0.5);
            effects.shake(0.8, 0.2);
        }
        
        hud.showBossAnnouncement('进入狂暴状态!');
        
        // 血条变色
        this.healthBarFill.material.color.setHex(0xff0000);
        
        if (audio) audio.playBossPhase();
    }
    
    takeDamage(amount, hitDirection = null) {
        if (this.dead) return false;
        
        // 护盾减伤
        let actualDamage = amount;
        if (this.shieldActive && this.shieldAmount > 0) {
            const shieldAbsorb = Math.min(this.shieldAmount, amount * 0.8);
            this.shieldAmount -= shieldAbsorb;
            actualDamage = amount - shieldAbsorb;
            
            if (this.shieldAmount <= 0) {
                this.shieldActive = false;
                this.shieldMesh.visible = false;
            }
        }
        
        this.health -= actualDamage;
        this.hitFlashTime = 0.1;
        
        // 更新血条
        const healthPercent = Math.max(0, this.health / this.maxHealth);
        this.healthBarFill.scale.x = healthPercent;
        
        // 血条颜色变化
        if (healthPercent > 0.6) {
            this.healthBarFill.material.color.setHex(0x00ff00);
        } else if (healthPercent > 0.3) {
            this.healthBarFill.material.color.setHex(0xffff00);
        } else {
            this.healthBarFill.material.color.setHex(0xff0000);
        }
        
        // 受伤闪烁
        this.mesh.traverse((child) => {
            if (child.isMesh && child.material && child.material.emissive) {
                child.material.emissiveIntensity = 0.8;
                setTimeout(() => {
                    if (child.material) {
                        child.material.emissiveIntensity = 0.3;
                    }
                }, 100);
            }
        });
        
        if (this.health <= 0) {
            this.die();
        }
        
        return true;
    }
    
    die() {
        this.dead = true;
        
        // 死亡爆炸
        if (particles) {
            particles.createExplosion(this.mesh.position.clone(), this.color, 50);
        }
        
        if (effects) {
            effects.shake(1, 0.3);
            effects.createShockwave(this.mesh.position.clone(), this.color, 25, 0.8);
        }
        
        // 掉落拾取物
        if (pickups) {
            pickups.spawnPickup(this.mesh.position.clone(), 'health');
            pickups.spawnPickup(this.mesh.position.clone().add(new THREE.Vector3(2, 0, 0)), 'coin');
            pickups.spawnPickup(this.mesh.position.clone().add(new THREE.Vector3(-2, 0, 2)), 'damageBoost');
        }
        
        // 加分
        if (gameState) {
            gameState.addScore(this.score);
        }
        
        // 成就
        if (achievements) {
            achievements.unlock('boss_killer');
        }
        
        if (audio) audio.playBossDeath();
        
        // 延迟移除
        setTimeout(() => {
            if (this.mesh && this.mesh.parent) {
                this.mesh.parent.remove(this.mesh);
            }
        }, 1000);
    }
}

// Boss管理器
class BossManager {
    constructor() {
        this.bosses = [];
        this.activeBoss = null;
    }
    
    spawnBoss(type, position) {
        const boss = new Boss(type, position);
        this.bosses.push(boss);
        this.activeBoss = boss;
        
        hud.showBossAnnouncement(`${boss.config.name} 出现了!`);
        hud.showBossHealthBar(true);
        
        return boss;
    }
    
    update(deltaTime, playerPos) {
        for (let i = this.bosses.length - 1; i >= 0; i--) {
            const boss = this.bosses[i];
            boss.update(deltaTime, playerPos);
            
            if (boss.dead) {
                this.bosses.splice(i, 1);
                if (this.activeBoss === boss) {
                    this.activeBoss = null;
                    hud.showBossHealthBar(false);
                }
            }
        }
    }
    
    getActiveBoss() {
        return this.activeBoss;
    }
    
    reset() {
        for (const boss of this.bosses) {
            if (boss.mesh && boss.mesh.parent) {
                boss.mesh.parent.remove(boss.mesh);
            }
        }
        this.bosses = [];
        this.activeBoss = null;
        hud.showBossHealthBar(false);
    }
}

const bossManager = new BossManager();


// pickups.js
// 拾取物系统
class Pickup {
    constructor(type, position) {
        this.type = type;
        this.config = CONFIG.PICKUPS[type];
        this.position = position.clone();
        this.position.y = 0.5;
        this.dead = false;
        this.bobOffset = Math.random() * Math.PI * 2;
        
        this.createMesh();
    }
    
    createMesh() {
        this.mesh = new THREE.Group();
        
        const color = this.config.color;
        
        // 根据类型创建不同形状
        let geometry;
        switch (this.type) {
            case 'health':
                // 十字形生命包
                geometry = new THREE.BoxGeometry(0.6, 0.6, 0.2);
                const horizontal = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color }));
                const vertical = new THREE.Mesh(
                    new THREE.BoxGeometry(0.2, 0.6, 0.6),
                    new THREE.MeshBasicMaterial({ color })
                );
                this.mesh.add(horizontal);
                this.mesh.add(vertical);
                break;
                
            case 'damageBoost':
                // 火焰形状
                geometry = new THREE.ConeGeometry(0.3, 0.8, 8);
                this.mesh.add(new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color })));
                break;
                
            case 'speedBoost':
                // 闪电形状
                const lightningShape = new THREE.Shape();
                lightningShape.moveTo(0, 0.4);
                lightningShape.lineTo(-0.2, 0);
                lightningShape.lineTo(0, -0.1);
                lightningShape.lineTo(-0.15, -0.4);
                lightningShape.lineTo(0.15, -0.1);
                lightningShape.lineTo(0, 0);
                geometry = new THREE.ExtrudeGeometry(lightningShape, { depth: 0.1, bevelEnabled: false });
                geometry.center();
                this.mesh.add(new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color })));
                break;
                
            case 'shield':
                // 盾牌形状
                geometry = new THREE.TorusGeometry(0.35, 0.08, 8, 16);
                const shieldRing = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color }));
                shieldRing.rotation.x = Math.PI / 2;
                this.mesh.add(shieldRing);
                
                const shieldCenter = new THREE.Mesh(
                    new THREE.CircleGeometry(0.25, 16),
                    new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.5 })
                );
                shieldCenter.rotation.x = -Math.PI / 2;
                shieldCenter.position.y = 0.05;
                this.mesh.add(shieldCenter);
                break;
                
            case 'coin':
                // 硬币/能量核心
                geometry = new THREE.OctahedronGeometry(0.3);
                const coinMat = new THREE.MeshStandardMaterial({ 
                    color, 
                    emissive: color, 
                    emissiveIntensity: 0.5,
                    metalness: 0.9,
                    roughness: 0.1
                });
                this.mesh.add(new THREE.Mesh(geometry, coinMat));
                
                // 光环
                const ringGeo = new THREE.TorusGeometry(0.4, 0.03, 8, 16);
                const ringMat = new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.6 });
                const ring = new THREE.Mesh(ringGeo, ringMat);
                ring.rotation.x = Math.PI / 2;
                this.mesh.add(ring);
                break;
                
            default:
                geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
                this.mesh.add(new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color })));
        }
        
        // 发光效果
        const light = new THREE.PointLight(color, 0.5, 3);
        light.position.y = 0.5;
        this.mesh.add(light);
        
        this.mesh.position.copy(this.position);
        renderer.scene.add(this.mesh);
    }
    
    update(deltaTime, playerPos) {
        if (this.dead) return;
        
        // 上下浮动 + 旋转
        this.bobOffset += deltaTime * 2;
        this.mesh.position.y = this.position.y + Math.sin(this.bobOffset) * 0.2;
        this.mesh.rotation.y += deltaTime;
        
        // 检测玩家拾取
        const distance = this.mesh.position.distanceTo(playerPos);
        if (distance < 1.5) {
            this.collect();
        }
    }
    
    collect() {
        this.dead = true;
        
        // 应用效果
        switch (this.type) {
            case 'health':
                player.heal(this.config.healAmount);
                break;
            case 'damageBoost':
                player.damageBoostMultiplier = this.config.multiplier;
                player.damageBoostTime = this.config.duration;
                break;
            case 'speedBoost':
                player.speedBoostMultiplier = this.config.multiplier;
                player.speedBoostTime = this.config.duration;
                break;
            case 'shield':
                player.shield = (player.shield || 0) + this.config.shieldAmount;
                break;
            case 'coin':
                gameState.addScore(this.config.scoreValue);
                gameState.coinsCollected = (gameState.coinsCollected || 0) + 1;
                
                // 添加到商店金币
                if (shop && shop.addCoins) {
                    shop.addCoins(5); // 每个金币拾取值5个币
                }
                
                if (achievements && gameState.coinsCollected >= 20) {
                    achievements.unlock('collector');
                }
                break;
        }
        
        // 拾取特效
        if (particles) {
            particles.createExplosion(this.mesh.position.clone(), this.config.color, 10);
        }
        
        if (audio) {
            audio.playPickup();
        }
        
        // 移除
        if (this.mesh.parent) {
            this.mesh.parent.remove(this.mesh);
        }
    }
}

// 拾取物管理器
class PickupManager {
    constructor() {
        this.pickups = [];
    }
    
    spawnPickup(position, type = null) {
        // 如果没指定类型,按概率随机
        if (!type) {
            const rand = Math.random();
            let cumulative = 0;
            
            for (const [key, config] of Object.entries(CONFIG.PICKUPS)) {
                cumulative += config.spawnChance;
                if (rand < cumulative) {
                    type = key;
                    break;
                }
            }
            
            if (!type) type = 'coin'; // 默认
        }
        
        const pickup = new Pickup(type, position);
        this.pickups.push(pickup);
        
        return pickup;
    }
    
    trySpawnOnEnemyDeath(enemy) {
        // 敌人死亡时有概率掉落
        const rand = Math.random();
        const dropChance = enemy.isBoss ? 1.0 : 0.15; // Boss必掉,小怪15%
        
        if (rand < dropChance) {
            this.spawnPickup(enemy.mesh.position.clone());
        }
    }
    
    update(deltaTime, playerPos) {
        for (let i = this.pickups.length - 1; i >= 0; i--) {
            const pickup = this.pickups[i];
            pickup.update(deltaTime, playerPos);
            
            if (pickup.dead) {
                this.pickups.splice(i, 1);
            }
        }
    }
    
    reset() {
        for (const pickup of this.pickups) {
            if (pickup.mesh && pickup.mesh.parent) {
                pickup.mesh.parent.remove(pickup.mesh);
            }
        }
        this.pickups = [];
    }
}

const pickups = new PickupManager();


// achievements.js
// 成就系统
class AchievementManager {
    constructor() {
        this.unlocked = new Set();
        this.queue = []; // 待显示的成就
        this.showing = false;
    }
    
    unlock(achievementId) {
        if (this.unlocked.has(achievementId)) return false;
        
        const achievement = CONFIG.ACHIEVEMENTS[achievementId];
        if (!achievement) return false;
        
        this.unlocked.add(achievementId);
        this.queue.push(achievement);
        
        // 保存到本地存储
        this.save();
        
        // 显示成就
        this.showNext();
        
        console.log(`🏆 成就解锁: ${achievement.name}`);
        return true;
    }
    
    showNext() {
        if (this.showing || this.queue.length === 0) return;
        
        this.showing = true;
        const achievement = this.queue.shift();
        
        // 创建成就通知
        this.showNotification(achievement);
        
        if (audio) {
            audio.playAchievement();
        }
    }
    
    showNotification(achievement) {
        const notification = document.createElement('div');
        notification.style.cssText = `
            position: fixed;
            top: 100px;
            right: -300px;
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            border: 2px solid #ffd700;
            border-radius: 10px;
            padding: 15px 20px;
            display: flex;
            align-items: center;
            gap: 15px;
            z-index: 1000;
            transition: right 0.5s ease-out;
            box-shadow: 0 0 20px rgba(255, 215, 0, 0.3);
            min-width: 250px;
        `;
        
        notification.innerHTML = `
            <div style="font-size: 40px;">${achievement.icon}</div>
            <div>
                <div style="color: #ffd700; font-weight: bold; font-size: 14px;">成就解锁!</div>
                <div style="color: white; font-size: 16px; font-weight: bold; margin-top: 2px;">${achievement.name}</div>
                <div style="color: #aaa; font-size: 12px; margin-top: 2px;">${achievement.description}</div>
            </div>
        `;
        
        document.body.appendChild(notification);
        
        // 滑入动画
        setTimeout(() => {
            notification.style.right = '20px';
        }, 100);
        
        // 停留3秒后滑出
        setTimeout(() => {
            notification.style.right = '-300px';
            
            setTimeout(() => {
                if (notification.parentElement) {
                    notification.parentElement.removeChild(notification);
                }
                this.showing = false;
                this.showNext();
            }, 500);
        }, 3000);
    }
    
    checkAchievements(stats) {
        // 根据游戏状态检查成就
        if (stats.wave >= 5) this.unlock('wave_5');
        if (stats.wave >= 10) this.unlock('wave_10');
        if (stats.wave >= 20) this.unlock('wave_20');
        if (stats.kills >= 1) this.unlock('first_blood');
        if (stats.maxCombo >= 10) this.unlock('combo_10');
        if (stats.meleeKills >= 50) this.unlock('melee_master');
        if (stats.perfectWave) this.unlock('perfect_wave');
    }
    
    getAllUnlocked() {
        return Array.from(this.unlocked);
    }
    
    getAllAchievements() {
        return Object.entries(CONFIG.ACHIEVEMENTS).map(([id, data]) => ({
            id,
            ...data,
            unlocked: this.unlocked.has(id)
        }));
    }
    
    save() {
        try {
            localStorage.setItem('neonFPS_achievements', JSON.stringify(Array.from(this.unlocked)));
        } catch (e) {
            // localStorage不可用
        }
    }
    
    load() {
        try {
            const saved = localStorage.getItem('neonFPS_achievements');
            if (saved) {
                this.unlocked = new Set(JSON.parse(saved));
            }
        } catch (e) {
            // localStorage不可用
        }
    }
    
    reset() {
        this.unlocked.clear();
        this.save();
    }
}

const achievements = new AchievementManager();


// combo.js
// 连击系统
class ComboSystem {
    constructor() {
        this.combo = 0;
        this.maxCombo = 0;
        this.comboTimer = 0;
        this.comboDuration = 3.0; // 连击持续时间(秒)
        this.score = 0;
        this.totalKills = 0;
        this.totalDamageDealt = 0;
        this.headshotCount = 0;
        
        // 连击加成
        this.comboMultipliers = [
            { threshold: 5, multiplier: 1.5, name: "连杀" },
            { threshold: 10, multiplier: 2.0, name: "狂杀" },
            { threshold: 20, multiplier: 3.0, name: "屠戮" },
            { threshold: 30, multiplier: 4.0, name: "灭世" },
            { threshold: 50, multiplier: 5.0, name: "神挡杀神" },
        ];
        
        // 成就相关
        this.achievements = null;
    }
    
    init(achievements) {
        this.achievements = achievements;
    }
    
    reset() {
        this.combo = 0;
        this.maxCombo = 0;
        this.comboTimer = 0;
        this.score = 0;
        this.totalKills = 0;
        this.totalDamageDealt = 0;
        this.headshotCount = 0;
    }
    
    update(deltaTime) {
        if (this.combo > 0) {
            this.comboTimer -= deltaTime;
            if (this.comboTimer <= 0) {
                this.resetCombo();
            }
        }
    }
    
    addKill(enemy, isHeadshot = false) {
        this.combo++;
        this.comboTimer = this.comboDuration;
        this.totalKills++;
        
        if (this.combo > this.maxCombo) {
            this.maxCombo = this.combo;
        }
        
        // 计算得分
        let baseScore = enemy.scoreValue || 100;
        let multiplier = this.getMultiplier();
        
        if (isHeadshot) {
            baseScore *= 2;
            this.headshotCount++;
        }
        
        const scoreGain = Math.floor(baseScore * multiplier);
        this.score += scoreGain;
        
        // 检查成就
        if (this.achievements) {
            if (this.combo >= 10) {
                this.achievements.unlock('combo_10');
            }
            if (this.combo >= 25) {
                this.achievements.unlock('combo_25');
            }
            if (this.combo >= 50) {
                this.achievements.unlock('combo_50');
            }
            if (this.headshotCount >= 50) {
                this.achievements.unlock('headshot_master');
            }
            if (this.totalKills >= 100) {
                this.achievements.unlock('killer_100');
            }
        }
        
        return {
            combo: this.combo,
            score: this.score,
            scoreGain: scoreGain,
            multiplier: multiplier,
            isHeadshot: isHeadshot
        };
    }
    
    addDamage(damage) {
        this.totalDamageDealt += damage;
    }
    
    resetCombo() {
        this.combo = 0;
        this.comboTimer = 0;
    }
    
    getMultiplier() {
        let multiplier = 1.0;
        for (const tier of this.comboMultipliers) {
            if (this.combo >= tier.threshold) {
                multiplier = tier.multiplier;
            }
        }
        return multiplier;
    }
    
    getComboName() {
        let name = "";
        for (const tier of this.comboMultipliers) {
            if (this.combo >= tier.threshold) {
                name = tier.name;
            }
        }
        return name;
    }
    
    getGrade() {
        // 根据分数和表现评级
        if (this.score >= 50000) return { grade: "S+", color: "#ffd700" };
        if (this.score >= 30000) return { grade: "S", color: "#ffd700" };
        if (this.score >= 20000) return { grade: "A", color: "#00ff88" };
        if (this.score >= 10000) return { grade: "B", color: "#00aaff" };
        if (this.score >= 5000) return { grade: "C", color: "#aa88ff" };
        if (this.score >= 2000) return { grade: "D", color: "#ff8888" };
        return { grade: "F", color: "#ff4444" };
    }
    
    getStats() {
        return {
            score: this.score,
            combo: this.combo,
            maxCombo: this.maxCombo,
            totalKills: this.totalKills,
            totalDamageDealt: Math.floor(this.totalDamageDealt),
            headshotCount: this.headshotCount,
            grade: this.getGrade()
        };
    }
}

// 飘字系统
class FloatingText {
    constructor(x, y, z, text, color = '#ffffff', size = 24) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.text = text;
        this.color = color;
        this.size = size;
        this.life = 1.5;
        this.maxLife = 1.5;
        this.velocityY = 2;
        this.velocityX = (Math.random() - 0.5) * 0.5;
        this.opacity = 1;
        this.scale = 1;
    }
    
    update(deltaTime) {
        this.life -= deltaTime;
        this.y += this.velocityY * deltaTime;
        this.x += this.velocityX * deltaTime;
        this.opacity = this.life / this.maxLife;
        this.scale = 1 + (1 - this.opacity) * 0.5;
        return this.life > 0;
    }
}

class FloatingTextManager {
    constructor() {
        this.texts = [];
    }
    
    add(x, y, z, text, color = '#ffffff', size = 24) {
        this.texts.push(new FloatingText(x, y, z, text, color, size));
    }
    
    addDamage(x, y, z, damage, isCrit = false, isHeadshot = false) {
        let color = isHeadshot ? '#ff4444' : '#ffffff';
        let size = isHeadshot ? 28 : 20;
        let text = Math.floor(damage).toString();
        if (isHeadshot) {
            text = "暴击! " + text;
        }
        this.add(x, y + 1, z, text, color, size);
    }
    
    addCombo(x, y, z, combo, multiplier) {
        const text = `${combo} 连击! x${multiplier}`;
        this.add(x, y + 2, z, text, '#ffd700', 32);
    }
    
    update(deltaTime) {
        this.texts = this.texts.filter(t => t.update(deltaTime));
    }
    
    getTexts() {
        return this.texts;
    }
    
    clear() {
        this.texts = [];
    }
}

// 导出
if (typeof window !== 'undefined') {
    window.ComboSystem = ComboSystem;
    window.FloatingTextManager = FloatingTextManager;
}


// skills.js
// 技能系统
class Skill {
    constructor(config) {
        this.name = config.name;
        this.description = config.description;
        this.cooldown = config.cooldown; // 冷却时间(秒)
        this.currentCooldown = 0;
        this.duration = config.duration || 0; // 持续时间
        this.remainingDuration = 0;
        this.isActive = false;
        this.icon = config.icon || '⚡';
        this.key = config.key || 'Q';
        
        // 效果参数
        this.effects = config.effects || {};
        this.onActivate = config.onActivate || (() => {});
        this.onDeactivate = config.onDeactivate || (() => {});
        this.onUpdate = config.onUpdate || (() => {});
    }
    
    canUse() {
        return this.currentCooldown <= 0;
    }
    
    use() {
        if (!this.canUse()) return false;
        
        this.currentCooldown = this.cooldown;
        this.remainingDuration = this.duration;
        this.isActive = true;
        this.onActivate();
        
        return true;
    }
    
    update(deltaTime) {
        if (this.currentCooldown > 0) {
            this.currentCooldown -= deltaTime;
            if (this.currentCooldown < 0) this.currentCooldown = 0;
        }
        
        if (this.isActive && this.duration > 0) {
            this.remainingDuration -= deltaTime;
            this.onUpdate(deltaTime);
            
            if (this.remainingDuration <= 0) {
                this.isActive = false;
                this.remainingDuration = 0;
                this.onDeactivate();
            }
        }
    }
    
    getCooldownPercent() {
        if (this.cooldown <= 0) return 0;
        return this.currentCooldown / this.cooldown;
    }
    
    getDurationPercent() {
        if (this.duration <= 0) return 0;
        return this.remainingDuration / this.duration;
    }
}

// 角色技能定义
const CharacterSkills = {
    warrior: {
        skills: [
            {
                name: '狂暴',
                description: '进入狂暴状态,伤害+50%,移动速度+30%,持续8秒',
                cooldown: 30,
                duration: 8,
                icon: '💢',
                key: 'Q',
                effects: {
                    damageMultiplier: 1.5,
                    speedMultiplier: 1.3
                }
            },
            {
                name: '战吼',
                description: '战吼震慑周围敌人,造成伤害并减速3秒',
                cooldown: 20,
                duration: 0,
                icon: '📢',
                key: 'E',
                effects: {
                    damage: 50,
                    slowAmount: 0.5,
                    slowDuration: 3,
                    radius: 10
                }
            }
        ],
        passive: {
            name: '坚韧',
            description: '最大生命值+50'
        }
    },
    
    ninja: {
        skills: [
            {
                name: '疾风步',
                description: '瞬移一段距离,短暂无敌',
                cooldown: 15,
                duration: 0.5,
                icon: '💨',
                key: 'Q',
                effects: {
                    dashDistance: 15,
                    invincible: true
                }
            },
            {
                name: '影分身',
                description: '创建一个分身吸引敌人注意力,持续5秒',
                cooldown: 25,
                duration: 5,
                icon: '👥',
                key: 'E',
                effects: {
                    cloneCount: 1,
                    cloneHealth: 100
                }
            }
        ],
        passive: {
            name: '敏捷',
            description: '移动速度+20%,暴击率+10%'
        }
    },
    
    engineer: {
        skills: [
            {
                name: '召唤炮塔',
                description: '部署一个自动攻击的炮塔,持续15秒',
                cooldown: 35,
                duration: 15,
                icon: '🔫',
                key: 'Q',
                effects: {
                    turretDamage: 15,
                    turretFireRate: 2,
                    turretRange: 20
                }
            },
            {
                name: '力场护盾',
                description: '展开护盾,减伤50%,持续10秒',
                cooldown: 30,
                duration: 10,
                icon: '🛡️',
                key: 'E',
                effects: {
                    damageReduction: 0.5
                }
            }
        ],
        passive: {
            name: '工程学',
            description: '金币获取+25%,商店物品-10%价格'
        }
    },
    
    medic: {
        skills: [
            {
                name: '治疗脉冲',
                description: '立即恢复50生命值',
                cooldown: 20,
                duration: 0,
                icon: '💚',
                key: 'Q',
                effects: {
                    healAmount: 50
                }
            },
            {
                name: '再生领域',
                description: '持续恢复生命值,持续8秒',
                cooldown: 25,
                duration: 8,
                icon: '✨',
                key: 'E',
                effects: {
                    healPerSecond: 10
                }
            }
        ],
        passive: {
            name: '医学',
            description: '生命恢复速度+50%,拾取生命包效果+25%'
        }
    }
};

// 技能管理器
class SkillManager {
    constructor() {
        this.skills = [];
        this.characterType = null;
        this.player = null;
    }
    
    init(player, characterType) {
        this.player = player;
        this.characterType = characterType;
        this.skills = [];
        
        const charConfig = CharacterSkills[characterType];
        if (charConfig) {
            for (const skillConfig of charConfig.skills) {
                const skill = new Skill({
                    ...skillConfig,
                    onActivate: () => this.onSkillActivate(skillConfig),
                    onDeactivate: () => this.onSkillDeactivate(skillConfig),
                    onUpdate: (dt) => this.onSkillUpdate(skillConfig, dt)
                });
                this.skills.push(skill);
            }
        }
    }
    
    onSkillActivate(config) {
        const effects = config.effects;
        
        // 伤害加成
        if (effects.damageMultiplier) {
            this.player.damageMultiplier *= effects.damageMultiplier;
        }
        
        // 速度加成
        if (effects.speedMultiplier) {
            this.player.speedMultiplier *= effects.speedMultiplier;
        }
        
        // 治疗
        if (effects.healAmount) {
            this.player.heal(effects.healAmount);
        }
        
        // 无敌
        if (effects.invincible) {
            this.player.invincible = true;
        }
        
        // 减伤
        if (effects.damageReduction) {
            this.player.damageReduction += effects.damageReduction;
        }
        
        // 播放音效
        if (window.audioManager) {
            window.audioManager.playSound('skill');
        }
        
        // 视觉效果
        if (window.effectsManager) {
            window.effectsManager.spawnEffect(
                this.player.position.x,
                this.player.position.y + 1,
                this.player.position.z,
                'skill_activate'
            );
        }
    }
    
    onSkillDeactivate(config) {
        const effects = config.effects;
        
        if (effects.damageMultiplier) {
            this.player.damageMultiplier /= effects.damageMultiplier;
        }
        
        if (effects.speedMultiplier) {
            this.player.speedMultiplier /= effects.speedMultiplier;
        }
        
        if (effects.invincible) {
            this.player.invincible = false;
        }
        
        if (effects.damageReduction) {
            this.player.damageReduction -= effects.damageReduction;
        }
    }
    
    onSkillUpdate(config, deltaTime) {
        const effects = config.effects;
        
        // 持续治疗
        if (effects.healPerSecond) {
            this.player.heal(effects.healPerSecond * deltaTime);
        }
    }
    
    useSkill(index) {
        if (index >= 0 && index < this.skills.length) {
            return this.skills[index].use();
        }
        return false;
    }
    
    update(deltaTime) {
        for (const skill of this.skills) {
            skill.update(deltaTime);
        }
    }
    
    getSkills() {
        return this.skills;
    }
    
    getPassive() {
        const charConfig = CharacterSkills[this.characterType];
        return charConfig ? charConfig.passive : null;
    }
}

// 导出
if (typeof window !== 'undefined') {
    window.Skill = Skill;
    window.SkillManager = SkillManager;
    window.CharacterSkills = CharacterSkills;
}


// shop.js
// 商店系统 - 波次间隙购买武器升级
class ShopSystem {
    constructor() {
        this.coins = 0;
        this.weaponLevels = {}; // 每种武器的升级等级
        this.generalUpgrades = {
            maxHealth: 0,
            speed: 0,
            healthRegen: 0
        };
        
        this.shopOpen = false;
    }
    
    init() {
        // 初始化所有武器等级为0
        for (const weaponKey of Object.keys(CONFIG.WEAPONS)) {
            this.weaponLevels[weaponKey] = {
                damage: 0,
                fireRate: 0,
                speed: 0
            };
        }
        
        return this;
    }
    
    addCoins(amount) {
        this.coins += amount;
        document.dispatchEvent(new CustomEvent('coinsUpdate', { detail: { coins: this.coins } }));
    }
    
    spendCoins(amount) {
        if (this.coins >= amount) {
            this.coins -= amount;
            document.dispatchEvent(new CustomEvent('coinsUpdate', { detail: { coins: this.coins } }));
            return true;
        }
        return false;
    }
    
    // 获取升级价格
    getUpgradePrice(weaponKey, upgradeType, level) {
        const basePrices = {
            damage: 50,
            fireRate: 60,
            speed: 40
        };
        const base = basePrices[upgradeType] || 50;
        return Math.floor(base * Math.pow(1.5, level));
    }
    
    getGeneralUpgradePrice(upgradeType, level) {
        const basePrices = {
            maxHealth: 80,
            speed: 70,
            healthRegen: 100
        };
        const base = basePrices[upgradeType] || 80;
        return Math.floor(base * Math.pow(1.6, level));
    }
    
    // 升级武器
    upgradeWeapon(weaponKey, upgradeType) {
        const levels = this.weaponLevels[weaponKey];
        if (!levels) return false;
        
        const maxLevel = CONFIG.WEAPON_UPGRADES[upgradeType]?.maxLevel || 5;
        if (levels[upgradeType] >= maxLevel) return false;
        
        const price = this.getUpgradePrice(weaponKey, upgradeType, levels[upgradeType]);
        if (!this.spendCoins(price)) return false;
        
        levels[upgradeType]++;
        
        // 应用升级到武器
        this.applyWeaponUpgrade(weaponKey, upgradeType);
        
        if (audio) audio.playUpgrade();
        return true;
    }
    
    // 升级通用属性
    upgradeGeneral(upgradeType) {
        const level = this.generalUpgrades[upgradeType];
        const maxLevel = 5;
        if (level >= maxLevel) return false;
        
        const price = this.getGeneralUpgradePrice(upgradeType, level);
        if (!this.spendCoins(price)) return false;
        
        this.generalUpgrades[upgradeType]++;
        this.applyGeneralUpgrade(upgradeType);
        
        if (audio) audio.playUpgrade();
        return true;
    }
    
    // 应用武器升级
    applyWeaponUpgrade(weaponKey, upgradeType) {
        const weapon = weapons.weapons[weaponKey];
        if (!weapon) return;
        
        const level = this.weaponLevels[weaponKey][upgradeType];
        const bonus = CONFIG.WEAPON_UPGRADES[upgradeType]?.bonusPerLevel || 0.1;
        
        switch (upgradeType) {
            case 'damage':
                // 存储基础伤害以便叠加
                if (!weapon.baseDamage) weapon.baseDamage = CONFIG.WEAPONS[weaponKey].damage;
                weapon.damage = weapon.baseDamage * (1 + bonus * level);
                break;
            case 'fireRate':
                if (!weapon.baseFireRate) weapon.baseFireRate = CONFIG.WEAPONS[weaponKey].fireRate;
                weapon.fireRate = weapon.baseFireRate * (1 - bonus * level); // 射速提升=间隔减少
                break;
            case 'speed':
                if (weapon.bulletSpeed !== undefined) {
                    if (!weapon.baseBulletSpeed) weapon.baseBulletSpeed = CONFIG.WEAPONS[weaponKey].bulletSpeed;
                    weapon.bulletSpeed = weapon.baseBulletSpeed * (1 + bonus * level);
                }
                break;
        }
    }
    
    // 应用通用升级
    applyGeneralUpgrade(upgradeType) {
        const level = this.generalUpgrades[upgradeType];
        
        switch (upgradeType) {
            case 'maxHealth':
                if (player) {
                    const bonus = 20 * level;
                    player.maxHealth = CONFIG.PLAYER_MAX_HEALTH + bonus;
                    player.health = Math.min(player.health + 20, player.maxHealth);
                }
                break;
            case 'speed':
                if (player) {
                    player.speedBonus = (player.speedBonus || 0) + 0.5;
                }
                break;
            case 'healthRegen':
                if (player) {
                    player.regenRate = (player.regenRate || 0) + 1; // 每秒回复1点
                }
                break;
        }
    }
    
    // 获取武器当前属性
    getWeaponStats(weaponKey) {
        const weapon = weapons.weapons[weaponKey];
        if (!weapon) return null;
        
        return {
            damage: weapon.damage,
            fireRate: weapon.fireRate,
            bulletSpeed: weapon.bulletSpeed
        };
    }
    
    // 打开商店
    openShop() {
        this.shopOpen = true;
        this.renderShop();
        document.getElementById('shopOverlay').style.display = 'flex';
        
        if (audio) audio.playShopOpen();
    }
    
    // 关闭商店
    closeShop() {
        this.shopOpen = false;
        document.getElementById('shopOverlay').style.display = 'none';
    }
    
    // 渲染商店UI
    renderShop() {
        const shopContent = document.getElementById('shopContent');
        if (!shopContent) return;
        
        let html = '<div class="shop-header">';
        html += '<h2>⚡ 武器升级站</h2>';
        html += `<p class="coins-display">💰 能量核心: <span id="shopCoins">${this.coins}</span></p>`;
        html += '</div>';
        
        // 武器购买区(未解锁的武器)
        const lockedWeapons = Object.entries(CONFIG.WEAPONS).filter(
            ([key, w]) => !weapons.isUnlocked(key) && w.price > 0
        );
        
        if (lockedWeapons.length > 0) {
            html += '<div class="shop-section">';
            html += '<h3>🛒 武器商店</h3>';
            html += '<div class="weapon-upgrades">';
            
            for (const [weaponKey, weapon] of lockedWeapons) {
                const canAfford = this.coins >= weapon.price;
                
                html += `<div class="weapon-upgrade-card locked" style="border-color: #${weapon.color.toString(16).padStart(6, '0')}">`;
                html += `<h4>🔒 ${weapon.name}</h4>`;
                html += `<p class="weapon-desc">${weapon.description || ''}</p>`;
                html += `<div class="weapon-stats">`;
                html += `<span>伤害: ${weapon.damage}</span>`;
                html += `<span>射速: ${(1000/weapon.fireRate).toFixed(1)}/秒</span>`;
                html += `</div>`;
                html += `<button class="buy-btn ${canAfford ? '' : 'disabled'}" 
                        onclick="shop.buyWeapon('${weaponKey}'); shop.renderShop();">
                    ${canAfford ? `购买 (${weapon.price}💰)` : `需要 ${weapon.price}💰`}
                </button>`;
                html += '</div>';
            }
            
            html += '</div></div>';
        }
        
        // 武器升级区
        html += '<div class="shop-section">';
        html += '<h3>⬆️ 武器升级</h3>';
        html += '<div class="weapon-upgrades">';
        
        for (const [weaponKey, weapon] of Object.entries(CONFIG.WEAPONS)) {
            if (weaponKey === 'sword') continue;
            if (!weapons.isUnlocked(weaponKey)) continue; // 未解锁的不显示升级
            
            const levels = this.weaponLevels[weaponKey];
            const weaponStats = this.getWeaponStats(weaponKey) || weapon;
            
            html += `<div class="weapon-upgrade-card" style="border-color: #${weapon.color.toString(16).padStart(6, '0')}">`;
            html += `<h4>${weapon.name}</h4>`;
            html += `<div class="weapon-stats">`;
            html += `<span>伤害: ${weaponStats.damage?.toFixed(0) || weapon.damage}</span>`;
            html += `<span>射速: ${(1000/(weaponStats.fireRate || weapon.fireRate)).toFixed(1)}/秒</span>`;
            html += `</div>`;
            
            // 伤害升级
            const dmgLevel = levels?.damage || 0;
            const dmgMax = CONFIG.WEAPON_UPGRADES.damage.maxLevel;
            const dmgPrice = this.getUpgradePrice(weaponKey, 'damage', dmgLevel);
            const dmgDisabled = dmgLevel >= dmgMax || this.coins < dmgPrice;
            html += `<button class="upgrade-btn ${dmgDisabled ? 'disabled' : ''}" 
                    onclick="shop.upgradeWeapon('${weaponKey}', 'damage'); shop.renderShop();">
                伤害+ ${dmgLevel}/${dmgMax} 
                ${dmgLevel >= dmgMax ? '已满级' : `(${dmgPrice}💰)`}
            </button>`;
            
            // 射速升级
            const frLevel = levels?.fireRate || 0;
            const frMax = CONFIG.WEAPON_UPGRADES.fireRate.maxLevel;
            const frPrice = this.getUpgradePrice(weaponKey, 'fireRate', frLevel);
            const frDisabled = frLevel >= frMax || this.coins < frPrice;
            html += `<button class="upgrade-btn ${frDisabled ? 'disabled' : ''}" 
                    onclick="shop.upgradeWeapon('${weaponKey}', 'fireRate'); shop.renderShop();">
                射速+ ${frLevel}/${frMax} 
                ${frLevel >= frMax ? '已满级' : `(${frPrice}💰)`}
            </button>`;
            
            // 子弹速度升级(仅非激光武器)
            if (weapon.bulletSpeed) {
                const spdLevel = levels?.speed || 0;
                const spdMax = CONFIG.WEAPON_UPGRADES.speed.maxLevel;
                const spdPrice = this.getUpgradePrice(weaponKey, 'speed', spdLevel);
                const spdDisabled = spdLevel >= spdMax || this.coins < spdPrice;
                html += `<button class="upgrade-btn ${spdDisabled ? 'disabled' : ''}" 
                        onclick="shop.upgradeWeapon('${weaponKey}', 'speed'); shop.renderShop();">
                    弹速+ ${spdLevel}/${spdMax} 
                    ${spdLevel >= spdMax ? '已满级' : `(${spdPrice}💰)`}
                </button>`;
            }
            
            html += '</div>';
        }
        html += '</div></div>';
        
        // 通用升级区
        html += '<div class="shop-section">';
        html += '<h3>💪 属性强化</h3>';
        html += '<div class="general-upgrades">';
        
        const generalUpgrades = [
            { key: 'maxHealth', name: '生命上限', icon: '❤️', desc: '+20 最大生命' },
            { key: 'speed', name: '移动速度', icon: '👟', desc: '+0.5 移动速度' },
            { key: 'healthRegen', name: '生命回复', icon: '💚', desc: '+1/秒 自动回复' }
        ];
        
        for (const upgrade of generalUpgrades) {
            const level = this.generalUpgrades[upgrade.key];
            const maxLevel = 5;
            const price = this.getGeneralUpgradePrice(upgrade.key, level);
            const disabled = level >= maxLevel || this.coins < price;
            
            html += `<div class="general-upgrade-card">`;
            html += `<span class="upgrade-icon">${upgrade.icon}</span>`;
            html += `<div class="upgrade-info">`;
            html += `<h4>${upgrade.name}</h4>`;
            html += `<p>${upgrade.desc}</p>`;
            html += `<p class="upgrade-level">等级: ${level}/${maxLevel}</p>`;
            html += `</div>`;
            html += `<button class="upgrade-btn ${disabled ? 'disabled' : ''}" 
                    onclick="shop.upgradeGeneral('${upgrade.key}'); shop.renderShop();">
                ${level >= maxLevel ? '已满级' : `${price}💰`}
            </button>`;
            html += '</div>';
        }
        
        html += '</div></div>';
        
        // 继续按钮
        html += '<div class="shop-footer">';
        html += `<button class="start-wave-btn" onclick="shop.closeShop(); game.startNextWave();">
            ▶️ 开始第 ${gameState.wave + 1} 波
        </button>`;
        html += '</div>';
        
        shopContent.innerHTML = html;
    }
    
    // 购买武器
    buyWeapon(weaponKey) {
        if (!weapons || !weapons.weapons[weaponKey]) return false;
        if (weapons.isUnlocked(weaponKey)) return false;
        
        const weapon = CONFIG.WEAPONS[weaponKey];
        const price = weapon.price || 200;
        
        if (!this.spendCoins(price)) return false;
        
        weapons.unlockWeapon(weaponKey);
        
        if (audio) audio.playUpgrade();
        return true;
    }
    
    // 重置商店(新游戏)
    reset() {
        this.coins = 0;
        this.generalUpgrades = {
            maxHealth: 0,
            speed: 0,
            healthRegen: 0
        };
        
        for (const weaponKey of Object.keys(CONFIG.WEAPONS)) {
            this.weaponLevels[weaponKey] = {
                damage: 0,
                fireRate: 0,
                speed: 0
            };
        }
        
        // 重置武器解锁状态(只保留初始手枪和武士刀)
        if (weapons && weapons.unlockedWeapons) {
            weapons.unlockedWeapons.clear();
            weapons.unlockedWeapons.add('pistol');
            weapons.unlockedWeapons.add('sword');
        }
        
        // 重置武器属性
        for (const [weaponKey, weapon] of Object.entries(weapons.weapons)) {
            if (weapon.baseDamage) weapon.damage = weapon.baseDamage;
            if (weapon.baseFireRate) weapon.fireRate = weapon.baseFireRate;
            if (weapon.baseBulletSpeed) weapon.bulletSpeed = weapon.baseBulletSpeed;
        }
    }
}

const shop = new ShopSystem();


// waveManager.js
// 波次管理器
class WaveManager {
    constructor() {
        this.currentWave = 0;
        this.waveActive = false;
        this.waveBreak = false;
        this.breakTime = 0;
        this.enemiesRemaining = 0;
        this.isBossWave = false;
    }
    
    init() {
        this.currentWave = 0;
        this.waveActive = false;
        this.waveBreak = false;
        return this;
    }
    
    startWave(waveNumber) {
        this.currentWave = waveNumber;
        this.waveActive = true;
        this.waveBreak = false;
        
        gameState.wave = waveNumber;
        gameState.waveDamageTaken = 0; // 重置本波伤害记录
        gameState.nextWave();
        
        // 判断是否是Boss波
        this.isBossWave = waveNumber % CONFIG.BOSS_WAVE_INTERVAL === 0;
        
        if (this.isBossWave) {
            this.spawnBossWave(waveNumber);
        } else {
            // 生成普通敌人
            enemies.spawnWave(waveNumber);
        }
        
        // 播放波次开始音效
        if (audio) audio.playWaveStart();
        
        console.log(`Wave ${waveNumber} started! ${this.isBossWave ? '[BOSS WAVE]' : ''}`);
    }
    
    spawnBossWave(waveNumber) {
        // Boss波:先清理小怪,再生成Boss
        // 选择Boss类型
        const bossTypes = Object.keys(CONFIG.BOSSES);
        const bossIndex = Math.floor((waveNumber / CONFIG.BOSS_WAVE_INTERVAL - 1) % bossTypes.length);
        const bossType = bossTypes[bossIndex];
        
        // 生成一些小怪作为先锋
        const minionCount = 3 + Math.floor(waveNumber / 10);
        for (let i = 0; i < minionCount; i++) {
            const angle = (Math.PI * 2 / minionCount) * i;
            const distance = 10 + Math.random() * 5;
            const pos = new THREE.Vector3(
                Math.cos(angle) * distance,
                0,
                Math.sin(angle) * distance
            );
            enemies.spawnEnemy('grunt', pos);
        }
        
        // 延迟生成Boss
        setTimeout(() => {
            if (bossManager) {
                const bossPos = new THREE.Vector3(0, 0, -15);
                bossManager.spawnBoss(bossType, bossPos);
            }
        }, 2000);
    }
    
    onWaveComplete() {
        if (!this.waveActive) return;
        
        this.waveActive = false;
        this.waveBreak = true;
        
        // 检查完美波次成就
        if (gameState.waveDamageTaken === 0 && gameState.wave > 1) {
            if (achievements) {
                achievements.unlock('perfect_wave');
            }
        }
        
        // 检查波次成就
        if (achievements) {
            achievements.checkAchievements({
                wave: this.currentWave
            });
        }
        
        // 波次间回复
        if (player) {
            player.heal(25);
        }
        
        // 给予波次完成奖励金币
        if (shop) {
            const coinReward = 30 + this.currentWave * 10;
            shop.addCoins(coinReward);
            hud.showFloatingText(`+${coinReward} 💰`, 0, 2, 0xffff00);
        }
        
        // 打开商店(如果有商店系统)
        if (shop && shop.openShop) {
            shop.openShop();
            if (input && input.isMobile) {
                input.releasePointerLock();
            }
        } else {
            this.breakTime = CONFIG.WAVE_BREAK_TIME;
        }
        
        // 波次完成提示
        if (hud) {
            hud.showWaveAnnouncement(`波次 ${this.currentWave} 完成!`);
        }
        
        if (audio) audio.playWaveComplete();
        
        console.log(`Wave ${this.currentWave} complete!`);
    }
    
    update(deltaTime) {
        if (this.waveBreak) {
            // 如果商店打开,不自动开始下一波
            const shopOpen = shop && shop.shopOpen;
            if (!shopOpen) {
                this.breakTime -= deltaTime;
                
                if (this.breakTime <= 0) {
                    // 开始下一波
                    this.startWave(this.currentWave + 1);
                }
            }
        }
        
        // 检查波次是否完成
        if (this.waveActive) {
            const enemiesAlive = enemies ? enemies.list.filter(e => !e.dead).length : 0;
            const bossAlive = bossManager && bossManager.activeBoss ? 1 : 0;
            
            if (enemiesAlive === 0 && bossAlive === 0) {
                // 延迟一点再判定完成,给死亡动画时间
                setTimeout(() => {
                    if (this.waveActive) {
                        const stillAlive = enemies ? enemies.list.filter(e => !e.dead).length : 0;
                        const bossStillAlive = bossManager && bossManager.activeBoss ? 1 : 0;
                        if (stillAlive === 0 && bossStillAlive === 0) {
                            this.onWaveComplete();
                        }
                    }
                }, 500);
            }
        }
    }
    
    reset() {
        this.currentWave = 0;
        this.waveActive = false;
        this.waveBreak = false;
        this.breakTime = 0;
        this.isBossWave = false;
    }
}

const waveManager = new WaveManager();


// arena.js
// 竞技场/场景
class Arena {
    constructor() {
        this.size = CONFIG.ARENA_SIZE;
        this.mesh = null;
    }
    
    create() {
        const scene = renderer.scene;
        const size = this.size;
        
        // 地面
        const floorGeometry = new THREE.PlaneGeometry(size * 2, size * 2, 50, 50);
        const floorMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x1a1a2e,
            roughness: 0.8,
            metalness: 0.2
        });
        const floor = new THREE.Mesh(floorGeometry, floorMaterial);
        floor.rotation.x = -Math.PI / 2;
        floor.receiveShadow = true;
        scene.add(floor);
        
        // 网格线
        const gridHelper = new THREE.GridHelper(size * 2, 40, 0x00ffff, 0x004466);
        gridHelper.position.y = 0.01;
        gridHelper.material.opacity = 0.3;
        gridHelper.material.transparent = true;
        scene.add(gridHelper);
        
        // 边界墙
        const wallHeight = 5;
        const wallMaterial = new THREE.MeshStandardMaterial({
            color: 0x16213e,
            emissive: 0x001122,
            transparent: true,
            opacity: 0.8
        });
        
        // 四面墙
        const walls = [
            { pos: [0, wallHeight/2, -size], size: [size * 2, wallHeight, 0.5] },
            { pos: [0, wallHeight/2, size], size: [size * 2, wallHeight, 0.5] },
            { pos: [-size, wallHeight/2, 0], size: [0.5, wallHeight, size * 2] },
            { pos: [size, wallHeight/2, 0], size: [0.5, wallHeight, size * 2] },
        ];
        
        for (const wall of walls) {
            const wallGeo = new THREE.BoxGeometry(...wall.size);
            const wallMesh = new THREE.Mesh(wallGeo, wallMaterial);
            wallMesh.position.set(...wall.pos);
            scene.add(wallMesh);
        }
        
        // 霓虹装饰柱
        const pillarCount = 8;
        const pillarColors = [0xff00ff, 0x00ffff, 0xffff00, 0xff0088];
        
        for (let i = 0; i < pillarCount; i++) {
            const angle = (i / pillarCount) * Math.PI * 2;
            const radius = size - 1;
            
            const pillarGeo = new THREE.CylinderGeometry(0.3, 0.4, wallHeight, 8);
            const pillarMat = new THREE.MeshStandardMaterial({
                color: pillarColors[i % pillarColors.length],
                emissive: pillarColors[i % pillarColors.length],
                emissiveIntensity: 0.5,
                metalness: 0.8,
                roughness: 0.2
            });
            const pillar = new THREE.Mesh(pillarGeo, pillarMat);
            pillar.position.set(
                Math.cos(angle) * radius,
                wallHeight / 2,
                Math.sin(angle) * radius
            );
            pillar.castShadow = true;
            scene.add(pillar);
            
            // 顶部光球
            const lightSphere = new THREE.Mesh(
                new THREE.SphereGeometry(0.5, 16, 16),
                new THREE.MeshBasicMaterial({ 
                    color: pillarColors[i % pillarColors.length],
                    transparent: true,
                    opacity: 0.8
                })
            );
            lightSphere.position.copy(pillar.position);
            lightSphere.position.y = wallHeight;
            scene.add(lightSphere);
            
            // 点光源
            const pointLight = new THREE.PointLight(
                pillarColors[i % pillarColors.length],
                0.5,
                10
            );
            pointLight.position.copy(lightSphere.position);
            scene.add(pointLight);
        }
        
        // 天空雾效
        scene.fog = new THREE.Fog(0x0a0a1a, size * 0.5, size * 2);
        
        // 添加一些浮空几何体装饰
        this.addFloatingDecorations();
        
        this.mesh = floor;
        return this;
    }
    
    addFloatingDecorations() {
        const scene = renderer.scene;
        const shapes = [];
        
        // 几个浮动的几何体
        for (let i = 0; i < 6; i++) {
            let geometry;
            const type = i % 3;
            
            if (type === 0) {
                geometry = new THREE.TorusGeometry(1, 0.2, 8, 16);
            } else if (type === 1) {
                geometry = new THREE.OctahedronGeometry(0.8);
            } else {
                geometry = new THREE.IcosahedronGeometry(0.7, 0);
            }
            
            const material = new THREE.MeshBasicMaterial({
                color: new THREE.Color().setHSL(i / 6, 0.8, 0.6),
                wireframe: true,
                transparent: true,
                opacity: 0.3
            });
            
            const mesh = new THREE.Mesh(geometry, material);
            const angle = (i / 6) * Math.PI * 2;
            const radius = this.size * 0.6;
            mesh.position.set(
                Math.cos(angle) * radius,
                6 + Math.random() * 4,
                Math.sin(angle) * radius
            );
            
            mesh.userData = {
                floatSpeed: 0.5 + Math.random() * 0.5,
                rotationSpeed: 0.2 + Math.random() * 0.3,
                baseY: mesh.position.y,
                phase: Math.random() * Math.PI * 2
            };
            
            scene.add(mesh);
            shapes.push(mesh);
        }
        
        this.floatingShapes = shapes;
        
        // 动画这些浮动形状(在effects中更新)
        const originalUpdate = effects.update.bind(effects);
        effects.update = (dt) => {
            originalUpdate(dt);
            
            const time = performance.now() * 0.001;
            for (const shape of shapes) {
                if (!shape.parent) continue;
                shape.position.y = shape.userData.baseY + 
                    Math.sin(time * shape.userData.floatSpeed + shape.userData.phase) * 0.5;
                shape.rotation.x += shape.userData.rotationSpeed * dt;
                shape.rotation.y += shape.userData.rotationSpeed * dt * 0.7;
            }
        };
    }
    
    clear() {
        // 清空竞技场(保留相机和光照)
        // 这个方法根据需要实现
    }
}

const arena = new Arena();


// player.js
// 玩家系统
class Player {
    constructor() {
        this.mesh = null;
        this.health = 100;
        this.maxHealth = 100;
        this.speed = CONFIG.PLAYER_SPEED;
        this.velocity = new THREE.Vector3();
        this.onGround = false;
        this.isSprinting = false;
        this.isDodging = false;
        this.dodgeCooldown = 0;
        this.dodgeDirection = new THREE.Vector3();
        this.dodgeTime = 0;
        
        // 角色属性加成
        this.character = null;
        this.healthBonus = 0;
        this.speedBonus = 0;
        this.damageBonus = 0;
        
        // 技能
        this.specialCooldown = 0;
        this.specialActive = false;
        this.specialDuration = 0;
        
        // 受击
        this.hitFlashTime = 0;
        
        // 碰撞
        this.collisionRadius = 0.4;
        this.height = 1.6;
    }
    
    init(characterKey = 'soldier') {
        this.character = characterKey;
        const charData = CONFIG.CHARACTERS[characterKey];
        
        if (charData) {
            this.healthBonus = charData.healthBonus;
            this.speedBonus = charData.speedBonus;
            this.damageBonus = charData.damageBonus;
        }
        
        this.maxHealth = CONFIG.PLAYER_MAX_HEALTH + this.healthBonus;
        this.health = this.maxHealth;
        this.speed = CONFIG.PLAYER_SPEED + this.speedBonus;
        
        // 创建玩家相机容器(相机就是玩家视角)
        this.mesh = new THREE.Object3D();
        this.mesh.position.set(0, this.height, 0);
        renderer.scene.add(this.mesh);
        
        // 将相机附加到玩家
        renderer.camera.position.set(0, 0, 0);
        this.mesh.add(renderer.camera);
        
        // 创建武器视模型
        this.createViewModel();
        
        return this;
    }
    
    createViewModel() {
        // 创建武器视模型组
        this.viewModel = new THREE.Group();
        this.viewModel.position.set(0.3, -0.25, -0.5);
        renderer.camera.add(this.viewModel);
        
        // 默认武器
        this.updateViewModel('pistol');
    }
    
    updateViewModel(weaponKey) {
        // 清除旧武器
        while (this.viewModel.children.length > 0) {
            this.viewModel.remove(this.viewModel.children[0]);
        }
        
        const weaponConfig = CONFIG.WEAPONS[weaponKey];
        if (!weaponConfig) return;
        
        const color = weaponConfig.color;
        
        if (weaponKey === 'pistol') {
            // 手枪模型
            const body = new THREE.Mesh(
                new THREE.BoxGeometry(0.08, 0.12, 0.25),
                new THREE.MeshStandardMaterial({ color: color, emissive: color, emissiveIntensity: 0.3, metalness: 0.8, roughness: 0.2 })
            );
            this.viewModel.add(body);
            
            const barrel = new THREE.Mesh(
                new THREE.CylinderGeometry(0.025, 0.025, 0.15, 8),
                new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.9, roughness: 0.1 })
            );
            barrel.rotation.x = -Math.PI / 2;
            barrel.position.z = -0.15;
            this.viewModel.add(barrel);
            
            const grip = new THREE.Mesh(
                new THREE.BoxGeometry(0.06, 0.15, 0.06),
                new THREE.MeshStandardMaterial({ color: 0x222222 })
            );
            grip.position.y = -0.1;
            grip.position.z = 0.05;
            this.viewModel.add(grip);
            
        } else if (weaponKey === 'shotgun') {
            // 霰弹枪
            const body = new THREE.Mesh(
                new THREE.BoxGeometry(0.1, 0.12, 0.4),
                new THREE.MeshStandardMaterial({ color: color, emissive: color, emissiveIntensity: 0.2, metalness: 0.7, roughness: 0.3 })
            );
            this.viewModel.add(body);
            
            // 双管
            for (let i = -1; i <= 1; i += 2) {
                const barrel = new THREE.Mesh(
                    new THREE.CylinderGeometry(0.02, 0.02, 0.35, 8),
                    new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.9 })
                );
                barrel.rotation.x = -Math.PI / 2;
                barrel.position.set(i * 0.035, 0, -0.2);
                this.viewModel.add(barrel);
            }
            
        } else if (weaponKey === 'laser') {
            // 激光枪
            const body = new THREE.Mesh(
                new THREE.BoxGeometry(0.09, 0.15, 0.5),
                new THREE.MeshStandardMaterial({ color: 0x222222, metalness: 0.8, roughness: 0.2 })
            );
            this.viewModel.add(body);
            
            const barrel = new THREE.Mesh(
                new THREE.CylinderGeometry(0.04, 0.03, 0.3, 8),
                new THREE.MeshStandardMaterial({ color: color, emissive: color, emissiveIntensity: 0.5, transparent: true, opacity: 0.8 })
            );
            barrel.rotation.x = -Math.PI / 2;
            barrel.position.z = -0.3;
            this.viewModel.add(barrel);
            
            // 发光环
            for (let i = 0; i < 3; i++) {
                const ring = new THREE.Mesh(
                    new THREE.TorusGeometry(0.05, 0.01, 8, 16),
                    new THREE.MeshBasicMaterial({ color: color })
                );
                ring.position.z = -0.15 + i * 0.1;
                this.viewModel.add(ring);
            }
            
        } else if (weaponKey === 'smg') {
            // 霓虹冲锋枪
            const body = new THREE.Mesh(
                new THREE.BoxGeometry(0.06, 0.1, 0.35),
                new THREE.MeshStandardMaterial({ color: 0x222222, metalness: 0.8, roughness: 0.2 })
            );
            this.viewModel.add(body);
            
            const barrel = new THREE.Mesh(
                new THREE.CylinderGeometry(0.015, 0.02, 0.2, 6),
                new THREE.MeshStandardMaterial({ color: 0x333333, metalness: 0.9 })
            );
            barrel.rotation.x = -Math.PI / 2;
            barrel.position.z = -0.25;
            this.viewModel.add(barrel);
            
            // 霓虹发光条
            const glow = new THREE.Mesh(
                new THREE.BoxGeometry(0.02, 0.02, 0.3),
                new THREE.MeshBasicMaterial({ color: color })
            );
            glow.position.set(0, 0.04, 0);
            this.viewModel.add(glow);
            
            // 弹夹
            const mag = new THREE.Mesh(
                new THREE.BoxGeometry(0.04, 0.15, 0.03),
                new THREE.MeshStandardMaterial({ color: 0x1a1a1a })
            );
            mag.position.set(0, -0.08, 0.05);
            this.viewModel.add(mag);
            
        } else if (weaponKey === 'plasma') {
            // 等离子步枪
            const body = new THREE.Mesh(
                new THREE.BoxGeometry(0.08, 0.12, 0.45),
                new THREE.MeshStandardMaterial({ color: 0x1a1a2e, metalness: 0.7, roughness: 0.3 })
            );
            this.viewModel.add(body);
            
            // 等离子发射管
            const barrel = new THREE.Mesh(
                new THREE.CylinderGeometry(0.03, 0.025, 0.25, 8),
                new THREE.MeshStandardMaterial({ color: color, emissive: color, emissiveIntensity: 0.6, transparent: true, opacity: 0.7 })
            );
            barrel.rotation.x = -Math.PI / 2;
            barrel.position.z = -0.3;
            this.viewModel.add(barrel);
            
            // 能量罐
            const canister = new THREE.Mesh(
                new THREE.CylinderGeometry(0.03, 0.03, 0.08, 8),
                new THREE.MeshBasicMaterial({ color: color, transparent: true, opacity: 0.8 })
            );
            canister.position.set(0.05, -0.02, 0.1);
            canister.rotation.z = Math.PI / 6;
            this.viewModel.add(canister);
            
            // 散热片
            for (let i = 0; i < 3; i++) {
                const fin = new THREE.Mesh(
                    new THREE.BoxGeometry(0.07, 0.01, 0.02),
                    new THREE.MeshStandardMaterial({ color: 0x444444 })
                );
                fin.position.set(0, 0.05, -0.05 + i * 0.05);
                this.viewModel.add(fin);
            }
            
        } else if (weaponKey === 'rocket') {
            // 爆裂火箭筒
            const body = new THREE.Mesh(
                new THREE.CylinderGeometry(0.05, 0.06, 0.5, 8),
                new THREE.MeshStandardMaterial({ color: 0x2a2a2a, metalness: 0.6, roughness: 0.4 })
            );
            body.rotation.x = -Math.PI / 2;
            this.viewModel.add(body);
            
            // 瞄准镜
            const scope = new THREE.Mesh(
                new THREE.CylinderGeometry(0.015, 0.015, 0.08, 6),
                new THREE.MeshStandardMaterial({ color: 0x333333 })
            );
            scope.rotation.z = Math.PI / 2;
            scope.position.set(0, 0.05, 0.05);
            this.viewModel.add(scope);
            
            // 火箭弹预览
            const rocket = new THREE.Mesh(
                new THREE.CylinderGeometry(0.02, 0.015, 0.15, 6),
                new THREE.MeshStandardMaterial({ color: color, emissive: color, emissiveIntensity: 0.3 })
            );
            rocket.rotation.x = -Math.PI / 2;
            rocket.position.z = -0.2;
            this.viewModel.add(rocket);
            
            // 握把
            const grip = new THREE.Mesh(
                new THREE.BoxGeometry(0.04, 0.12, 0.04),
                new THREE.MeshStandardMaterial({ color: 0x1a1a1a })
            );
            grip.position.set(0, -0.08, 0.1);
            this.viewModel.add(grip);
            
        } else if (weaponKey === 'sword') {
            // 武士刀
            const blade = new THREE.Mesh(
                new THREE.BoxGeometry(0.03, 0.8, 0.01),
                new THREE.MeshStandardMaterial({ color: color, emissive: color, emissiveIntensity: 0.4, metalness: 0.9 })
            );
            blade.position.set(0, 0.3, -0.3);
            blade.rotation.x = -0.3;
            this.viewModel.add(blade);
            
            const hilt = new THREE.Mesh(
                new THREE.BoxGeometry(0.08, 0.1, 0.03),
                new THREE.MeshStandardMaterial({ color: 0x333333 })
            );
            hilt.position.set(0, -0.1, -0.3);
            this.viewModel.add(hilt);
        }
    }
    
    update(deltaTime) {
        if (!gameState.isPlaying()) return;
        
        // 冷却更新
        if (this.dodgeCooldown > 0) this.dodgeCooldown -= deltaTime;
        if (this.specialCooldown > 0) this.specialCooldown -= deltaTime;
        if (this.hitFlashTime > 0) this.hitFlashTime -= deltaTime;
        
        // 特殊技能持续时间
        if (this.specialActive) {
            this.specialDuration -= deltaTime;
            if (this.specialDuration <= 0) {
                this.endSpecial();
            }
        }
        
        // 生命回复
        if (this.regenRate && this.regenRate > 0 && this.health < this.maxHealth) {
            this.health = Math.min(this.maxHealth, this.health + this.regenRate * deltaTime);
            // 更新HUD(降低频率)
            if (Math.random() < 0.1) {
                // 偶尔触发HUD更新,避免太频繁
            }
        }
        
        // 翻滚
        if (this.isDodging) {
            this.dodgeTime -= deltaTime;
            if (this.dodgeTime <= 0) {
                this.isDodging = false;
            }
        }
        
        // 移动
        this.handleMovement(deltaTime);
        
        // 重力
        this.applyGravity(deltaTime);
        
        // 视角控制
        this.handleLook();
        
        // 武器切换
        this.handleWeaponSwitch();
        
        // 近战攻击
        if ((input.isKeyPressed('f') || input.mouseButtons.right) && !this.isAttacking) {
            this.meleeAttack();
        }
        
        // 特殊技能
        if (input.isKeyPressed('e') && this.specialCooldown <= 0) {
            this.activateSpecial();
        }
        
        // 武器后坐力恢复
        if (this.recoilAmount > 0) {
            this.recoilAmount -= deltaTime * 5;
            this.recoilAmount = Math.max(0, this.recoilAmount);
            this.viewModel.position.z = -0.5 + this.recoilAmount * 0.1;
            this.viewModel.rotation.x = this.recoilAmount * 0.5;
        }
        
        // 检查死亡
        if (this.health <= 0) {
            this.die();
        }
    }
    
    handleMovement(deltaTime) {
        const moveSpeed = this.isSprinting ? CONFIG.PLAYER_SPRINT_SPEED + this.speedBonus : this.speed;
        
        // 获取输入
        const moveForward = input.getAxis(false); // W/S
        const moveStrafe = input.getAxis(true);   // A/D
        
        // 计算移动方向(基于相机朝向)
        const direction = new THREE.Vector3();
        const cameraDirection = new THREE.Vector3();
        renderer.camera.getWorldDirection(cameraDirection);
        cameraDirection.y = 0;
        cameraDirection.normalize();
        
        const right = new THREE.Vector3();
        right.crossVectors(cameraDirection, new THREE.Vector3(0, 1, 0)).normalize();
        
        direction.addScaledVector(cameraDirection, moveForward);
        direction.addScaledVector(right, moveStrafe);
        
        if (direction.length() > 0) {
            direction.normalize();
        }
        
        // 翻滚
        if (this.isDodging) {
            direction.copy(this.dodgeDirection);
            const dodgeSpeed = 15;
            this.mesh.position.x += direction.x * dodgeSpeed * deltaTime;
            this.mesh.position.z += direction.z * dodgeSpeed * deltaTime;
        } else {
            // 正常移动
            this.mesh.position.x += direction.x * moveSpeed * deltaTime;
            this.mesh.position.z += direction.z * moveSpeed * deltaTime;
        }
        
        // 边界限制
        const boundary = CONFIG.ARENA_SIZE - 2;
        this.mesh.position.x = Math.max(-boundary, Math.min(boundary, this.mesh.position.x));
        this.mesh.position.z = Math.max(-boundary, Math.min(boundary, this.mesh.position.z));
        
        // 冲刺检测
        this.isSprinting = input.isKeyPressed('shift') && this.onGround && moveForward > 0;
        
        // 翻滚
        if (input.isKeyPressed('control') && this.dodgeCooldown <= 0 && this.onGround) {
            this.dodge(direction);
        }
        
        // 跳跃
        if (input.isKeyPressed(' ') && this.onGround) {
            this.velocity.y = CONFIG.PLAYER_JUMP_FORCE;
            this.onGround = false;
            if (audio) audio.playJump();
        }
    }
    
    dodge(direction) {
        if (direction.length() === 0) {
            // 没有方向输入就向后翻滚
            const cameraDir = new THREE.Vector3();
            renderer.camera.getWorldDirection(cameraDir);
            cameraDir.y = 0;
            cameraDir.normalize();
            this.dodgeDirection.copy(cameraDir).negate();
        } else {
            this.dodgeDirection.copy(direction).normalize();
        }
        
        this.isDodging = true;
        this.dodgeTime = 0.3;
        this.dodgeCooldown = 1.5;
        this.isInvincible = true;
        
        setTimeout(() => {
            this.isInvincible = false;
        }, 300);
        
        if (audio) audio.playDodge();
    }
    
    applyGravity(deltaTime) {
        this.velocity.y -= CONFIG.PLAYER_GRAVITY * deltaTime;
        this.mesh.position.y += this.velocity.y * deltaTime;
        
        // 地面检测
        if (this.mesh.position.y <= this.height) {
            this.mesh.position.y = this.height;
            this.velocity.y = 0;
            this.onGround = true;
        }
    }
    
    handleLook() {
        if (!input.mouse.locked && !input.isMobile) return;
        
        // 鼠标/触摸视角
        if (Math.abs(input.mouse.dx) > 0 || Math.abs(input.mouse.dy) > 0) {
            const sensitivity = input.isMobile ? CONFIG.MOBILE_SENSITIVITY : CONFIG.PLAYER_MOUSE_SENSITIVITY;
            
            // 水平旋转(绕Y轴)
            this.mesh.rotation.y -= input.mouse.dx * sensitivity;
            
            // 垂直旋转(绕X轴,限制范围)
            renderer.camera.rotation.x -= input.mouse.dy * sensitivity;
            renderer.camera.rotation.x = Math.max(-Math.PI / 2 + 0.1, Math.min(Math.PI / 2 - 0.1, renderer.camera.rotation.x));
        }
    }
    
    handleWeaponSwitch() {
        // 武器列表(按切换顺序)
        const weaponList = ['pistol', 'shotgun', 'smg', 'plasma', 'laser', 'rocket', 'sword'];
        
        // 数字键切换
        for (let i = 0; i < weaponList.length; i++) {
            const key = (i + 1).toString();
            if (input.isKeyPressed(key) && weapons.isUnlocked(weaponList[i])) {
                weapons.switchWeapon(weaponList[i]);
                this.updateViewModel(weaponList[i]);
                hud.updateWeapon(CONFIG.WEAPONS[weaponList[i]].name);
                break;
            }
        }
        
        // Q/E快速切换下一把/上一把已解锁武器
        if (input.isKeyPressed('q') || input.isKeyPressed('e')) {
            const currentIndex = weaponList.indexOf(weapons.currentWeapon);
            const direction = input.isKeyPressed('e') ? 1 : -1;
            
            let nextIndex = (currentIndex + direction + weaponList.length) % weaponList.length;
            let attempts = 0;
            
            while (!weapons.isUnlocked(weaponList[nextIndex]) && attempts < weaponList.length) {
                nextIndex = (nextIndex + direction + weaponList.length) % weaponList.length;
                attempts++;
            }
            
            if (weapons.isUnlocked(weaponList[nextIndex])) {
                weapons.switchWeapon(weaponList[nextIndex]);
                this.updateViewModel(weaponList[nextIndex]);
                hud.updateWeapon(CONFIG.WEAPONS[weaponList[nextIndex]].name);
            }
        }
    }
    
    takeDamage(amount) {
        if (this.isInvincible) return false;
        
        // 护盾先吸收伤害
        if (this.shield && this.shield > 0) {
            const shieldAbsorb = Math.min(this.shield, amount);
            this.shield -= shieldAbsorb;
            amount -= shieldAbsorb;
            
            if (amount <= 0) {
                // 护盾完全吸收了伤害
                if (effects) effects.shake(0.1, 0.05);
                return true;
            }
        }
        
        this.health -= amount;
        this.health = Math.max(0, this.health);
        
        // 记录本波伤害(用于完美波次成就)
        if (gameState && gameState.waveDamageTaken !== undefined) {
            gameState.waveDamageTaken += amount;
        }
        
        hud.updateHealth(this.health, this.maxHealth);
        hud.showDamage(0.5);
        
        if (audio) audio.playHurt();
        
        // 屏幕震动
        if (effects) {
            effects.shake(0.3, 0.1);
        }
        
        // 检查死亡
        if (this.health <= 0) {
            this.die();
        }
        
        return true;
    }
    
    heal(amount) {
        this.health = Math.min(this.maxHealth, this.health + amount);
        hud.updateHealth(this.health, this.maxHealth);
    }
    
    meleeAttack() {
        this.isAttacking = true;
        this.recoilAmount = 0.3;
        
        // 挥刀动画
        const originalRot = this.viewModel.rotation.z;
        this.viewModel.rotation.z = -0.5;
        
        setTimeout(() => {
            this.viewModel.rotation.z = 0.5;
            setTimeout(() => {
                this.viewModel.rotation.z = originalRot;
            }, 100);
        }, 50);
        
        // 检测命中
        const range = CONFIG.WEAPONS.sword.range;
        const damage = CONFIG.WEAPONS.sword.damage * (1 + this.damageBonus);
        
        if (enemies) {
            const cameraDir = new THREE.Vector3();
            renderer.camera.getWorldDirection(cameraDir);
            
            for (const enemy of enemies.list) {
                if (enemy.dead) continue;
                
                const toEnemy = new THREE.Vector3();
                toEnemy.subVectors(enemy.mesh.position, this.mesh.position);
                const distance = toEnemy.length();
                toEnemy.y = 0;
                toEnemy.normalize();
                
                const dot = cameraDir.dot(toEnemy);
                
                if (distance < range && dot > 0.7) {
                    enemy.takeDamage(damage, cameraDir);
                    
                    // 命中特效
                    if (effects) {
                        effects.createHitEffect(enemy.mesh.position.clone(), CONFIG.WEAPONS.sword.color);
                        effects.shake(0.2, 0.05);
                        effects.slowMotion(0.05, 0.1);
                    }
                    
                    if (audio) audio.playHit();
                }
            }
        }
        
        setTimeout(() => {
            this.isAttacking = false;
        }, CONFIG.WEAPONS.sword.fireRate);
    }
    
    activateSpecial() {
        const charData = CONFIG.CHARACTERS[this.character];
        if (!charData) return;
        
        this.specialActive = true;
        this.specialCooldown = 30; // 30秒冷却
        
        // 根据角色应用不同效果
        switch (this.character) {
            case 'soldier':
                // 狂暴:伤害翻倍
                this.specialDuration = 8;
                this.damageBonus += 1.0; // 额外+100%
                if (effects) effects.showScreenGlow(0xff0000, 0.3);
                break;
                
            case 'ninja':
                // 疾风步:加速+无敌
                this.specialDuration = 5;
                this.speedBonus += 10;
                this.isInvincible = true;
                if (effects) effects.showScreenGlow(0x8844ff, 0.3);
                break;
                
            case 'engineer':
                // 召唤炮塔
                this.specialDuration = 15;
                this.summonTurret();
                break;
                
            case 'medic':
                // 治疗脉冲
                this.specialDuration = 0;
                this.heal(50);
                if (effects) effects.showScreenGlow(0x44ff88, 0.5);
                if (audio) audio.playHeal();
                break;
        }
        
        if (audio) audio.playSpecial();
    }
    
    endSpecial() {
        this.specialActive = false;
        
        switch (this.character) {
            case 'soldier':
                this.damageBonus = CONFIG.CHARACTERS.soldier.damageBonus;
                break;
            case 'ninja':
                this.speedBonus = CONFIG.CHARACTERS.ninja.speedBonus;
                this.isInvincible = false;
                break;
        }
        
        if (effects) effects.hideScreenGlow();
    }
    
    summonTurret() {
        // 召唤一个自动攻击的炮塔
        const turret = new THREE.Group();
        
        const base = new THREE.Mesh(
            new THREE.CylinderGeometry(0.5, 0.6, 0.3, 8),
            new THREE.MeshStandardMaterial({ color: 0xffaa00, metalness: 0.7 })
        );
        turret.add(base);
        
        const gun = new THREE.Mesh(
            new THREE.BoxGeometry(0.15, 0.15, 0.8),
            new THREE.MeshStandardMaterial({ color: 0x666666, metalness: 0.8 })
        );
        gun.position.y = 0.3;
        turret.add(gun);
        
        // 放在玩家旁边
        const spawnPos = this.mesh.position.clone();
        spawnPos.x += 1;
        spawnPos.y = 0.15;
        turret.position.copy(spawnPos);
        
        renderer.scene.add(turret);
        
        // 炮塔AI - 简化版
        this.turret = {
            mesh: turret,
            damage: 20,
            fireRate: 500,
            lastFire: 0,
            range: 20,
            lifetime: 15 // 15秒后消失
        };
        
        // 添加到游戏更新
        if (!game.turrets) game.turrets = [];
        game.turrets.push(this.turret);
    }
    
    die() {
        if (gameState.isGameOver()) return;
        gameState.setState('gameover');
        if (audio) audio.playGameOver();
    }
    
    reset() {
        this.mesh.position.set(0, this.height, 0);
        this.mesh.rotation.set(0, 0, 0);
        renderer.camera.rotation.x = 0;
        this.velocity.set(0, 0, 0);
        this.health = this.maxHealth;
        this.dodgeCooldown = 0;
        this.specialCooldown = 0;
        this.isDodging = false;
        this.specialActive = false;
        
        // 重置角色属性
        const charData = CONFIG.CHARACTERS[this.character];
        if (charData) {
            this.healthBonus = charData.healthBonus;
            this.speedBonus = charData.speedBonus;
            this.damageBonus = charData.damageBonus;
        }
        
        hud.updateHealth(this.health, this.maxHealth);
    }
}

const player = new Player();


// mobile.js
// 移动端适配
class MobileControls {
    constructor() {
        this.isMobile = false;
        this.active = false;
        
        // 虚拟摇杆
        this.joystick = {
            active: false,
            startX: 0,
            startY: 0,
            currentX: 0,
            currentY: 0,
            deltaX: 0,
            deltaY: 0,
            maxDistance: 50
        };
        
        // 触摸视角
        this.touchLook = {
            active: false,
            lastX: 0,
            lastY: 0,
            sensitivity: 0.005
        };
        
        // 按钮状态
        this.buttons = {
            fire: false,
            jump: false,
            melee: false,
            weapon1: false,
            weapon2: false,
            weapon3: false
        };
        
        this.isFiring = false;
    }
    
    init() {
        this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
            || ('ontouchstart' in window)
            || (navigator.maxTouchPoints > 0);
        
        if (this.isMobile) {
            this.active = true;
            this.createControls();
            this.setupEventListeners();
            console.log('Mobile controls initialized');
        }
        
        return this;
    }
    
    createControls() {
        // 左侧虚拟摇杆容器
        const joystickContainer = document.createElement('div');
        joystickContainer.id = 'joystick-container';
        joystickContainer.style.cssText = `
            position: fixed;
            left: 30px;
            bottom: 30px;
            width: 120px;
            height: 120px;
            background: rgba(0, 0, 0, 0.3);
            border: 2px solid rgba(0, 255, 255, 0.5);
            border-radius: 50%;
            z-index: 200;
            touch-action: none;
        `;
        
        const joystickKnob = document.createElement('div');
        joystickKnob.id = 'joystick-knob';
        joystickKnob.style.cssText = `
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 50px;
            height: 50px;
            background: rgba(0, 255, 255, 0.6);
            border-radius: 50%;
            box-shadow: 0 0 15px rgba(0, 255, 255, 0.8);
        `;
        joystickContainer.appendChild(joystickKnob);
        document.body.appendChild(joystickContainer);
        
        // 右侧触摸视角区域
        const touchZone = document.createElement('div');
        touchZone.id = 'touch-look-zone';
        touchZone.style.cssText = `
            position: fixed;
            right: 0;
            top: 0;
            width: 50%;
            height: 100%;
            z-index: 150;
            touch-action: none;
        `;
        document.body.appendChild(touchZone);
        
        // 开火按钮
        const fireBtn = document.createElement('button');
        fireBtn.id = 'fire-btn';
        fireBtn.innerHTML = '🔫';
        fireBtn.style.cssText = `
            position: fixed;
            right: 30px;
            bottom: 80px;
            width: 70px;
            height: 70px;
            background: rgba(255, 0, 100, 0.6);
            border: 2px solid rgba(255, 0, 100, 0.8);
            border-radius: 50%;
            font-size: 28px;
            z-index: 200;
            touch-action: none;
            display: flex;
            align-items: center;
            justify-content: center;
        `;
        document.body.appendChild(fireBtn);
        
        // 跳跃按钮
        const jumpBtn = document.createElement('button');
        jumpBtn.id = 'jump-btn';
        jumpBtn.innerHTML = '⬆️';
        jumpBtn.style.cssText = `
            position: fixed;
            right: 120px;
            bottom: 30px;
            width: 60px;
            height: 60px;
            background: rgba(0, 255, 100, 0.6);
            border: 2px solid rgba(0, 255, 100, 0.8);
            border-radius: 50%;
            font-size: 24px;
            z-index: 200;
            touch-action: none;
            display: flex;
            align-items: center;
            justify-content: center;
        `;
        document.body.appendChild(jumpBtn);
        
        // 武器切换按钮
        const weaponButtons = ['1', '2', '3', '4'];
        const weaponIcons = ['🔫', '💥', '⚡', '⚔️'];
        weaponButtons.forEach((num, i) => {
            const btn = document.createElement('button');
            btn.id = `weapon-${num}-btn`;
            btn.innerHTML = weaponIcons[i];
            btn.style.cssText = `
                position: fixed;
                right: ${30 + i * 55}px;
                bottom: 170px;
                width: 45px;
                height: 45px;
                background: rgba(255, 255, 0, 0.5);
                border: 2px solid rgba(255, 255, 0, 0.7);
                border-radius: 8px;
                font-size: 18px;
                z-index: 200;
                touch-action: none;
                display: flex;
                align-items: center;
                justify-content: center;
            `;
            btn.dataset.weapon = ['pistol', 'shotgun', 'laser', 'sword'][i];
            document.body.appendChild(btn);
        });
    }
    
    setupEventListeners() {
        const joystickContainer = document.getElementById('joystick-container');
        const joystickKnob = document.getElementById('joystick-knob');
        const touchZone = document.getElementById('touch-look-zone');
        const fireBtn = document.getElementById('fire-btn');
        const jumpBtn = document.getElementById('jump-btn');
        
        // 虚拟摇杆
        joystickContainer.addEventListener('touchstart', (e) => {
            e.preventDefault();
            const touch = e.touches[0];
            const rect = joystickContainer.getBoundingClientRect();
            this.joystick.active = true;
            this.joystick.startX = rect.left + rect.width / 2;
            this.joystick.startY = rect.top + rect.height / 2;
            this.updateJoystick(touch.clientX, touch.clientY, joystickKnob);
        }, { passive: false });
        
        joystickContainer.addEventListener('touchmove', (e) => {
            e.preventDefault();
            if (this.joystick.active) {
                const touch = e.touches[0];
                this.updateJoystick(touch.clientX, touch.clientY, joystickKnob);
            }
        }, { passive: false });
        
        const endJoystick = () => {
            this.joystick.active = false;
            this.joystick.deltaX = 0;
            this.joystick.deltaY = 0;
            if (joystickKnob) {
                joystickKnob.style.transform = 'translate(-50%, -50%)';
            }
        };
        
        joystickContainer.addEventListener('touchend', endJoystick);
        joystickContainer.addEventListener('touchcancel', endJoystick);
        
        // 触摸视角
        touchZone.addEventListener('touchstart', (e) => {
            e.preventDefault();
            if (e.touches.length > 0) {
                this.touchLook.active = true;
                this.touchLook.lastX = e.touches[0].clientX;
                this.touchLook.lastY = e.touches[0].clientY;
            }
        }, { passive: false });
        
        touchZone.addEventListener('touchmove', (e) => {
            e.preventDefault();
            if (this.touchLook.active && gameState.isPlaying()) {
                const touch = e.touches[0];
                const dx = touch.clientX - this.touchLook.lastX;
                const dy = touch.clientY - this.touchLook.lastY;
                
                // 更新相机旋转
                if (player && player.mesh) {
                    player.mesh.rotation.y -= dx * this.touchLook.sensitivity;
                    renderer.camera.rotation.x -= dy * this.touchLook.sensitivity;
                    renderer.camera.rotation.x = Math.max(-Math.PI / 2 + 0.1, Math.min(Math.PI / 2 - 0.1, renderer.camera.rotation.x));
                }
                
                this.touchLook.lastX = touch.clientX;
                this.touchLook.lastY = touch.clientY;
            }
        }, { passive: false });
        
        const endTouchLook = () => {
            this.touchLook.active = false;
        };
        
        touchZone.addEventListener('touchend', endTouchLook);
        touchZone.addEventListener('touchcancel', endTouchLook);
        
        // 开火按钮
        fireBtn.addEventListener('touchstart', (e) => {
            e.preventDefault();
            this.isFiring = true;
            this.buttons.fire = true;
        }, { passive: false });
        
        fireBtn.addEventListener('touchend', (e) => {
            e.preventDefault();
            this.isFiring = false;
            this.buttons.fire = false;
        });
        
        // 跳跃按钮
        jumpBtn.addEventListener('touchstart', (e) => {
            e.preventDefault();
            this.buttons.jump = true;
            // 模拟跳跃输入
            if (player && player.onGround && gameState.isPlaying()) {
                player.velocity.y = CONFIG.PLAYER_JUMP_FORCE;
                player.onGround = false;
                if (audio) audio.playJump();
            }
        }, { passive: false });
        
        jumpBtn.addEventListener('touchend', () => {
            this.buttons.jump = false;
        });
        
        // 武器切换按钮
        for (let i = 1; i <= 4; i++) {
            const btn = document.getElementById(`weapon-${i}-btn`);
            if (btn) {
                btn.addEventListener('touchstart', (e) => {
                    e.preventDefault();
                    const weapon = btn.dataset.weapon;
                    if (weapons && weapons.switchWeapon) {
                        weapons.switchWeapon(weapon);
                        hud.updateWeapon(CONFIG.WEAPONS[weapon].name);
                    }
                }, { passive: false });
            }
        }
    }
    
    updateJoystick(clientX, clientY, knob) {
        const dx = clientX - this.joystick.startX;
        const dy = clientY - this.joystick.startY;
        
        const distance = Math.sqrt(dx * dx + dy * dy);
        const maxDist = this.joystick.maxDistance;
        
        if (distance > maxDist) {
            const angle = Math.atan2(dy, dx);
            this.joystick.deltaX = Math.cos(angle) * maxDist / maxDist;
            this.joystick.deltaY = Math.sin(angle) * maxDist / maxDist;
            knob.style.transform = `translate(calc(-50% + ${Math.cos(angle) * maxDist}px), calc(-50% + ${Math.sin(angle) * maxDist}px))`;
        } else {
            this.joystick.deltaX = dx / maxDist;
            this.joystick.deltaY = dy / maxDist;
            knob.style.transform = `translate(calc(-50% + ${dx}px), calc(-50% + ${dy}px))`;
        }
    }
    
    getMoveInput() {
        return {
            x: this.joystick.deltaX,
            y: -this.joystick.deltaY // 负值因为向下是正Y
        };
    }
    
    show() {
        const controls = ['joystick-container', 'touch-look-zone', 'fire-btn', 'jump-btn', 'weapon-1-btn', 'weapon-2-btn', 'weapon-3-btn', 'weapon-4-btn'];
        controls.forEach(id => {
            const el = document.getElementById(id);
            if (el) el.style.display = 'flex';
        });
    }
    
    hide() {
        const controls = ['joystick-container', 'touch-look-zone', 'fire-btn', 'jump-btn', 'weapon-1-btn', 'weapon-2-btn', 'weapon-3-btn', 'weapon-4-btn'];
        controls.forEach(id => {
            const el = document.getElementById(id);
            if (el) el.style.display = 'none';
        });
    }
}

const mobile = new MobileControls();


// autoDemo.js
// 自动演示模式 - AI自动玩游戏,用于首页展示/吸引模式
class AutoDemo {
    constructor() {
        this.enabled = false;
        this.active = false;
        
        this.state = {
            targetPosition: null,
            changeDirectionTimer: 0,
            shootTimer: 0,
            weaponSwitchTimer: 0,
            jumpTimer: 0
        };
    }
    
    init() {
        this.state.targetPosition = new THREE.Vector3(
            (Math.random() - 0.5) * CONFIG.ARENA_SIZE * 1.2,
            1.7,
            (Math.random() - 0.5) * CONFIG.ARENA_SIZE * 1.2
        );
        return this;
    }
    
    start() {
        if (!gameState.isPlaying()) {
            gameState.setState('playing');
            game.start();
        }
        this.active = true;
        this.enabled = true;
    }
    
    stop() {
        this.active = false;
        this.enabled = false;
    }
    
    update(deltaTime) {
        if (!this.active || !gameState.isPlaying()) return;
        
        const state = this.state;
        
        state.changeDirectionTimer -= deltaTime;
        state.shootTimer -= deltaTime;
        state.weaponSwitchTimer -= deltaTime;
        state.jumpTimer -= deltaTime;
        
        // 找最近的敌人
        let closestEnemy = null;
        let closestDist = Infinity;
        
        for (const enemy of enemies.list) {
            if (enemy.dead) continue;
            const dist = player.mesh.position.distanceTo(enemy.mesh.position);
            if (dist < closestDist) {
                closestDist = dist;
                closestEnemy = enemy;
            }
        }
        
        // 如果有敌人,面向敌人并射击
        if (closestEnemy) {
            // 面向敌人
            const direction = new THREE.Vector3();
            direction.subVectors(closestEnemy.mesh.position, player.mesh.position);
            direction.y = 0;
            direction.normalize();
            
            const targetAngle = Math.atan2(direction.x, direction.z);
            player.mesh.rotation.y = targetAngle;
            
            // 移动(保持距离)
            const idealDistance = 15;
            if (closestDist > idealDistance + 2) {
                // 靠近
                player.mesh.position.addScaledVector(direction, 5 * deltaTime);
            } else if (closestDist < idealDistance - 2) {
                // 后退
                player.mesh.position.addScaledVector(direction, -3 * deltaTime);
            } else {
                // 侧移
                const strafe = Math.sin(performance.now() * 0.002) * 2;
                const right = new THREE.Vector3();
                right.crossVectors(direction, new THREE.Vector3(0, 1, 0));
                player.mesh.position.addScaledVector(right, strafe * deltaTime);
            }
            
            // 射击
            if (state.shootTimer <= 0) {
                weapons.fire(player, enemies.list);
                state.shootTimer = 0.15 + Math.random() * 0.1;
            }
            
            // 跳跃(随机)
            if (state.jumpTimer <= 0 && player.onGround && Math.random() < 0.3) {
                player.velocity.y = CONFIG.PLAYER_JUMP_FORCE;
                player.onGround = false;
                state.jumpTimer = 2 + Math.random() * 3;
            }
            
        } else {
            // 没有敌人,随便逛逛
            if (state.changeDirectionTimer <= 0) {
                state.targetPosition = new THREE.Vector3(
                    (Math.random() - 0.5) * CONFIG.ARENA_SIZE * 1.2,
                    1.7,
                    (Math.random() - 0.5) * CONFIG.ARENA_SIZE * 1.2
                );
                state.changeDirectionTimer = 3 + Math.random() * 4;
            }
            
            // 向目标移动
            const direction = new THREE.Vector3();
            direction.subVectors(state.targetPosition, player.mesh.position);
            direction.y = 0;
            
            if (direction.length() > 1) {
                direction.normalize();
                player.mesh.position.addScaledVector(direction, 6 * deltaTime);
                player.mesh.rotation.y = Math.atan2(direction.x, direction.z);
            }
            
            // 随机射击
            if (state.shootTimer <= 0 && Math.random() < 0.3) {
                weapons.fire(player, enemies.list);
            }
            
            if (state.shootTimer <= 0) {
                state.shootTimer = 0.5 + Math.random() * 1;
            }
        }
        
        // 切换武器
        if (state.weaponSwitchTimer <= 0) {
            const weapons_list = ['pistol', 'shotgun', 'laser'];
            const randomWeapon = weapons_list[Math.floor(Math.random() * weapons_list.length)];
            weapons.switchWeapon(randomWeapon);
            hud.updateWeapon(CONFIG.WEAPONS[randomWeapon].name);
            state.weaponSwitchTimer = 5 + Math.random() * 10;
        }
        
        // 边界限制
        const boundary = CONFIG.ARENA_SIZE - 1;
        player.mesh.position.x = Math.max(-boundary, Math.min(boundary, player.mesh.position.x));
        player.mesh.position.z = Math.max(-boundary, Math.min(boundary, player.mesh.position.z));
    }
}

const autoDemo = new AutoDemo();


// gameLoop.js
// 游戏主循环
class Game {
    constructor() {
        this.lastTime = 0;
        this.deltaTime = 0;
        this.isRunning = false;
        this.animationId = null;
        
        this.enemies = [];
        this.bullets = [];
        this.particles = [];
        this.turrets = [];
        
        this.waveManager = null;
    }
    
    init() {
        // 初始化所有系统
        renderer.init();
        input.init();
        hud.init();
        ui.init();
        audio.init();
        effects.init();
        
        // 创建竞技场
        arena.create();
        
        // 初始化武器系统
        weapons.init();
        
        // 初始化商店系统
        if (shop && shop.init) {
            shop.init();
        }
        
        // 初始化敌人系统
        enemies.init();
        
        // 初始化波次管理器
        this.waveManager = waveManager;
        if (waveManager && waveManager.init) {
            waveManager.init();
        }
        
        // 初始化自动演示模式
        if (autoDemo && autoDemo.init) {
            autoDemo.init();
        }
        
        // 移动端适配
        if (input.isMobile && mobile) {
            mobile.init();
        }
        
        // 显示主菜单
        ui.showMenu('main');
        hud.hide();
        
        // 开始渲染循环
        this.isRunning = true;
        this.animate();
        
        console.log('Neon FPS initialized successfully!');
        console.log('Character:', gameState.selectedCharacter);
        console.log('Mobile:', input.isMobile);
    }
    
    start() {
        // 重置游戏状态
        gameState.score = 0;
        gameState.wave = 0;
        gameState.kills = 0;
        gameState.waveDamageTaken = 0;
        gameState.coinsCollected = 0;
        
        // 重置商店
        if (shop && shop.reset) {
            shop.reset();
        }
        
        // 初始化玩家
        player.init(gameState.selectedCharacter);
        
        // 清空敌人和子弹
        enemies.clear();
        this.clearBullets();
        this.clearParticles();
        this.turrets = [];
        
        // 重置Boss
        if (bossManager && bossManager.reset) {
            bossManager.reset();
        }
        
        // 重置拾取物
        if (pickups && pickups.reset) {
            pickups.reset();
        }
        
        // 开始第一波
        if (this.waveManager && this.waveManager.startWave) {
            setTimeout(() => {
                this.waveManager.startWave(1);
            }, 2000);
        }
        
        hud.updateHealth(player.health, player.maxHealth);
        hud.updateWeapon(CONFIG.WEAPONS[weapons.currentWeapon].name);
        
        // 加载成就
        if (achievements && achievements.load) {
            achievements.load();
        }
    }
    
    reset() {
        // 清空所有游戏对象
        enemies.clear();
        this.clearBullets();
        this.clearParticles();
        this.turrets = [];
        
        if (player.mesh) {
            player.reset();
        }
    }
    
    animate() {
        if (!this.isRunning) return;
        
        this.animationId = requestAnimationFrame(() => this.animate());
        
        const currentTime = performance.now();
        this.deltaTime = Math.min((currentTime - this.lastTime) / 1000, 0.1);
        this.lastTime = currentTime;
        
        // 慢动作效果
        if (effects && effects.slowMotionFactor !== undefined && effects.slowMotionFactor < 1) {
            this.deltaTime *= effects.slowMotionFactor;
            effects.updateSlowMotion(this.deltaTime);
        }
        
        if (gameState.isPlaying()) {
            this.update();
        }
        
        // 渲染
        renderer.render();
        
        // 输入后置处理
        input.lateUpdate();
    }
    
    update() {
        // 更新玩家
        player.update(this.deltaTime);
        
        // 更新武器/射击
        if (input.mouseButtons.left || (input.isMobile && mobile && mobile.isFiring)) {
            weapons.fire(player, enemies.list);
        }
        
        // 更新子弹
        this.updateBullets();
        
        // 更新敌人
        enemies.update(this.deltaTime, player.mesh.position);
        
        // 更新Boss
        if (bossManager && bossManager.update) {
            bossManager.update(this.deltaTime, player.mesh.position);
            
            // 更新Boss血条
            const activeBoss = bossManager.getActiveBoss();
            if (activeBoss && hud) {
                hud.updateBossHealth(activeBoss.health, activeBoss.maxHealth);
            }
        }
        
        // 更新拾取物
        if (pickups && pickups.update) {
            pickups.update(this.deltaTime, player.mesh.position);
        }
        
        // 更新波次
        if (this.waveManager && this.waveManager.update) {
            this.waveManager.update(this.deltaTime);
        }
        
        // 更新粒子
        if (particles && particles.update) {
            particles.update(this.deltaTime);
        }
        
        // 更新特效
        if (effects && effects.update) {
            effects.update(this.deltaTime);
        }
        
        // 更新炮塔
        this.updateTurrets();
        
        // 自动演示模式
        if (autoDemo && autoDemo.enabled) {
            autoDemo.update(this.deltaTime);
        }
    }
    
    updateBullets() {
        for (let i = this.bullets.length - 1; i >= 0; i--) {
            const bullet = this.bullets[i];
            
            // 移动子弹
            bullet.mesh.position.addScaledVector(bullet.velocity, this.deltaTime);
            bullet.life -= this.deltaTime;
            
            // 生命结束
            if (bullet.life <= 0) {
                renderer.scene.remove(bullet.mesh);
                this.bullets.splice(i, 1);
                continue;
            }
            
            // 碰撞检测(与敌人)
            if (bullet.isPlayerBullet) {
                for (const enemy of enemies.list) {
                    if (enemy.dead) continue;
                    
                    const dx = bullet.mesh.position.x - enemy.mesh.position.x;
                    const dz = bullet.mesh.position.z - enemy.mesh.position.z;
                    const dy = bullet.mesh.position.y - (enemy.height || 1);
                    const dist = Math.sqrt(dx * dx + dz * dz + dy * dy);
                    
                    if (dist < (enemy.size || 1)) {
                        // 命中
                        const damage = bullet.damage * (1 + player.damageBonus);
                        const hitPos = bullet.mesh.position.clone();
                        const hitDir = bullet.velocity.clone().normalize();
                        
                        // 火箭弹:范围爆炸伤害
                        if (bullet.isRocket) {
                            this.createExplosion(hitPos, bullet.splashRadius, bullet.splashDamage, bullet.color);
                        } else {
                            // 普通命中
                            enemy.takeDamage(damage, hitDir);
                            
                            // 等离子弹:灼烧效果
                            if (bullet.isPlasma) {
                                enemy.applyBurn(bullet.burnDamage, bullet.burnDuration);
                            }
                            
                            // 命中特效
                            if (effects) {
                                effects.createHitEffect(hitPos, bullet.color);
                            }
                        }
                        
                        // 移除子弹
                        renderer.scene.remove(bullet.mesh);
                        this.bullets.splice(i, 1);
                        break;
                    }
                }
            } else {
                // 敌人子弹打玩家
                const dx = bullet.mesh.position.x - player.mesh.position.x;
                const dz = bullet.mesh.position.z - player.mesh.position.z;
                const dist = Math.sqrt(dx * dx + dz * dz);
                
                if (dist < player.collisionRadius) {
                    player.takeDamage(bullet.damage);
                    renderer.scene.remove(bullet.mesh);
                    this.bullets.splice(i, 1);
                }
            }
        }
    }
    
    createExplosion(position, radius, damage, color) {
        // 爆炸特效
        if (effects) {
            effects.createShockwave(position, color, radius, 0.3);
            effects.shake(0.3, 0.15);
        }
        
        if (particles) {
            particles.createExplosion(position, color, 30);
        }
        
        // 范围伤害
        for (const enemy of enemies.list) {
            if (enemy.dead) continue;
            
            const dx = position.x - enemy.mesh.position.x;
            const dz = position.z - enemy.mesh.position.z;
            const dist = Math.sqrt(dx * dx + dz * dz);
            
            if (dist < radius) {
                // 距离衰减
                const falloff = 1 - (dist / radius);
                const actualDamage = damage * falloff * (1 + player.damageBonus);
                const direction = new THREE.Vector3(-dx, 0, -dz).normalize();
                enemy.takeDamage(actualDamage, direction);
            }
        }
        
        // 也可能伤到玩家(自残)
        if (player) {
            const dx = position.x - player.mesh.position.x;
            const dz = position.z - player.mesh.position.z;
            const dist = Math.sqrt(dx * dx + dz * dz);
            
            if (dist < radius * 0.7) {
                const falloff = 1 - (dist / (radius * 0.7));
                player.takeDamage(damage * falloff * 0.3); // 自残伤害减半再减半
            }
        }
    }
    
    updateTurrets() {
        if (this.turrets.length === 0) return;
        
        const now = performance.now();
        
        for (let i = this.turrets.length - 1; i >= 0; i--) {
            const turret = this.turrets[i];
            turret.lifetime -= this.deltaTime;
            
            if (turret.lifetime <= 0) {
                renderer.scene.remove(turret.mesh);
                this.turrets.splice(i, 1);
                continue;
            }
            
            // 寻找最近的敌人
            let nearestEnemy = null;
            let nearestDist = turret.range;
            
            for (const enemy of enemies.list) {
                if (enemy.dead) continue;
                const dist = turret.mesh.position.distanceTo(enemy.mesh.position);
                if (dist < nearestDist) {
                    nearestDist = dist;
                    nearestEnemy = enemy;
                }
            }
            
            if (nearestEnemy && now - turret.lastFire > turret.fireRate) {
                // 转向敌人
                const direction = new THREE.Vector3();
                direction.subVectors(nearestEnemy.mesh.position, turret.mesh.position);
                direction.y = 0;
                direction.normalize();
                
                // 发射子弹
                const bullet = {
                    mesh: new THREE.Mesh(
                        new THREE.SphereGeometry(0.08, 6, 6),
                        new THREE.MeshBasicMaterial({ color: 0xffaa00 })
                    ),
                    velocity: direction.multiplyScalar(30),
                    damage: turret.damage,
                    life: 2,
                    color: 0xffaa00,
                    isPlayerBullet: true
                };
                
                bullet.mesh.position.copy(turret.mesh.position);
                bullet.mesh.position.y = 0.5;
                renderer.scene.add(bullet.mesh);
                this.bullets.push(bullet);
                
                turret.lastFire = now;
            }
        }
    }
    
    clearBullets() {
        for (const bullet of this.bullets) {
            if (bullet.mesh) {
                renderer.scene.remove(bullet.mesh);
            }
        }
        this.bullets = [];
    }
    
    clearParticles() {
        if (particles && particles.clear) {
            particles.clear();
        }
    }
    
    startNextWave() {
        // 从商店界面开始下一波
        if (shop && shop.closeShop) {
            shop.closeShop();
        }
        
        if (this.waveManager && this.waveManager.startWave) {
            this.waveManager.startWave(this.waveManager.currentWave + 1);
        }
        
        // 移动端重新锁定指针
        if (input && input.isMobile && input.isPointerLocked) {
            // 移动端不需要指针锁定
        }
    }
    
    stop() {
        this.isRunning = false;
        if (this.animationId) {
            cancelAnimationFrame(this.animationId);
        }
    }
}

const game = new Game();


// main.js
// Neon FPS - 主入口
// 所有模块按依赖顺序加载

// 确保Three.js已加载
if (typeof THREE === 'undefined') {
    console.error('Three.js is not loaded!');
}

// 等待DOM加载完成
document.addEventListener('DOMContentLoaded', () => {
    console.log('Neon FPS loading...');
    
    // 加载字体(可选)
    const fontLink = document.createElement('link');
    fontLink.href = 'https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap';
    fontLink.rel = 'stylesheet';
    document.head.appendChild(fontLink);
    
    // 初始化游戏
    setTimeout(() => {
        game.init();
        console.log('Neon FPS started!');
    }, 100);
});

// 兼容性:如果是直接通过script标签加载,确保全局可用
window.NeonFPS = {
    game: game,
    player: player,
    renderer: renderer,
    input: input,
    hud: hud,
    ui: ui,
    audio: audio,
    effects: effects,
    enemies: enemies,
    weapons: weapons,
    gameState: gameState,
    CONFIG: CONFIG
};



</script>
</body>
</html>

Game Source: Neon FPS

Creator: RocketOwl77

Libraries: three

Complexity: complex (7796 lines, 244.0 KB)

The full source code is displayed above on this page.

Remix Instructions

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