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

397 lines (344 loc) 17.4 kB
/** * 难度管理器 - 管理游戏难度相关的功能 */ const DifficultyManager_7ree = { // 当前难度设置 currentDifficulty: 'normal', // 当前配置 settings: null, // 难度名称映射(用于显示) difficultyNames: { 'easy': '菜鸟难度', 'normal': '老手难度', 'hard': '专家难度', 'expert': '大师难度' }, /** * 初始化难度管理器 */ init: function() { // 从本地存储加载难度设置 const savedDifficulty = localStorage.getItem('tetris_difficulty_7ree'); if (savedDifficulty) { this.currentDifficulty = savedDifficulty; } // 加载难度设置 this.loadDifficultySettings(); // 更新UI上的难度显示 this.updateDifficultyDisplay(); // 监听select元素变化 this.setupSelectChangeListener(); console.log("[DifficultyManager] 初始化完成,当前难度:" + this.currentDifficulty); }, /** * 设置下拉框变更监听器 */ setupSelectChangeListener: function() { const difficultySelect = document.getElementById('difficulty_select_7ree'); if (difficultySelect) { console.log("[DifficultyManager Debug] 设置难度选择器事件监听器"); // 初始设置select的值属性,用于伪元素显示 difficultySelect.setAttribute('value', this.currentDifficulty); // 确保select的实际值与当前难度一致 difficultySelect.value = this.currentDifficulty; // 先移除可能已存在的事件监听器(避免重复) const newDiffSelect = difficultySelect.cloneNode(true); difficultySelect.parentNode.replaceChild(newDiffSelect, difficultySelect); // 为新的select元素添加事件监听器 newDiffSelect.addEventListener('change', (event) => { const newDifficulty = event.target.value; console.log("[DifficultyManager Debug] 难度选择改变:", newDifficulty); // 设置select元素的value属性,以便CSS伪元素能够显示正确的文本 newDiffSelect.setAttribute('value', newDifficulty); // 确保下拉框值与选择一致 setTimeout(() => { newDiffSelect.value = newDifficulty; console.log("[DifficultyManager] 下拉框值已更新为: " + newDifficulty); }, 50); // 更新难度设置 this.setDifficulty(newDifficulty); }); } else { console.error("[DifficultyManager Debug] 无法找到难度选择器元素"); } }, /** * 更新UI上的难度显示 */ updateDifficultyDisplay: function() { const displayName = this.getCurrentDifficultyDisplayName(); const text = getText_7ree('displayDifficulty', { difficulty: displayName }); const pcDisplay = document.getElementById('difficulty_value_pc'); const mobileDisplay = document.getElementById('difficulty_value_mobile'); const finalDisplay = document.getElementById('final_difficulty_7ree'); if (pcDisplay) pcDisplay.textContent = text; if (mobileDisplay) mobileDisplay.textContent = displayName; if (finalDisplay) finalDisplay.textContent = displayName; // 更新欢迎界面 select 的 data-text (如果存在) const selectorContainer = document.querySelector('.difficulty_selector_7ree'); if (selectorContainer) { selectorContainer.dataset.text = displayName; } // 同时更新欢迎界面 select 的 value (如果存在) const difficultySelect = document.getElementById('difficulty_select_7ree'); if (difficultySelect) { difficultySelect.value = this.currentDifficulty; difficultySelect.setAttribute('value', this.currentDifficulty); } console.log(getText_7ree('logDiffManagerInit', { difficulty: displayName })); console.log(getText_7ree('logDiffInitialStack', { layers: this.getInitialStackLayers() })); console.log(getText_7ree('logDiffSpeedFactor', { factor: this.getSpeedFactor() })); }, /** * 加载难度设置 */ loadDifficultySettings: function() { const hardcodedDefaults_7ree = { // 硬编码的最终后备默认值 defaultSpeed: 1000, initialStackLayers: 0, speedFactor: 0.9 }; let effectiveBaseSettings_7ree = { ...hardcodedDefaults_7ree }; if (typeof config !== 'undefined' && config.difficulty) { // 使用 config.difficulty 中的顶层默认值(如果存在) if (config.difficulty.defaultSpeed !== undefined) { effectiveBaseSettings_7ree.defaultSpeed = config.difficulty.defaultSpeed; } if (config.difficulty.initialStackLayers !== undefined) { effectiveBaseSettings_7ree.initialStackLayers = config.difficulty.initialStackLayers; } if (config.difficulty.speedFactor !== undefined) { effectiveBaseSettings_7ree.speedFactor = config.difficulty.speedFactor; } console.log("[DifficultyManager] Applied top-level defaults from config_system_7ree.js:", effectiveBaseSettings_7ree); } else { console.error("[DifficultyManager] 系统配置文件 config_system_7ree.js 中的 'config.difficulty' 未找到。将使用硬编码的默认基础设置。"); } let presetSpecificSettings_7ree = {}; if (typeof config !== 'undefined' && config.difficulty && config.difficulty.presets && config.difficulty.presets[this.currentDifficulty]) { presetSpecificSettings_7ree = config.difficulty.presets[this.currentDifficulty]; console.log(`[DifficultyManager] 已加载难度预设 '${this.currentDifficulty}':`, presetSpecificSettings_7ree); } else { console.warn(`[DifficultyManager] 未找到难度预设 '${this.currentDifficulty}'。难度设置可能不准确,将仅依赖基础设置和用户设置。`); } let userSpecificSettings_7ree = {}; if (typeof user_config !== 'undefined' && user_config.difficulty && Object.keys(user_config.difficulty).length > 0) { // 检查用户配置中是否有针对当前难度的特定设置,或者全局的用户难度设置 if (user_config.difficulty[this.currentDifficulty]) { userSpecificSettings_7ree = user_config.difficulty[this.currentDifficulty]; console.log(getText_7ree('logDiffLoadUserSpecificPreset', { difficulty: this.currentDifficulty }), userSpecificSettings_7ree); } else { // 如果没有针对特定难度的用户配置,则检查是否有全局的用户难度设置(例如直接在 user_config.difficulty 下的 defaultSpeed) // 但要小心,不要意外地把所有用户预设都合并进来 const globalUserSettings = {}; if (user_config.difficulty.defaultSpeed !== undefined) globalUserSettings.defaultSpeed = user_config.difficulty.defaultSpeed; if (user_config.difficulty.initialStackLayers !== undefined) globalUserSettings.initialStackLayers = user_config.difficulty.initialStackLayers; if (user_config.difficulty.speedFactor !== undefined) globalUserSettings.speedFactor = user_config.difficulty.speedFactor; if (Object.keys(globalUserSettings).length > 0) { userSpecificSettings_7ree = globalUserSettings; console.log(getText_7ree('logDiffLoadUserGlobal'), userSpecificSettings_7ree); } else { console.log(getText_7ree('logDiffLoadUserNoSpecific', { difficulty: this.currentDifficulty })); } } } else { console.log(getText_7ree('logDiffLoadUserNone')); } // 合并设置:以基础设置为起点,然后叠加上预设特定设置,最后叠加上用户特定设置。 this.settings = { ...effectiveBaseSettings_7ree, ...presetSpecificSettings_7ree, ...userSpecificSettings_7ree }; console.log(getText_7ree('logDiffManagerLoaded'), this.settings); }, /** * 设置难度级别 * @param {string} difficulty - 难度级别名称 ('easy', 'normal', 'hard', 'expert') */ setDifficulty: function(difficulty) { // 验证难度级别是否有效 if (typeof config !== 'undefined' && config.difficulty && config.difficulty.presets && config.difficulty.presets[difficulty]) { // 检查难度是否真的改变了 if (this.currentDifficulty === difficulty) { console.log("[DifficultyManager] 难度未改变,无需操作"); return false; // 难度未变,返回false } const previousDifficulty = this.currentDifficulty; this.currentDifficulty = difficulty; this.loadDifficultySettings(); // 保存到本地存储 localStorage.setItem('tetris_difficulty_7ree', difficulty); // 更新UI显示 this.updateDifficultyDisplay(); // 如果游戏实例存在且正在进行中,才询问是否重置 if (typeof window.tetrisGame_7ree !== 'undefined' && window.tetrisGame_7ree.isPlaying) { console.log("[DifficultyManager] 游戏进行中,检测到难度更改..."); if (window.confirm(getText_7ree('confirmDifficultyChange', { oldDifficulty: this.difficultyNames[previousDifficulty], newDifficulty: this.difficultyNames[this.currentDifficulty] }))) { console.log(getText_7ree('logUserConfirmRestart')); // 重置游戏并应用新设置 window.tetrisGame_7ree.resetGameWithDifficulty(this.settings); } else { console.log(getText_7ree('logUserCancelRestart')); // 用户不立即重开,恢复之前的难度设置(避免显示与实际不符) this.currentDifficulty = previousDifficulty; this.loadDifficultySettings(); localStorage.setItem('tetris_difficulty_7ree', this.currentDifficulty); this.updateDifficultyDisplay(); // 恢复UI显示 return false; // 操作被用户取消 } } else { console.log(getText_7ree('logDiffGameNotPlaying')); // 如果游戏未开始,不需要执行重置,startGame时会处理 } console.log(getText_7ree('logDiffSetSuccess', { difficulty: difficulty })); return true; } else { console.error(getText_7ree('errorInvalidDifficulty', { difficulty: difficulty })); return false; } }, /** * 获取当前速度因子 * @returns {number} 速度因子 */ getSpeedFactor: function() { return this.settings.speedFactor; }, /** * 获取默认下落速度 * @returns {number} 默认下落速度(毫秒) */ getDefaultSpeed: function() { return this.settings.defaultSpeed; }, /** * 获取初始叠加方块层数 * @returns {number} 初始叠加方块层数 */ getInitialStackLayers: function() { return this.settings.initialStackLayers; }, /** * 根据等级计算下落速度 * @param {number} level - 当前游戏等级 * @returns {number} 计算后的下落速度(毫秒) */ calculateSpeedByLevel: function(level) { // 使用指数减速,每升一级减少按speedFactor比例 return Math.floor(this.settings.defaultSpeed * Math.pow(this.settings.speedFactor, level - 1)); }, /** * 创建初始叠加方块 * @param {object} gameBoard - 游戏面板二维数组 * @param {number} cols - 游戏面板列数 * @param {number} rows - 游戏面板行数 * @returns {object} 修改后的游戏面板 */ createInitialStack: function(gameBoard, cols, rows) { const layers = this.settings.initialStackLayers; // 如果没有初始叠加层,直接返回原面板 if (layers <= 0) { return gameBoard; } // 创建指定层数的初始方块 for (let layer = 0; layer < layers; layer++) { const rowIndex = rows - 1 - layer; if (rowIndex < 0) break; // 防止溢出 // 根据难度层级创建不同的方块分布 let emptySpaces = 0; // 跟踪当前行的空位数量 // 预先计算每行至少需要的空位数 let minEmptySpaces; switch (this.currentDifficulty) { case 'expert': minEmptySpaces = Math.max(3, Math.floor(cols * 0.3)); // 至少3个空位或30%的列数 break; case 'hard': minEmptySpaces = Math.max(2, Math.floor(cols * 0.2)); // 至少2个空位或20%的列数 break; default: minEmptySpaces = Math.max(1, Math.floor(cols * 0.1)); // 至少1个空位或10%的列数 } // 为每行创建方块 for (let col = 0; col < cols; col++) { // 随机决定是否放置方块,难度越高空隙越多(更不规则的形状) let emptyThreshold; switch (this.currentDifficulty) { case 'expert': emptyThreshold = 0.4; // 40%的空隙 break; case 'hard': emptyThreshold = 0.3; // 30%的空隙 break; default: emptyThreshold = 0.2; // 20%的空隙 } // 如果已经接近行尾,且尚未创建足够的空位,强制创建空位 if (col >= cols - (minEmptySpaces - emptySpaces) && emptySpaces < minEmptySpaces) { // 不放方块,留空 emptySpaces++; continue; } if (Math.random() < emptyThreshold) { // 留空 emptySpaces++; } else { // 放置一个随机颜色的方块 const colorIndex = Math.floor(Math.random() * 7) + 1; // 1-7之间的随机颜色 gameBoard[rowIndex][col] = colorIndex; } } // 如果整行都满了,强制添加随机空位 if (emptySpaces === 0) { console.log(getText_7ree('logDiffRandomGap')); for (let i = 0; i < minEmptySpaces; i++) { const randomCol = Math.floor(Math.random() * cols); gameBoard[rowIndex][randomCol] = 0; // 清空随机位置 } } } return gameBoard; }, /** * 获取所有可用的难度预设 * @returns {object} 难度预设对象 */ getAvailablePresets: function() { if (typeof config !== 'undefined' && config.difficulty && config.difficulty.presets) { return config.difficulty.presets; } return { easy: { defaultSpeed: 1200, initialStackLayers: 0, speedFactor: 0.95 }, normal: { defaultSpeed: 1000, initialStackLayers: 0, speedFactor: 0.9 }, hard: { defaultSpeed: 800, initialStackLayers: 3, speedFactor: 0.85 }, expert: { defaultSpeed: 600, initialStackLayers: 5, speedFactor: 0.8 } }; }, /** * 获取当前难度名称 * @returns {string} 当前难度名称 */ getCurrentDifficultyName: function() { return this.currentDifficulty; }, /** * 获取当前难度的显示名称(中文) * @returns {string} 当前难度的显示名称 */ getCurrentDifficultyDisplayName: function() { switch(this.currentDifficulty) { case 'easy': return getText_7ree('diffEasy'); case 'normal': return getText_7ree('diffNormal'); case 'hard': return getText_7ree('diffHard'); case 'expert': return getText_7ree('diffExpert'); default: return this.currentDifficulty; } } }; // 文档加载完成后自动初始化 document.addEventListener('DOMContentLoaded', function() { // DifficultyManager_7ree.init(); // Initialization moved to tetris_7ree.js });