UNPKG

aitetris

Version:

致敬程序员阿列克谢·帕基特诺夫带给全世界人民的欢乐摸鱼时光,今天我们与AI一起重制了这款经典摸鱼小游戏,公益、免费、开源、分享给大家~ In tribute to programmer Alexey Pajitnov, who brought joy and countless delightful slacking-off moments to people around the world, we've teamed up with AI to remake the classic time-kill

1,898 lines 78.4 kB
// Tetris游戏核心逻辑
class TetrisGame_7ree {
    constructor() {
        // 游戏配置
        this.rows = 20;
        this.cols = 11;
        this.score = 0;
        this.level = 1;
        this.lines = 0;
        this.isPlaying = false;
        this.isPaused = false;
        this.gameEnded = false;
        this.isSoundOn = true;
        this.isGhostPieceEnabled = true; // 新增:幽灵方块状态
        this.gameTime = 0;
        this.timeInterval = null;
        this.gameInterval = null;
        
        // 方块下落速度(毫秒),从难度设置获取
        this.speed = this.getInitialSpeed();
        
        // 当前方块和下一个方块
        this.currentPiece = null;
        this.nextPiece = null;
        
        // 游戏面板状态,0表示空,非0表示已填充方块(值对应颜色索引)
        this.board = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
        
        // 方块形状定义(7种标准俄罗斯方块)
        this.shapes = [
            // I形
            [
                [0, 0, 0, 0],
                [1, 1, 1, 1],
                [0, 0, 0, 0],
                [0, 0, 0, 0]
            ],
            // J形
            [
                [2, 0, 0],
                [2, 2, 2],
                [0, 0, 0]
            ],
            // L形
            [
                [0, 0, 3],
                [3, 3, 3],
                [0, 0, 0]
            ],
            // O形
            [
                [4, 4],
                [4, 4]
            ],
            // S形
            [
                [0, 5, 5],
                [5, 5, 0],
                [0, 0, 0]
            ],
            // T形
            [
                [0, 6, 0],
                [6, 6, 6],
                [0, 0, 0]
            ],
            // Z形
            [
                [7, 7, 0],
                [0, 7, 7],
                [0, 0, 0]
            ]
        ];
        
        // 方块颜色 - 从配置文件读取
        const hasColorConfig = (typeof config !== 'undefined' && typeof config.squareColor !== 'undefined');
        
        // 如果配置文件中有颜色定义,则使用配置文件中的值,否则使用默认值
        this.colors = hasColorConfig ? config.squareColor : [
            'transparent',     // 0: 空白
            '#00FFFF',         // 1: 青色 (I)
            '#0000FF',         // 2: 蓝色 (J)
            '#FF7F00',         // 3: 橙色 (L)
            '#FFFF00',         // 4: 黄色 (O)
            '#00FF00',         // 5: 绿色 (S)
            '#800080',         // 6: 紫色 (T)
            '#FF0000'          // 7: 红色 (Z)
        ];
        
        console.log(getText_7ree('logColorSource') + (hasColorConfig ? getText_7ree('configProfile') : getText_7ree('defaultValue')));
        
        // --- 更新配置读取逻辑:用户配置 > 系统配置 > 默认值 ---
        
        // 声音状态
        let soundDefaultOn = true; // 硬编码默认值
        if (typeof config !== 'undefined' && config.audio && config.audio.defaultOn !== undefined) {
            soundDefaultOn = config.audio.defaultOn; // 从系统配置读取
        }
        if (typeof user_config !== 'undefined' && user_config.audio && user_config.audio.defaultOn !== undefined) {
            soundDefaultOn = user_config.audio.defaultOn; // 优先从用户配置读取
        }
        this.isSoundOn = soundDefaultOn;
        console.log(getText_7ree('logConfigSoundDefault') + this.isSoundOn); // Use getText_7ree
        
        // 幽灵方块状态
        let ghostDefaultOn = true; // 硬编码默认值
        if (typeof config !== 'undefined' && config.features && config.features.ghostPieceDefaultOn !== undefined) {
            ghostDefaultOn = config.features.ghostPieceDefaultOn; // 从系统配置读取
        }
        if (typeof user_config !== 'undefined' && user_config.features && user_config.features.ghostPieceDefaultOn !== undefined) {
            ghostDefaultOn = user_config.features.ghostPieceDefaultOn; // 优先从用户配置读取
        }
        this.isGhostPieceEnabled = ghostDefaultOn;
        console.log(getText_7ree('logConfigGhostDefault') + this.isGhostPieceEnabled); // Use getText_7ree

        // --- 本地存储 (用户偏好) 仍然具有最高优先级 ---
        
        // 读取本地存储的声音状态
        const savedSoundState = localStorage.getItem('tetris_sound_on_7ree');
        if (savedSoundState !== null) {
            this.isSoundOn = savedSoundState === 'true';
            console.log(getText_7ree('logLoadSoundStateLocal') + this.isSoundOn); // Use getText_7ree
        } else {
            // 如果本地没有,则将最终确定的配置值存入本地
            localStorage.setItem('tetris_sound_on_7ree', this.isSoundOn);
            // 确保静音状态也同步更新
            localStorage.setItem('tetris_muted_7ree', !this.isSoundOn);
        }

        // 读取本地存储的幽灵方块状态
        const savedGhostState = localStorage.getItem('tetris_ghost_on_7ree');
        if (savedGhostState !== null) {
            this.isGhostPieceEnabled = savedGhostState === 'true';
            console.log(getText_7ree('logLoadGhostStateLocal') + this.isGhostPieceEnabled); // Use getText_7ree
        } else {
            // 如果本地没有,则将最终确定的配置值存入本地
            localStorage.setItem('tetris_ghost_on_7ree', this.isGhostPieceEnabled);
        }
        
        // 初始化DOM元素引用
        this.initDomElements();
        
        // 初始化事件监听
        this.initEventListeners();
        
        // 初始化音效
        this.initSounds();
    }
    
    // 初始化DOM元素引用
    initDomElements() {
        this.gameBoardElement = document.getElementById('game_board_7ree');
        this.nextPieceElement = document.getElementById('next_piece_7ree');
        this.scoreElement = document.getElementById('score_7ree');
        this.levelElement = document.getElementById('level_7ree');
        this.linesElement = document.getElementById('lines_7ree');
        this.timeElement = document.getElementById('time_7ree');
        
        // 移动端元素
        this.mobileScoreElement = document.getElementById('mobile_score_7ree');
        this.mobileLevelElement = document.getElementById('mobile_level_7ree');
        this.mobileLinesElement = document.getElementById('mobile_lines_7ree');
        this.mobileTimeElement = document.getElementById('mobile_time_7ree');
        
        // 按钮元素
        this.startButton = document.getElementById('start_btn_7ree');
        this.pauseButton = document.getElementById('pause_btn_7ree');
        this.soundButton = document.getElementById('sound_btn_7ree');
        this.leftButton = document.getElementById('left_btn_7ree');
        this.rightButton = document.getElementById('right_btn_7ree');
        this.downButton = document.getElementById('down_btn_7ree');
        this.rotateButton = document.getElementById('rotate_btn_7ree');
        this.dropButton = document.getElementById('drop_btn_7ree');
        this.ghostToggleButton = document.getElementById('ghost_toggle_btn_7ree'); // 新增按钮引用
        
        // 卡片元素
        this.welcomeCardElement = document.getElementById('welcome_card_7ree');
        this.gameoverCardElement = document.getElementById('gameover_card_7ree');
        this.pauseCardElement = document.getElementById('pause_card_7ree');
        this.resumeGameButton = document.getElementById('resume_game_btn_7ree');
        
        // 新增:帮助卡片和按钮引用
        this.helpCardElement = document.getElementById('help_card_7ree');
        this.helpButton = document.getElementById('help_btn_7ree');
        this.closeHelpButton = document.getElementById('close_help_btn_7ree');
        
        // 创建游戏面板
        this.createGameBoard();
        this.createNextPieceBoard();
        
        // 设置声音按钮的初始状态
        if (this.soundButton) {
            this.soundButton.textContent = this.isSoundOn ? '🔊' : '🔇';
        }
        // 设置幽灵方块按钮的初始状态
        this.updateGhostButtonVisuals();
    }
    
    // 初始化音效
    initSounds() {
        // 获取音频元素
        this.rotateSound = document.getElementById('rotate_sound_7ree');
        this.moveSound = document.getElementById('move_sound_7ree');
        this.dropSound = document.getElementById('drop_sound_7ree');
        this.clearSound = document.getElementById('clear_sound_7ree');
        this.gameoverSound = document.getElementById('gameover_sound_7ree');
        this.levelupSound = document.getElementById('levelup_sound_7ree');
        this.landedSound = document.getElementById('landed_sound_7ree');
        this.harddropSound = document.getElementById('harddrop_sound_7ree');
        this.comboSound = document.getElementById('combo_sound_7ree');
        
        // 设置音频源路径
        const audioPath = (typeof config !== 'undefined' && config.audio && config.audio.path) 
            ? ((config.audio.path.endsWith('/')) ? config.audio.path : config.audio.path + '/') 
            : 'resource/sounds/';
            
        // 检查配置文件中是否有音效定义
        const hasSoundEffects = (
            typeof config !== 'undefined' && 
            config.audio && 
            config.audio.files && 
            config.audio.files.soundEffects
        );
        
        // 设置音频源,优先使用配置文件中的音效定义
        if (this.rotateSound && this.rotateSound.querySelector('source')) {
            const rotateFile = hasSoundEffects ? `${config.audio.files.soundEffects.rotate}_7ree.mp3` : 'rotate.mp3';
            this.rotateSound.querySelector('source').src = audioPath + rotateFile;
            this.rotateSound.load();
        }
        
        if (this.moveSound && this.moveSound.querySelector('source')) {
            const moveFile = hasSoundEffects ? `${config.audio.files.soundEffects.move}_7ree.mp3` : 'move.mp3';
            this.moveSound.querySelector('source').src = audioPath + moveFile;
            this.moveSound.load();
        }
        
        if (this.dropSound && this.dropSound.querySelector('source')) {
            const dropFile = hasSoundEffects ? `${config.audio.files.soundEffects.drop}_7ree.mp3` : 'drop.mp3';
            this.dropSound.querySelector('source').src = audioPath + dropFile;
            this.dropSound.load();
        }
        
        if (this.clearSound && this.clearSound.querySelector('source')) {
            const clearFile = hasSoundEffects ? `${config.audio.files.soundEffects.lineClear}_7ree.mp3` : 'clear.mp3';
            this.clearSound.querySelector('source').src = audioPath + clearFile;
            this.clearSound.load();
        }
        
        if (this.gameoverSound && this.gameoverSound.querySelector('source')) {
            const gameoverFile = hasSoundEffects ? `${config.audio.files.soundEffects.gameOver}_7ree.mp3` : 'gameover.mp3';
            this.gameoverSound.querySelector('source').src = audioPath + gameoverFile;
            this.gameoverSound.load();
        }
        
        if (this.levelupSound && this.levelupSound.querySelector('source')) {
            const levelupFile = hasSoundEffects ? `${config.audio.files.soundEffects.levelUp}_7ree.mp3` : 'levelup.mp3';
            this.levelupSound.querySelector('source').src = audioPath + levelupFile;
            this.levelupSound.load();
        }
        
        if (this.landedSound && this.landedSound.querySelector('source')) {
            const landedFile = hasSoundEffects ? `${config.audio.files.soundEffects.landed}_7ree.mp3` : 'landed.mp3';
            this.landedSound.querySelector('source').src = audioPath + landedFile;
            this.landedSound.load();
        }
        
        if (this.harddropSound && this.harddropSound.querySelector('source')) {
            const harddropFile = hasSoundEffects ? `${config.audio.files.soundEffects.hardDrop}_7ree.mp3` : 'harddrop.mp3';
            this.harddropSound.querySelector('source').src = audioPath + harddropFile;
            this.harddropSound.load();
        }
        
        if (this.comboSound && this.comboSound.querySelector('source')) {
            const comboFile = hasSoundEffects ? `${config.audio.files.soundEffects.combo}_7ree.mp3` : 'combo.mp3';
            this.comboSound.querySelector('source').src = audioPath + comboFile;
            this.comboSound.load();
        }
        
        console.log("[游戏] 音效文件来源: " + (hasSoundEffects ? "配置文件" : "默认值"));
    }
    
    // 播放音效
    playSound(sound) {
        if (!this.isSoundOn) return;
        
        // 处理直接传入字符串的情况(用于移动端调用)
        if (typeof sound === 'string') {
            const soundName = sound; // Keep original name for logs
            switch(sound) {
                case 'rotate':
                    sound = this.rotateSound;
                    break;
                case 'move':
                    sound = this.moveSound;
                    break;
                case 'drop':
                    sound = this.dropSound;
                    break;
                case 'clear':
                    sound = this.clearSound;
                    break;
                case 'gameover':
                    sound = this.gameoverSound;
                    break;
                case 'levelup':
                    sound = this.levelupSound;
                    break;
                case 'landed':
                    sound = this.landedSound;
                    break;
                case 'harddrop':
                    sound = this.harddropSound;
                    break;
                case 'combo':
                    sound = this.comboSound;
                    break;
                default:
                    console.warn(getText_7ree('logUnknownSoundType'), soundName); // Use getText_7ree
                    return;
            }
        }
        
        // 确保是有效的音频元素
        if (!sound || typeof sound.play !== 'function') {
            console.warn(getText_7ree('logInvalidSoundElement')); // Use getText_7ree
            return;
        }
        
        try {
            sound.currentTime = 0;
            const playPromise = sound.play();
            
            if (playPromise !== undefined) {
                playPromise.catch(e => {
                    console.warn(getText_7ree('logSoundPlayFail'), e); // Use getText_7ree
                    
                    // 如果是移动端,尝试在下一次用户交互时播放
                    if (DeviceHandler_7ree && DeviceHandler_7ree.isMobile()) {
                        // 这里不需要额外处理,因为移动端的音频问题已在SoundManager中处理
                    }
                });
            }
        } catch (e) {
            console.warn(getText_7ree('logSoundPlayError'), e); // Use getText_7ree
        }
    }
    
    // 创建游戏面板
    createGameBoard() {
        this.gameBoardElement.innerHTML = '';
        this.gameBoardElement.style.gridTemplateRows = `repeat(${this.rows}, 1fr)`;
        this.gameBoardElement.style.gridTemplateColumns = `repeat(${this.cols}, 1fr)`;
        
        // 创建游戏面板的3D效果元素
        const sideEffect = document.createElement('div');
        sideEffect.className = 'game_board_side_effect';
        this.gameBoardElement.appendChild(sideEffect);
        
        // 创建扫光动画效果元素
        const lightSweep = document.createElement('div');
        lightSweep.className = 'game_board_light_sweep';
        this.gameBoardElement.appendChild(lightSweep);
        
        // 在动态创建单元格之前添加CSS Class以确保布局正确
        this.gameBoardElement.classList.add('game_board_grid_7ree');
        
        for (let row = 0; row < this.rows; row++) {
            for (let col = 0; col < this.cols; col++) {
                const cell = document.createElement('div');
                cell.className = 'cell_7ree';
                cell.dataset.row = row;
                cell.dataset.col = col;
                
                this.gameBoardElement.appendChild(cell);
            }
        }
    }
    
    // 创建下一个方块预览窗口
    createNextPieceBoard() {
        this.nextPieceElement.innerHTML = '';
        this.nextPieceElement.style.gridTemplateRows = 'repeat(4, 1fr)';
        this.nextPieceElement.style.gridTemplateColumns = 'repeat(4, 1fr)';
        
        // 添加CSS Class以确保预览窗口布局正确
        this.nextPieceElement.classList.add('next_piece_grid_7ree');
        
        for (let row = 0; row < 4; row++) {
            for (let col = 0; col < 4; col++) {
                const cell = document.createElement('div');
                cell.className = 'preview_cell_7ree';
                cell.dataset.row = row;
                cell.dataset.col = col;
                
                this.nextPieceElement.appendChild(cell);
            }
        }
    }
    
    // 初始化事件监听
    initEventListeners() {
        // 键盘控制
        document.addEventListener('keydown', this.handleKeyPress.bind(this));
        
        // --- 改为与操作按钮一致的鼠标事件处理,添加视觉反馈 ---
        // 定义控制按钮的处理
        const controlButtons = [
            { btn: this.startButton, action: () => this.startGame() },
            { btn: this.pauseButton, action: () => this.togglePause() },
            { btn: this.soundButton, action: () => this.toggleSound() },
            { btn: this.ghostToggleButton, action: () => this.toggleGhostPiece() } // 新增:绑定切换方法
        ];

        // 为控制按钮应用与操作按钮相同的视觉反馈处理
        controlButtons.forEach(({ btn, action }) => {
            if (btn) {
                let activeTimeoutId = null; // 用于存储延迟移除类的计时器ID

                // 按下时添加激活样式
                btn.addEventListener('mousedown', () => {
                    // 如果有正在等待移除的计时器,先清除它
                    if (activeTimeoutId) {
                        clearTimeout(activeTimeoutId);
                        activeTimeoutId = null;
                    }
                    btn.classList.add('btn_active_7ree');
                });

                // 松开时启动延迟移除并执行动作
                btn.addEventListener('mouseup', () => {
                    // 清除可能存在的旧计时器
                    if (activeTimeoutId) {
                        clearTimeout(activeTimeoutId);
                    }
                    // 启动新的延迟移除计时器
                    activeTimeoutId = setTimeout(() => {
                        btn.classList.remove('btn_active_7ree');
                        activeTimeoutId = null;
                    }, 400); // 与操作按钮一致,使用0.4秒
                    
                    // 触发视觉反馈
                    this.triggerButtonFeedback(btn);
                    
                    // 执行按钮动作 (控制按钮不需要检查游戏状态)
                    action();
                });

                // 鼠标移开时立即移除激活样式
                btn.addEventListener('mouseout', () => {
                    if (btn.classList.contains('btn_active_7ree')) {
                        if (activeTimeoutId) {
                            clearTimeout(activeTimeoutId);
                            activeTimeoutId = null;
                        }
                        btn.classList.remove('btn_active_7ree');
                    }
                });

                // 为兼容性保留click事件,但不添加视觉效果
                // 因为mouseup已经执行了action,这里不再重复执行
                btn.addEventListener('click', (e) => {
                    e.preventDefault(); // 防止重复触发
                });
            }
        });
        
        // --- 修改移动/旋转/下落按钮的监听器以添加视觉反馈 ---
        const buttonsToAnimate = [
            { btn: this.leftButton, action: () => this.moveLeft() },
            { btn: this.rightButton, action: () => this.moveRight() },
            { btn: this.downButton, action: () => this.moveDown(true) }, // 传递true表示是用户操作
            { btn: this.rotateButton, action: () => this.rotate() },
            { btn: this.dropButton, action: () => this.hardDrop() }
        ];

        buttonsToAnimate.forEach(({ btn, action }) => {
            if (btn) {
                let activeTimeoutId = null; // 用于存储延迟移除类的计时器ID

                // 按下时添加激活样式 (鼠标)
                btn.addEventListener('mousedown', () => {
                    // 如果有正在等待移除的计时器,先清除它
                    if (activeTimeoutId) {
                        clearTimeout(activeTimeoutId);
                        activeTimeoutId = null;
                    }
                    btn.classList.add('btn_active_7ree');
                });

                // 松开时启动延迟移除并执行动作 (鼠标)
                btn.addEventListener('mouseup', () => {
                    // 清除可能存在的旧计时器(以防万一)
                    if (activeTimeoutId) {
                        clearTimeout(activeTimeoutId);
                    }
                    // 启动新的延迟移除计时器
                    activeTimeoutId = setTimeout(() => {
                        btn.classList.remove('btn_active_7ree');
                        activeTimeoutId = null; // 清除计时器ID
                    }, 400); // 修改为 0.4秒
                    
                    // 触发视觉反馈
                    this.triggerButtonFeedback(btn);
                    
                    // 执行按钮动作
                    if (this.isPlaying && !this.isPaused) {
                        action();
                    }
                });

                // 鼠标移开时立即移除激活样式 (鼠标) (同样移除反馈逻辑)
                btn.addEventListener('mouseout', () => {
                    // 只有在按钮当前是激活状态(表示鼠标可能还按着)时才处理
                    if (btn.classList.contains('btn_active_7ree')) {
                        // 如果有延迟移除计时器,清除它
                        if (activeTimeoutId) {
                            clearTimeout(activeTimeoutId);
                            activeTimeoutId = null;
                        }
                        // 立即移除样式
                        btn.classList.remove('btn_active_7ree');
                    }
                });

                // 在PC端处理点击事件,但移动端不添加(因为移动端在mo_7ree.js中通过触摸事件处理)
                if (!DeviceHandler_7ree.isMobile()) {
                    btn.addEventListener('click', (e) => {
                        e.preventDefault(); // 防止重复触发
                        if (this.isPlaying && !this.isPaused) {
                            action();
                        }
                    });
                }
            }
        });
        
        // 难度选择控制
        this.initDifficultySelector();
        
        // 移除窗口大小变化时JS设置高度的逻辑
        window.addEventListener('resize', () => {
            // 只需重绘,大小由CSS处理
            this.draw();
        });
        
        // 初始化暂停卡片的继续按钮
        if (this.resumeGameButton) {
            this.resumeGameButton.addEventListener('click', () => {
                this.togglePause();
            });
        }

        // 新增:帮助按钮事件监听
        if (this.helpButton) {
            this.helpButton.addEventListener('click', () => {
                this.showHelpCard();
            });
        }

        // 新增:关闭帮助按钮事件监听
        if (this.closeHelpButton) {
            this.closeHelpButton.addEventListener('click', () => {
                this.hideHelpCard();
            });
        }

        // 新增:Esc键关闭帮助卡片
        document.addEventListener('keydown', (event) => {
            if (event.key === 'Escape' && this.helpCardElement && this.helpCardElement.classList.contains('show_7ree')) {
                this.hideHelpCard();
            }
        });
    }
    
    // --- 新增:触发按钮视觉反馈的辅助方法 ---
    triggerButtonFeedback(buttonElement) {
        if (!buttonElement) return;
        
        // 立即添加激活类
        buttonElement.classList.add('btn_active_7ree');
        
        // 设置延时移除 (与鼠标/触摸事件的延迟保持一致,例如 400ms)
        setTimeout(() => {
            buttonElement.classList.remove('btn_active_7ree');
        }, 400); 
    }
    
    // 初始化难度选择器
    initDifficultySelector() {
        // 获取欢迎界面上的难度选择器
        const difficultySelect = document.getElementById('difficulty_select_7ree');
        if (!difficultySelect) return;
        
        if (typeof DifficultyManager_7ree !== 'undefined') {
            // 从难度管理器获取当前难度
            const currentDifficulty = DifficultyManager_7ree.getCurrentDifficultyName();
            
            // 设置选择器的当前值
            difficultySelect.value = currentDifficulty;
            
            // 设置select元素的value属性,以便CSS伪元素能正确显示
            difficultySelect.setAttribute('value', currentDifficulty);
            
            // 添加变更事件
            difficultySelect.addEventListener('change', (event) => {
                console.log("[Log] Difficulty 'change' event triggered."); // 日志1
                const newDifficulty = event.target.value;
                difficultySelect.setAttribute('value', newDifficulty);
                
                console.log("[Log] Calling DifficultyManager.setDifficulty with:", newDifficulty); // 日志2
                DifficultyManager_7ree.setDifficulty(newDifficulty);
                console.log("[Log] Difficulty 'change' event finished."); // 日志3
            });
        }
    }
    
    // 处理键盘按键
    handleKeyPress(event) {
        if (!this.isPlaying || this.isPaused) return;
        
        // 防止方向键导致页面滚动
        const relevantKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'];
        if (relevantKeys.includes(event.code)) {
            event.preventDefault();
        }
        
        let targetButton = null;
        
        switch (event.code) {
            case 'ArrowLeft':
                if (this.moveLeft()) {
                    targetButton = this.leftButton;
                }
                break;
            case 'ArrowRight':
                if (this.moveRight()) {
                    targetButton = this.rightButton;
                }
                break;
            case 'ArrowDown':
                if (this.moveDown(true)) { // 传递true表示是用户操作
                    targetButton = this.downButton;
                }
                break;
            case 'ArrowUp':
                if (this.rotate()) {
                    targetButton = this.rotateButton;
                }
                break;
            case 'Space':
                // 落到底会立即结束当前回合,反馈时间太短可能看不清
                this.hardDrop();
                targetButton = this.dropButton;
                break;
        }
        
        // 应用视觉反馈
        if (targetButton) {
            // targetButton.classList.add('btn_active_7ree');
            // setTimeout(() => {
            //    targetButton.classList.remove('btn_active_7ree');
            // }, 400); // 修改为 0.4秒
            this.triggerButtonFeedback(targetButton); // 使用新的辅助方法
        }
    }
    
    // 开始游戏
    startGame(fromSoundManager = false) {
        console.log("[Log] startGame() called. Source:", fromSoundManager ? "SoundManager" : "Direct"); // 日志4
        
        // 重置游戏状态
        console.log("[Log] startGame() calling resetGame()."); // 日志5
        this.resetGame();
        console.log("[Log] startGame() returned from resetGame()."); // 日志6
        
        this.isPlaying = true;
        this.isPaused = false;
        this.gameEnded = false;
        
        // 生成第一个方块
        this.currentPiece = this.generatePiece();
        
        // 生成下一个方块
        this.generateNextPiece();
        
        // 更新游戏显示
        this.draw();
        this.drawNextPiece();
        
        // 开始游戏循环
        this.gameInterval = setInterval(() => this.gameLoop(), this.speed);
        
        // 开始计时
        this.timeInterval = setInterval(() => {
            this.gameTime++;
            this.updateTimeDisplay();
        }, 1000);
        
        // 启用暂停按钮
        this.pauseButton.disabled = false;
        
        // 更新按钮文本
        this.startButton.textContent = '🔄'; // 重新开始图标
        this.pauseButton.textContent = '⏸️'; // 暂停图标
        
        // 播放背景音乐 - 只有在不是从声音管理器调用时才需要这样做
        if (!fromSoundManager && typeof SoundManager_7ree !== 'undefined' && !SoundManager_7ree.isMuted && !SoundManager_7ree.currentBgm) {
            console.log("[游戏] 启动背景音乐播放");
            SoundManager_7ree.playBgmDirect();
        } else {
            console.log("[游戏] 跳过背景音乐播放初始化 - " + (fromSoundManager ? "从声音管理器调用" : "其他原因"));
        }
        console.log("[Log] startGame() finished."); // 日志7
    }
    
    // 重置游戏状态
    resetGame() {
        console.log("[Log] resetGame() called."); // 日志8
        this.resetGameWithDifficulty();
        this.gameEnded = false; 
        console.log("[Log] resetGame() finished."); // 日志9
    }
    
    // 根据难度设置重置游戏
    resetGameWithDifficulty(difficultySettings = null) {
        console.log("[Log] resetGameWithDifficulty() called. Passed settings:", difficultySettings); // 日志10
        
        // 重置游戏状态
        this.isPlaying = false;
        this.isPaused = false;
        this.gameEnded = false;
        
        // 清除所有计时器
        if (this.gameInterval) {
            clearInterval(this.gameInterval);
            this.gameInterval = null;
        }
        if (this.timeInterval) {
            clearInterval(this.timeInterval);
            this.timeInterval = null;
        }
        
        // 重置游戏状态
        this.score = 0;
        this.lines = 0;
        this.level = 1;
        this.gameTime = 0;
        
        // 应用难度设置
        if (difficultySettings) {
            console.log("[Log] Applying passed difficulty settings in resetGameWithDifficulty."); // 日志11
            this.speed = difficultySettings.defaultSpeed;
        } else if (typeof DifficultyManager_7ree !== 'undefined') {
            console.log("[Log] Getting difficulty settings from DifficultyManager in resetGameWithDifficulty."); // 日志12
            this.speed = DifficultyManager_7ree.getDefaultSpeed();
        } else {
            console.log("[Log] Using fallback default speed in resetGameWithDifficulty."); // 日志13
        this.speed = 1000;
        }
        
        // 清空游戏面板
        this.board = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
        
        // 如果存在难度管理器,应用初始方块叠加
        if (typeof DifficultyManager_7ree !== 'undefined') {
            console.log("[Log] Checking and applying initial stack in resetGameWithDifficulty."); // 日志14
            this.board = DifficultyManager_7ree.createInitialStack(this.board, this.cols, this.rows);
        } else {
             console.log("[Log] DifficultyManager not found, skipping initial stack."); // 日志15
        }
        
        // 重置当前和下一个方块
        this.currentPiece = null;
        this.nextPiece = null;
        
        // 更新显示
        this.updateScoreDisplay();
        this.updateTimeDisplay();
        
        // 绘制空面板
        this.draw();
        console.log("[Log] resetGameWithDifficulty() finished."); // 日志16
    }
    
    // 获取初始下落速度
    getInitialSpeed() {
        if (typeof DifficultyManager_7ree !== 'undefined' && DifficultyManager_7ree.settings) {
            return DifficultyManager_7ree.getDefaultSpeed();
        } else if (typeof config !== 'undefined' && config.difficulty && config.difficulty.defaultSpeed) {
            return config.difficulty.defaultSpeed;
        }
        return 1000; // 默认1000毫秒
    }
    
    // 根据关卡计算下落速度
    getSpeedByLevel(level) {
        // 如果存在难度管理器,使用其计算方法
        if (typeof DifficultyManager_7ree !== 'undefined') {
            return DifficultyManager_7ree.calculateSpeedByLevel(level);
        }
        
        // 否则使用默认计算方法
        // 获取配置中的速度因子,默认为0.9
        const speedFactor = (typeof config !== 'undefined' && 
                              config.difficulty && 
                              config.difficulty.speedFactor) 
                            ? config.difficulty.speedFactor 
                            : 0.9;
        
        // 基础速度,每升一级减少指定比例
        return Math.floor(this.speed * Math.pow(speedFactor, level - 1));
    }
    
    // 游戏主循环
    gameLoop() {
        if (!this.moveDown(false)) { // 传递false表示是游戏自动下落,非用户操作
            // 无法下落,固定当前方块
            this.placePiece();
            // 检查行消除
            const clearedLines = this.clearLines();
            if (clearedLines > 0) {
                this.playSound(this.clearSound);
                // 更新分数
                this.updateScore(clearedLines);
            }
            
            // 生成新方块
            this.currentPiece = this.nextPiece;
            this.generateNextPiece();
            
            // 绘制下一个方块预览
            this.drawNextPiece();
            
            // 检查游戏结束
            if (this.checkCollision(0, 0)) {
                console.log("检测到碰撞,游戏结束...");
                this.endGame();
            }
        }
        
        // 重绘游戏面板
        this.draw();
    }
    
    // 生成随机方块
    generatePiece() {
        const randomIndex = Math.floor(Math.random() * this.shapes.length);
        const shape = this.shapes[randomIndex];
        
        return {
            shape: shape,
            color: randomIndex + 1,
            row: 0,
            col: Math.floor((this.cols - shape[0].length) / 2)
        };
    }
    
    // 生成下一个方块
    generateNextPiece() {
        this.nextPiece = this.generatePiece();
        return this.nextPiece;
    }
    
    // 检查碰撞
    checkCollision(rowOffset, colOffset, rotatedShape = null) {
        // 如果当前没有活动方块,则返回false
        if (!this.currentPiece) {
            return false;
        }
        
        const shape = rotatedShape || this.currentPiece.shape;
        const row = this.currentPiece.row + rowOffset;
        const col = this.currentPiece.col + colOffset;
        
        for (let r = 0; r < shape.length; r++) {
            for (let c = 0; c < shape[r].length; c++) {
                if (shape[r][c] !== 0) {
                    const newRow = row + r;
                    const newCol = col + c;
                    
                    // 检查边界
                    if (newRow >= this.rows || newCol < 0 || newCol >= this.cols) {
                        return true;
                    }
                    
                    // 检查是否与已有方块重叠(且不是边界外)
                    if (newRow >= 0 && this.board[newRow][newCol] !== 0) {
                        return true;
                    }
                }
            }
        }
        
        return false;
    }
    
    // 左移
    moveLeft() {
        if (!this.isPlaying || this.isPaused) return false;
        
        // 先记录当前方块的位置
        const oldPositions = this.getCurrentPiecePositions();
        
        if (!this.checkCollision(0, -1)) {
            // 先清除旧位置的绘制
            this.clearPieceFromBoard(oldPositions);
            
            // 更新方块位置
            this.currentPiece.col--;
            
            this.playSound(this.moveSound);
            this.draw();
            return true;
        }
        return false;
    }
    
    // 右移
    moveRight() {
        if (!this.isPlaying || this.isPaused) return false;
        
        // 先记录当前方块的位置
        const oldPositions = this.getCurrentPiecePositions();
        
        if (!this.checkCollision(0, 1)) {
            // 先清除旧位置的绘制
            this.clearPieceFromBoard(oldPositions);
            
            // 更新方块位置
            this.currentPiece.col++;
            
            this.playSound(this.moveSound);
            this.draw();
            return true;
        }
        return false;
    }
    
    // 下移
    moveDown(isUserAction = false) {
        if (!this.isPlaying || this.isPaused) return false;
        
        // 先记录当前方块的位置
        const oldPositions = this.getCurrentPiecePositions();
        
        if (!this.checkCollision(1, 0)) {
            // 先清除旧位置的绘制
            this.clearPieceFromBoard(oldPositions);
            
            // 更新方块位置
            this.currentPiece.row++;
            
            // 只有用户操作时才播放下落音效
            if (isUserAction) {
                this.playSound(this.dropSound);
            }
            this.draw();
            return true;
        }
        return false;
    }
    
    // 旋转
    rotate() {
        if (!this.isPlaying || this.isPaused) return false;
        
        // 先记录当前方块的位置
        const oldPositions = this.getCurrentPiecePositions();
        
        // 添加日志以便调试
        console.log(getText_7ree('logTryRotate')); // Use getText_7ree
        
        const rotatedShape = this.getRotatedShape();
        
        if (!this.checkCollision(0, 0, rotatedShape)) {
            // 先清除旧位置的绘制
            this.clearPieceFromBoard(oldPositions);
            
            this.currentPiece.shape = rotatedShape;
            this.playSound(this.rotateSound);
            this.draw();
            console.log(getText_7ree('logRotateSuccess')); // Use getText_7ree
            return true;
        }
        
        // 尝试踢墙旋转(贴边时尝试偏移一格再旋转)
        const kickOffsets = [
            [0, 1], [0, -1], [1, 0], [-1, 0], // 右、左、下、上
            [0, 2], [0, -2] // 更远距离尝试
        ];
        
        for (const [rowOffset, colOffset] of kickOffsets) {
            if (!this.checkCollision(rowOffset, colOffset, rotatedShape)) {
                // 先清除旧位置的绘制
                this.clearPieceFromBoard(oldPositions);
                
                this.currentPiece.row += rowOffset;
                this.currentPiece.col += colOffset;
                this.currentPiece.shape = rotatedShape;
                this.playSound(this.rotateSound);
                this.draw();
                console.log(getText_7ree('logKickRotateSuccess')); // Use getText_7ree
                return true;
            }
        }
        
        console.log(getText_7ree('logRotateFail')); // Use getText_7ree
        return false;
    }
    
    // 获取当前方块所在的位置
    getCurrentPiecePositions() {
        if (!this.currentPiece) return [];
        
        const { shape, row, col } = this.currentPiece;
        const positions = [];
        
        // 找出方块占用的所有位置
        for (let r = 0; r < shape.length; r++) {
            for (let c = 0; c < shape[r].length; c++) {
                if (shape[r][c] !== 0) {
                    const boardRow = row + r;
                    const boardCol = col + c;
                    
                    if (boardRow >= 0 && boardRow < this.rows && boardCol >= 0 && boardCol < this.cols) {
                        positions.push({
                            row: boardRow,
                            col: boardCol,
                            index: boardRow * this.cols + boardCol
                        });
                    }
                }
            }
        }
        
        // 移动设备上特别处理:找出所有可能有残影的单元格
        if (DeviceHandler_7ree && DeviceHandler_7ree.isMobile()) {
            // 获取所有活动单元格
            const activeCells = this.gameBoardElement.querySelectorAll('.cell_7ree.active_7ree');
            activeCells.forEach(cell => {
                const cellRow = parseInt(cell.dataset.row);
                const cellCol = parseInt(cell.dataset.col);
                const index = cellRow * this.cols + cellCol;
                
                // 如果这个活动单元格不在当前方块的位置列表中,添加它(可能是残影)
                if (!positions.some(pos => pos.index === index)) {
                    positions.push({
                        row: cellRow,
                        col: cellCol,
                        index: index
                    });
                }
            });
        }
        
        return positions;
    }
    
    // 从游戏面板清除指定位置的方块(用于方块移动前)
    clearPieceFromBoard(positions) {
        if (!positions || positions.length === 0) return;
        
        const cells = this.gameBoardElement.querySelectorAll('.cell_7ree');
        
        // 设置透明背景和移除活动样式
        positions.forEach(pos => {
            if (pos.index >= 0 && pos.index < cells.length) {
                const cell = cells[pos.index];
                cell.style.backgroundColor = this.colors[0]; // 透明
                cell.classList.remove('active_7ree');
                
                // 移除所有子元素(移除四角连接线)
                while (cell.firstChild) {
                    cell.removeChild(cell.firstChild);
                }
            }
        });
    }
    
    // 获取旋转后的形状(顺时针90度)
    getRotatedShape() {
        const shape = this.currentPiece.shape;
        const size = shape.length;
        const rotated = Array(size).fill().map(() => Array(size).fill(0));
        
        for (let row = 0; row < size; row++) {
            for (let col = 0; col < size; col++) {
                rotated[col][size - 1 - row] = shape[row][col];
            }
        }
        
        return rotated;
    }
    
    // 落到底(直接落到底部)
    hardDrop() {
        if (!this.isPlaying || this.isPaused) return;
        
        // 先记录当前方块的位置
        const oldPositions = this.getCurrentPiecePositions();
        
        let dropDistance = 0;
        while (!this.checkCollision(dropDistance + 1, 0)) {
            dropDistance++;
        }
        
        if (dropDistance > 0) {
            // 先清除旧位置的绘制
            this.clearPieceFromBoard(oldPositions);
            
            // 更新位置
        this.currentPiece.row += dropDistance;
        }
        
        // 使用专门的落到底音效
        this.playSound(this.harddropSound);
        
        // 立即放置方块并处理后续逻辑
        this.placePiece(true); // 传递参数表示是落到底,不播放落地音效
        const clearedLines = this.clearLines();
        if (clearedLines > 0) {
            this.playSound(this.clearSound);
            this.updateScore(clearedLines);
        }
        
        // 生成新方块
        this.currentPiece = this.nextPiece;
        this.nextPiece = this.generatePiece();
        this.drawNextPiece();
        
        if (this.checkCollision(0, 0)) {
            this.endGame();
        }
        
        this.draw();
    }
    
    // 将当前方块固定到游戏面板
    placePiece(skipLandedSound = false) {
        const { shape, row, col, color } = this.currentPiece;
        
        for (let r = 0; r < shape.length; r++) {
            for (let c = 0; c < shape[r].length; c++) {
                if (shape[r][c] !== 0) {
                    const boardRow = row + r;
                    const boardCol = col + c;
                    
                    // 确保在有效范围内
                    if (boardRow >= 0 && boardRow < this.rows && boardCol >= 0 && boardCol < this.cols) {
                        this.board[boardRow][boardCol] = color;
                    }
                }
            }
        }
        
        // 播放方块落地固定的音效,除非指定跳过(落到底时已经播放了其他音效)
        if (!skipLandedSound) {
            this.playSound(this.landedSound);
        }
    }
    
    // 清除已填满的行
    clearLines() {
        let linesCleared = 0;
        const rowsToClearIndices = [];
        
        // 1. 找出所有已填满的行
        for (let row = this.rows - 1; row >= 0; row--) {
            if (this.board[row].every(cell => cell !== 0)) {
                rowsToClearIndices.push(row);
                linesCleared++;
            }
        }
        
        // 2. 如果有需要清除的行
        if (linesCleared > 0) {
            // 立即更新统计数据和播放声音/庆祝
            this.lines += linesCleared;
            
            if (linesCleared >= 2) {
                const playComboSound = () => this.playSound('combo');
                if (typeof CelebrationManager_7ree !== 'undefined') {
                    CelebrationManager_7ree.celebrateLines(linesCleared, playComboSound);
                } else {
                    playComboSound();
                }
            } else {
                this.playSound(this.clearSound);
            }
            
            // 立即处理升级逻辑
            if (Math.floor(this.lines / 10) > Math.floor((this.lines - linesCleared) / 10)) {
                this.levelUp(); // levelUp 会处理速度和显示更新
            }
            this.updateScoreDisplay(); // 更新分数、行数、等级显示
            
            // 3. 创建粒子容器(如果不存在)
            let particlesContainer = document.querySelector('.particles-container_7ree');
            if (!particlesContainer) {
                particlesContainer = document.createElement('div');
                particlesContainer.className = 'particles-container_7ree';
                this.gameBoardElement.appendChild(particlesContainer);
            }
            
            // 4. 为每个要消除的行创建特效
            const cells = this.gameBoardElement.querySelectorAll('.cell_7ree');
            
            rowsToClearIndices.forEach((rowIndex, rowArrayIndex) => {
                // 添加水平光束效果
                const beamElement = document.createElement('div');
                beamElement.className = 'beam-horizontal_7ree';
                beamElement.style.top = `${rowIndex * 100 / this.rows}%`;
                beamElement.style.height = `${100 / this.rows}%`;
                beamElement.style.animation = `horizontal-beam_7ree 0.8s ease-out ${rowArrayIndex * 0.1}s forwards`;
                particlesContainer.appendChild(beamElement);
                
                // 为每个单元格添加效果
                for (let col = 0; col < this.cols; col++) {
                    const cellIndex = rowIndex * this.cols + col;
                    if (cells[cellIndex]) {
                        // 添加单元格清除动画类
                        cells[cellIndex].classList.add('line-clearing_7ree');
                        
                        // 获取单元格位置信息用于粒子定位
                        const cellRect = cells[cellIndex].getBoundingClientRect();
                        const gameBoardRect = this.gameBoardElement.getBoundingClientRect();
                        const cellX = cellRect.left + cellRect.width / 2 - gameBoardRect.left;
                        const cellY = cellRect.top + cellRect.height / 2 - gameBoardRect.top;
                        
                        // 添加中心光效
                        const centerGlow = document.createElement('div');
                        centerGlow.className = 'center-glow_7ree';
                        centerGlow.style.left = `${cellX}px`;
                        centerGlow.style.top = `${cellY}px`;
                        centerGlow.style.animation = `center-glow_7ree 0.8s ease-out ${rowArrayIndex * 0.1 + col * 0.02}s forwards`;
                        particlesContainer.appendChild(centerGlow);
                        
                        // 为每个单元格创建多个粒子
                        this.createParticles(particlesContainer, cellX, cellY, 10, rowArrayIndex * 0.1 + col * 0.02);
                    }
                }
            });
            
            // 5. 延迟执行实际的清除和重绘
            setTimeout(() => {
                // 创建一个新board
                const newBoard = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
                let newBoardRow = this.rows - 1;
                for (let oldRow = this.rows - 1; oldRow >= 0; oldRow--) {
                    // 如果当前行不是要清除的行,则复制到新板的对应位置
                    if (!rowsToClearIndices.includes(oldRow)) {
                        newBoard[newBoardRow] = this.board[oldRow];
                        newBoardRow--;
                    }
                }
                this.board = newBoard;
                
                // 移除动画类
                const clearingCells = this.gameBoardElement.querySelectorAll('.line-clearing_7ree');
                clearingCells.forEach(cell => cell.classList.remove('line-clearing_7ree'));
                
                // 重绘游戏面板,让上方的方块掉落
                this.draw(); 
                
                // 清理特效元素(延迟一点,确保动画完成)
                setTimeout(() => {
                    // 移除所有特效元素
                    while (particlesContainer.firstChild) {
                        particlesContainer.removeChild(particlesContainer.firstChild);
                    }
                }, 1000);
                
            }, 1000); // 延迟1秒
        }
        
        // 返回本次清除的行数
        return linesCleared;
    }
    
    // 创建粒子爆炸效果
    createParticles(container, x, y, count, delay) {
        // 增加粒子种类
        const particleColors = ['blue', 'cyan', 'purple', 'white'];
        const particleShapes = ['blue', 'cyan', 'purple', 'white', 'triangle', 'diamond'];
        const animationTypes = ['particle-explosion1_7ree', 'particle-explosion2_7ree', 'particle-explosion3_7ree'];
        
        // 增加粒子数量
        const particleCount = count * 1.5;
        
        for (let i = 0; i < particleCount; i++) {
            const particle = document.createElement('div');
            
            // 随机确定粒子特性
            const size = Math.random() * 8 + 2; // 2-10px
            // 选择粒子形状
            const shapeType = particleShapes[Math.floor(Math.random() * particleShapes.length)];
            const animationType = animationTypes[Math.floor(Math.random() * animationTypes.length)];
            
            // 随机确定粒子运动方向 - 增加发散距离
            const angle = Math.random() * Math.PI * 2; // 0-2π
            const distance = Math.random() * 100 + 30; // 30-130px
            const tx = Math.cos(angle) * distance;
            const ty = Math.sin(angle) * distance;
            
            // 随机旋转和缩放 - 增加不规则性
            const rotate = Math.random() * 360 - 180; // -180° to 180°
            const endScale = Math.random() * 0.5; // 0-0.5
            
            // 设置粒子样式
            particle.className = `particle_7ree particle-${shapeType}_7ree`;
            particle.style.width = `${size}px`;
            particle.style.height = `${size}px`;
            particle.style.left = `${x}px`;
            particle.style.top = `${y}px`;
            
            // 使用CSS变量传递动画参数
            particle.style.setProperty('--tx', `${tx}px`);
            particle.style.setProperty('--ty', `${ty}px`);
            particle.style.setProperty('--rotate', `${rotate}deg`);
            particle.style.setProperty('--scale', `${endScale}`);
            
            // 为特殊形状设置尺寸变量
            if (shapeType === 'triangle' || shapeType === 'diamond') {
                particle.style.setProperty('--size', `${size/2}px`);
            }
            
            // 设置动画,添加一点随机延迟使爆炸效果更自然
            const particleDelay = delay + Math.random() * 0.4;
            const duration = Math.random() * 0.8 + 0.8; // 0.8-1.6s
            particle.style.animation = `${animationType} ${duration}s ease-out ${particleDelay}s forwards`;
            
            // 添加到容器
            container.appendChild(particle);
        }
        
        // 添加一些更小、更快的粒子 - 增强爆炸感
        for (let i = 0; i < particleCount / 2; i++) {
            const sparkle = document.createElement('div');
            const size = Math.random() * 3 + 1; // 1-4px
            const angle = Math.random() * Math.PI * 2;
            const distance = Math.random() * 150 + 50; // 50-200px
            const tx = Math.cos(angle) * distance;
            const ty = Math.sin(angle) * distance;
            
            sparkle.className = 'particle_7ree particle-white_7ree';
            sparkle.style.width = `${size}px`;
            sparkle.style.height = `${size}px`;
            sparkle.style.left = `${x}px`;
            sparkle.style.top = `${y}px`;
            sparkle.style.setProperty('--tx', `${tx}px`);
            sparkle.style.setProperty('--ty', `${ty}px`);
            sparkle.style.setProperty('--rotate', `${Math.random() * 360}deg`);
            sparkle.style.setProperty('--scale', `0`);
            
            const sparkleDelay = delay + Math.random() * 0.2;
            const duration = Math.random() * 0.4 + 0.4; // 0.4-0.8s - 更快
            sparkle.style.animation = `particle-explosion1_7ree ${duration}s ease-out ${sparkleDelay}s forwards`;
            sparkle.style.opacity = '0.6';
            sparkle.style.filter = 'blur(0.5px)';
            
            container.appendChild(sparkle);
        }
    }
    
    // 升级
    levelUp() {
        this.level++;
        // 使用getSpeedByLevel计算新速度
        const newSpeed = this.getSpeedByLevel(this.level);
        
        // 显示升级庆祝通知
        if (typeof CelebrationManager_7ree !== 'undefined') {
            const playLevelUpSound = () => this.playSound(this.levelupSound);
            CelebrationManager_7ree.celebrateLevelUp(this.level, playLevelUpSound);
        } else {
            // 播放升级音效
            this.playSound(this.levelupSound);
        }
        
        console.log(getText_7ree('logPlayLevelUpSound')); // Use getText_7ree
        
        // 更新当前速度
        if (this.speed !== newSpeed) {
            console.log(getText_7ree('logLevelUpSpeedChange', {level: this.level, speed: this.speed, newSpeed: newSpeed})); // Use getText_7ree with placeholders
            this.speed = newSpeed;
        
        // 更新游戏循环的间隔
        clearInterval(this.gameInterval);
        this.gameInterval = setInterval(() => this.gameLoop(), this.speed);
        }
    }
    
    // 更新分数
    updateScore(linesCleared) {
        // 基础分数:每行5分
        let baseScore = linesCleared * 5;
        
        // 额外奖励分数
        let bonusScore = 0;
        switch (linesCleared) {
            case 2:
                bonusScore = 1;
                break;
            case 3:
                bonusScore = 4;
                break;
            case 4:
                bonusScore = 8;
                break;
        }
        
        this.score += baseScore + bonusScore;
        this.updateScoreDisplay();
    }
    
    // 更新分数显示
    updateScoreDisplay() {
        this.scoreElement.textContent = this.score;
        this.levelElement.textContent = this.level;
        this.linesElement.textContent = this.lines;
        
        // 更新移动端显示
        this.mobileScoreElement.textContent = this.score;
        this.mobileLevelElement.textContent = this.level;
        this.mobileLinesElement.textContent = this.lines;
    }
    
    // 更新时间显示
    updateTimeDisplay() {
        const minutes = Math.floor(this.gameTime / 60);
        const seconds = this.gameTime % 60;
        const timeText = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
        
        this.timeElement.textContent = timeText;
        this.mobileTimeElement.textContent = timeText;
    }
    
    // 绘制游戏面板
    draw() {
        // --- 幽灵方块处理 ---
        // 检查处理器是否已初始化并调用更新
        if (typeof ghostPieceHandler_7ree !== 'undefined' && ghostPieceHandler_7ree.game) {
            ghostPieceHandler_7ree.updateDisplay();
        }
        // ---------------------
        
        const cells = this.gameBoardElement.querySelectorAll('.cell_7ree');
        
        // 先标记当前活动方块的位置和颜色,避免清除和重绘之间的闪烁
        let activeCellsInfo = []; // 重命名以区分
        if (this.currentPiece) {
            const { shape, row, col, color } = this.currentPiece;
            
            for (let r = 0; r < shape.length; r++) {
                for (let c = 0; c < shape[r].length; c++) {
                    if (shape[r][c] !== 0) {
                        const boardRow = row + r;
                        const boardCol = col + c;
                        
                        // 确保在有效范围内
                        if (boardRow >= 0 && boardRow < this.rows && boardCol >= 0 && boardCol < this.cols) {
                            activeCellsInfo.push({ // 使用新名称
                                index: boardRow * this.cols + boardCol,
                                color: this.colors[color]
                            });
                        }
                    }
                }
            }
        }
        
        // 创建一个映射,标记哪些单元格是活动的
        const activeIndices = new Set(activeCellsInfo.map(cell => cell.index)); // 使用新名称
        
        // 一次性处理所有单元格,避免闪烁
        cells.forEach((cell, index) => {
            const row = parseInt(cell.dataset.row);
            const col = parseInt(cell.dataset.col);
            
            // --- 检查是否为幽灵单元格 ---
            const isGhost = cell.classList.contains('ghost_cell_7ree');
            
            // 如果是活动方块的一部分
            if (activeIndices.has(index)) {
                // 如果同时也是幽灵单元格,活动方块优先,移除 return
                // if (isGhost) return; 
                
                // 确保移除幽灵样式,让活动样式优先
                if (isGhost) {
                    cell.classList.remove('ghost_cell_7ree');
                }
                
                const activeCell = activeCellsInfo.find(ac => ac.index === index); // 使用新名称
                cell.style.backgroundColor = activeCell.color;
                cell.classList.add('active_7ree');
                cell.classList.remove('landed_7ree');
                
                // 添加四个span元素作为四角连接线
                cell.innerHTML = '';
                for (let i = 0; i < 4; i++) {
                    const span = document.createElement('span');
                    cell.appendChild(span);
                }
            }
            // 如果是已落地的方块
            else if (this.board[row][col] !== 0) {
                 // 如果同时也是幽灵单元格,幽灵样式优先
                if (isGhost) return; 
                
                cell.style.backgroundColor = '#777'; // 灰色
                cell.classList.add('landed_7ree');
                cell.classList.remove('active_7ree');
                
                // 移除所有子元素(移除四角连接线)
                while (cell.firstChild) {
                    cell.removeChild(cell.firstChild);
                }
            }
            // 空白单元格
            else {
                // 如果是幽灵单元格,样式已由CSS处理,无需额外操作
                if (isGhost) return;
                
                cell.style.backgroundColor = this.colors[0]; // 透明
                cell.classList.remove('active_7ree');
                cell.classList.remove('landed_7ree');
                
                // 移除所有子元素(移除四角连接线)
                while (cell.firstChild) {
                    cell.removeChild(cell.firstChild);
                }
            }
        });
        
        // 绘制下一个方块预览 (这个逻辑不需要改动)
        this.drawNextPiece();
    }
    
    // 绘制下一个方块预览
    drawNextPiece() {
        const previewCells = this.nextPieceElement.querySelectorAll('.preview_cell_7ree');
        
        // 清空预览区域
        previewCells.forEach(cell => {
            cell.style.backgroundColor = 'transparent';
            cell.classList.remove('active_preview_7ree'); 
            
            // 移除所有子元素(移除四角连接线)
            while (cell.firstChild) {
                cell.removeChild(cell.firstChild);
            }
        });
        
        if (this.nextPiece) {
            const { shape, color } = this.nextPiece;

            // 计算偏移量以居中方块
            let offsetRow = Math.floor((4 - shape.length) / 2);
            const offsetCol = Math.floor((4 - shape[0].length) / 2);
            
            // 特殊调整:对于 3x3 的形状 (J, L, S, T, Z),向下移动一行以改善视觉居中
            if (shape.length === 3) {
                offsetRow += 1;
            }
            
            for (let r = 0; r < shape.length; r++) {
                for (let c = 0; c < shape[r].length; c++) {
                    if (shape[r][c] !== 0) {
                        const previewRow = offsetRow + r;
                        const previewCol = offsetCol + c;
                        
                        // 确保在 4x4 网格内
                        if (previewRow >= 0 && previewRow < 4 && previewCol >= 0 && previewCol < 4) {
                            const cellIndex = previewRow * 4 + previewCol;
                        if (previewCells[cellIndex]) { 
                           previewCells[cellIndex].style.backgroundColor = this.colors[color];
                           previewCells[cellIndex].classList.add('active_preview_7ree'); 
                               
                               // 添加四个span元素作为四角连接线
                               previewCells[cellIndex].innerHTML = '';
                               for (let i = 0; i < 4; i++) {
                                   const span = document.createElement('span');
                                   previewCells[cellIndex].appendChild(span);
                               }
                            }
                        }
                    }
                }
            }
        }
    }
    
    // 暂停/继续游戏
    togglePause() {
        if (!this.isPlaying) return;
        
        this.isPaused = !this.isPaused;
        console.log(this.isPaused ? getText_7ree('logGamePaused') : getText_7ree('logGameResumed')); // Use getText_7ree
        
        if (this.isPaused) {
            // 暂停游戏
            clearInterval(this.gameInterval);
            clearInterval(this.timeInterval);
            
            // 显示暂停卡片
            if (this.pauseCardElement) {
                this.pauseCardElement.style.display = 'flex';
            }
            
            // 暂停背景音乐
            if (typeof SoundManager_7ree !== 'undefined' && !SoundManager_7ree.isMuted) {
                console.log(getText_7ree('logPauseBGM')); // Use getText_7ree
                SoundManager_7ree.stopBgm();
            }
            
            // 更新按钮显示
            if (this.pauseButton) {
                this.pauseButton.textContent = '▶️';
            }
        } else {
            // 继续游戏
            this.gameInterval = setInterval(() => this.gameLoop(), this.getSpeedByLevel(this.level));
            this.timeInterval = setInterval(() => {
                this.gameTime++;
                this.updateTimeDisplay();
            }, 1000);
            
            // 隐藏暂停卡片
            if (this.pauseCardElement) {
                this.pauseCardElement.style.display = 'none';
            }
            
            // 继续背景音乐 - 只在非静音状态才恢复
            if (typeof SoundManager_7ree !== 'undefined' && !SoundManager_7ree.isMuted) {
                console.log(getText_7ree('logResumeBGM')); // Use getText_7ree
                // 使用短延迟确保游戏状态更新后再播放音乐
                setTimeout(() => {
                    SoundManager_7ree.playBgmDirect();
                }, 100);
            }
            
            // 更新按钮显示
            if (this.pauseButton) {
                this.pauseButton.textContent = '⏸️';
            }
        }
    }
    
    // 切换音效
    toggleSound() {
        this.isSoundOn = !this.isSoundOn;
        this.soundButton.textContent = this.isSoundOn ? '🔊' : '🔇'; // 声音开/关图标
        
        // 保存到本地存储
        localStorage.setItem('tetris_sound_on_7ree', this.isSoundOn);
        
        // 与SoundManager_7ree同步
        if (typeof SoundManager_7ree !== 'undefined') {
            // 检查状态是否需要同步
            const shouldBeMuted = !this.isSoundOn;
            if (SoundManager_7ree.isMuted !== shouldBeMuted) {
                console.log(getText_7ree('logSyncSoundStateToggle') + this.isSoundOn + ", SoundManager.isMuted=" + SoundManager_7ree.isMuted + " -> " + shouldBeMuted); // Use getText_7ree
                
                // 直接设置SoundManager的isMuted属性
                SoundManager_7ree.isMuted = shouldBeMuted;
                
                // 保存到本地存储
                localStorage.setItem('tetris_muted_7ree', shouldBeMuted);
                
                // 更新声音管理器的UI
                if (typeof SoundManager_7ree.updateButtonIcon === 'function') {
                    SoundManager_7ree.updateButtonIcon();
                }
                
                // 根据新状态控制BGM
                if (shouldBeMuted) {
                    if (typeof SoundManager_7ree.stopBgm === 'function') {
                        SoundManager_7ree.stopBgm();
                    }
                } else if (this.isPlaying && !this.isPaused) {
                    if (typeof SoundManager_7ree.playBgmDirect === 'function') {
                        SoundManager_7ree.playBgmDirect();
                    }
                }
            }
        }
    }
    
    // 确保在游戏结束后BGM停止
    forceStopBGM() {
        // 使用多种方式尝试停止BGM
        if (typeof SoundManager_7ree !== 'undefined') {
            console.log(getText_7ree('logForceStopBGM')); // Use getText_7ree
            // 1. 使用标准方法
            SoundManager_7ree.stopBgm();
            
            // 2. 如果仍有BGM,直接操作BGM对象
            if (SoundManager_7ree.currentBgm) {
                console.log(getText_7ree('logBGMStillPlaying')); // Use getText_7ree
                try {
                    if (typeof SoundManager_7ree.currentBgm.pause === 'function') {
                        SoundManager_7ree.currentBgm.pause();
                        SoundManager_7ree.currentBgm.currentTime = 0;
                    }
                } catch (e) {
                    console.error(getText_7ree('logDirectBGMError'), e); // Use getText_7ree
                }
                
                // 强制清除引用
                SoundManager_7ree.currentBgm = null;
            }
            
            // 3. 尝试暂停AudioContext
            if (SoundManager_7ree.audioContext && SoundManager_7ree.audioContext.state === 'running') {
                try {
                    console.log(getText_7ree('logTryPauseAudioContext')); // Use getText_7ree
                    SoundManager_7ree.audioContext.suspend().then(() => {
                        console.log(getText_7ree('logPauseAudioContextSuccess')); // Use getText_7ree
                    }).catch(e => {
                        console.error(getText_7ree('logPauseAudioContextFail'), e); // Use getText_7ree
                    });
                } catch (e) {
                    console.error(getText_7ree('logPauseAudioContextError'), e); // Use getText_7ree
                }
            }
        }
    }
    
    // 游戏结束
    endGame() {
        console.log(getText_7ree('logEndGameStart')); // Use getText_7ree
        this.isPlaying = false;
        this.gameEnded = true;
        clearInterval(this.gameInterval);
        clearInterval(this.timeInterval);
        
        // 播放游戏结束音效
        this.playSound(this.gameoverSound);
        
        // 停止背景音乐
        this.forceStopBGM();
        
        this.startButton.textContent = '▶️'; // 变回开始图标
        this.pauseButton.disabled = true;
        this.pauseButton.textContent = '⏸️'; // 保持暂停图标
        
        // 更新结算卡片上的统计数据
        document.getElementById('final_score_7ree').textContent = this.score;
        document.getElementById('final_lines_7ree').textContent = this.lines;
        document.getElementById('final_level_7ree').textContent = this.level;
        
        // 格式化时间显示
        const minutes = Math.floor(this.gameTime / 60);
        const seconds = this.gameTime % 60;
        const timeText = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
        document.getElementById('final_time_7ree').textContent = timeText;
        
        // 更新难度显示
        if (typeof DifficultyManager_7ree !== 'undefined') {
            const difficultyName = DifficultyManager_7ree.getCurrentDifficultyDisplayName();
            document.getElementById('final_difficulty_7ree').textContent = difficultyName;
        } else {
            document.getElementById('final_difficulty_7ree').textContent = getText_7ree('unknown'); // Use getText_7ree
        }
        
        // 显示结算卡片
        const gameoverCard = document.getElementById('gameover_card_7ree');
        if (gameoverCard) {
            gameoverCard.style.display = 'flex';
            
            // 添加"重新开始"按钮事件
            const restartButton = document.getElementById('restart_game_btn_7ree');
            if (restartButton) {
                // 移除旧的事件监听器(避免重复)
                const newRestartButton = restartButton.cloneNode(true);
                restartButton.parentNode.replaceChild(newRestartButton, restartButton);
                
                // 添加新的事件监听器
                newRestartButton.addEventListener('click', () => {
                    // 隐藏结算卡片
                    gameoverCard.style.display = 'none';
                    
                    // 重新开始游戏
                    this.startGame();
                });
            }
            
            // 添加"重选难度"按钮事件
            const changeDifficultyButton = document.getElementById('change_difficulty_btn_7ree');
            if (changeDifficultyButton) {
                // 移除旧的事件监听器
                const newChangeDifficultyButton = changeDifficultyButton.cloneNode(true);
                changeDifficultyButton.parentNode.replaceChild(newChangeDifficultyButton, changeDifficultyButton);
                
                // 添加新的事件监听器 - 点击刷新页面
                newChangeDifficultyButton.addEventListener('click', () => {
                    location.reload();
                });
            }
        } else {
            // 如果找不到结算卡片元素,仍然显示传统的弹窗
            alert(getText_7ree('alertGameOverStats', {score: this.score, lines: this.lines, level: this.level})); // Use getText_7ree with placeholders
        }
    }
    
    // --- 新增:切换幽灵方块功能 ---
    toggleGhostPiece() {
        this.isGhostPieceEnabled = !this.isGhostPieceEnabled;
        console.log(getText_7ree('logToggleGhostState') + this.isGhostPieceEnabled); // Use getText_7ree
        localStorage.setItem('tetris_ghost_on_7ree', this.isGhostPieceEnabled);
        this.updateGhostButtonVisuals();
        
        // 立即更新幽灵方块显示
        if (typeof ghostPieceHandler_7ree !== 'undefined' && ghostPieceHandler_7ree.game) {
             ghostPieceHandler_7ree.updateDisplay();
        }
    }
    
    // --- 新增:更新幽灵按钮视觉效果 ---
    updateGhostButtonVisuals() {
        if (this.ghostToggleButton) {
             if (this.isGhostPieceEnabled) {
                 this.ghostToggleButton.textContent = '🔍'; // 设置为"开"的图标
                 this.ghostToggleButton.setAttribute('data-tooltip', getText_7ree('tooltipGhostOn')); // Use getText_7ree
             } else {
                 this.ghostToggleButton.textContent = '🔍︎'; // 设置为"关"的图标 (带变体选择符)
                 this.ghostToggleButton.setAttribute('data-tooltip', getText_7ree('tooltipGhostOff')); // Use getText_7ree
             }
        }
    }

    // --- 新增:显示帮助卡片 ---
    showHelpCard() {
        if (this.helpCardElement) {
            this.helpCardElement.classList.add('show_7ree');
            // 可选:暂停游戏
            if (this.isPlaying && !this.isPaused) {
                 this.togglePause();
            }
        }
    }

    // --- 新增:隐藏帮助卡片 ---
    hideHelpCard() {
        if (this.helpCardElement) {
            this.helpCardElement.classList.remove('show_7ree');
            // 可选:如果游戏因打开帮助卡片而暂停,则恢复游戏
            // 但要注意,如果游戏本来就暂停,隐藏帮助卡片不应该恢复游戏
            // 更安全的做法是只在打开帮助卡片时记录游戏状态,并在关闭时恢复
            // 目前简单处理:如果游戏是isPlaying状态且当前是暂停,则恢复
            if (this.isPlaying && this.isPaused) {
                 // 确保暂停卡片隐藏
                 if (this.pauseCardElement && this.pauseCardElement.classList.contains('show_7ree')) {
                     // 如果暂停卡片可见,说明游戏是手动暂停的,不自动恢复
                 } else {
                     // 否则,认为是打开帮助卡片导致的暂停,恢复游戏
                     this.togglePause();
                 }
            }
        }
    }
}

// 等待DOM加载完成后初始化游戏
document.addEventListener('DOMContentLoaded', () => {
    console.log(getText_7ree('logDOMLoadedInit')); // Use getText_7ree
    
    // 初始化声音管理器(优先,为游戏提供声音状态)
    if (typeof SoundManager_7ree !== 'undefined' && !SoundManager_7ree.isInitialized) {
        console.log(getText_7ree('logInitSoundManager')); // Use getText_7ree
        SoundManager_7ree.init();
    } else if (typeof SoundManager_7ree === 'undefined') {
        console.error(getText_7ree('errorSoundManagerUndefined')); // Use getText_7ree
    }
    
    // 初始化难度管理器
    if (typeof DifficultyManager_7ree !== 'undefined') {
        console.log(getText_7ree('logInitDifficultyManager')); // Use getText_7ree
        DifficultyManager_7ree.init();
    } else {
        console.warn(getText_7ree('warnDifficultyManagerUndefined')); // Use getText_7ree
    }
    
    // 初始化游戏实例
    console.log(getText_7ree('logInitGameInstance')); // Use getText_7ree
    const game = new TetrisGame_7ree();
    window.tetrisGame_7ree = game; // 将游戏实例暴露到全局,方便调试或其他模块访问
    
    // 不自动开始游戏,等待欢迎页面的开始按钮点击
    console.log(getText_7ree('logGameInitializedWaitWelcome')); // Use getText_7ree
    
    // 派发一个自定义事件,表明游戏已初始化(如果其他模块需要知道)
    // 这个事件现在也会被 ghost_piece_7ree.js 监听
    document.dispatchEvent(new CustomEvent('tetrisGameInitialized', {
        detail: { gameInstance: game }
    }));
});