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
554 lines (457 loc) • 21 kB
JavaScript
// 移动端特定功能和处理
// 移动端触摸操作处理器
const MobileTouchHandler_7ree = {
// 游戏实例引用
game: null,
// 长按间隔(毫秒)
longPressInterval: 100,
// 长按定时器
longPressTimers: {},
// 初始化触摸事件
init: function(gameInstance) {
this.game = gameInstance;
this.setupTouchControls();
// 增强移动端渲染性能
this.optimizeMobileRendering();
},
// 设置触摸控制
setupTouchControls: function() {
// 方向按钮的触摸控制
const leftBtn = document.getElementById('left_btn_7ree');
const rightBtn = document.getElementById('right_btn_7ree');
const downBtn = document.getElementById('down_btn_7ree');
// 旋转和落到底按钮
const rotateBtn = document.getElementById('rotate_btn_7ree');
const dropBtn = document.getElementById('drop_btn_7ree');
// --- 修改单次点击按钮的事件监听 ---
const setupSingleTapButton = (button, actionFn) => {
if (!button) return;
// 移除可能已存在的事件监听器,避免重复绑定
const newButton = button.cloneNode(true);
if (button.parentNode) {
button.parentNode.replaceChild(newButton, button);
}
newButton.addEventListener('touchstart', (e) => {
e.preventDefault();
newButton.classList.add('btn_active_7ree'); // 添加激活样式
if (this.game.isPlaying && !this.game.isPaused) {
actionFn(); // 保持touchstart时触发动作
}
}, { passive: false });
const removeActiveClass = (e) => {
e.preventDefault();
// 延迟移除激活样式,让效果更明显
setTimeout(() => {
newButton.classList.remove('btn_active_7ree');
}, 250); // 延迟增加到250毫秒
};
newButton.addEventListener('touchend', removeActiveClass);
newButton.addEventListener('touchcancel', removeActiveClass);
return newButton;
};
// 使用setupSingleTapButton为旋转和落到底按钮添加事件处理
setupSingleTapButton(rotateBtn, () => this.game.rotate());
setupSingleTapButton(dropBtn, () => this.game.hardDrop());
// 为方向按钮添加长按支持 (修改setupLongPress内部)
this.setupLongPress(leftBtn, 'moveLeft');
this.setupLongPress(rightBtn, 'moveRight');
this.setupLongPress(downBtn, 'moveDown');
// 游戏控制按钮 (开始/暂停/声音)
const startBtn = document.getElementById('start_btn_7ree');
const pauseBtn = document.getElementById('pause_btn_7ree');
const soundBtn = document.getElementById('sound_btn_7ree'); // 获取声音按钮
const ghostToggleBtn = document.getElementById('ghost_toggle_btn_7ree'); // 获取幽灵方块开关按钮
const helpBtn = document.getElementById('help_btn_7ree'); // 获取帮助按钮
// --- 使用 setupSingleTapButton 为主要控制按钮添加视觉反馈 ---
// Start/Reset Button
setupSingleTapButton(startBtn, () => {
// 游戏已经由欢迎页面开始,这里仅处理重新开始
this.game.startGame();
});
// Pause/Resume Button
setupSingleTapButton(pauseBtn, () => {
this.game.togglePause();
});
// Sound Button
setupSingleTapButton(soundBtn, () => {
if (this.game && typeof this.game.toggleSound === 'function') {
this.game.toggleSound();
}
});
// Ghost Toggle Button
setupSingleTapButton(ghostToggleBtn, () => {
if (this.game && typeof this.game.toggleGhostPiece === 'function') {
this.game.toggleGhostPiece();
}
});
// Help Button
setupSingleTapButton(helpBtn, () => {
if (this.game && typeof this.game.showHelpCard === 'function') {
this.game.showHelpCard();
}
});
// 添加手势滑动控制(可选)
this.setupSwipeControls();
},
// 优化移动端渲染性能
optimizeMobileRendering: function() {
if (!this.game) return;
// 增强移动端渲染性能,覆盖默认的clearPieceFromBoard方法
const originalClearPieceFromBoard = this.game.clearPieceFromBoard;
this.game.clearPieceFromBoard = function(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];
// 立即完全清除单元格,避免残影
if (!cell.classList.contains('landed_7ree')) {
// 先移除所有子元素(连接线)
while (cell.firstChild) {
cell.removeChild(cell.firstChild);
}
// 彻底重置单元格状态
cell.classList.remove('active_7ree');
cell.removeAttribute('style'); // 移除所有内联样式
cell.style.backgroundColor = this.colors[0]; // 设置透明背景
}
}
});
};
// 优化draw方法的性能,但不使用requestAnimationFrame以避免残影
const originalDraw = this.game.draw;
this.game.draw = function() {
// 直接调用原始方法,不延迟渲染
originalDraw.call(this);
};
console.log(getText_7ree('logMobileRenderOptimized'));
},
// 设置长按控制
setupLongPress: function(element, action) {
if (!element) return;
// 移除可能已存在的事件监听器,避免重复绑定
const newElement = element.cloneNode(true);
if (element.parentNode) {
element.parentNode.replaceChild(newElement, element);
}
// 触摸开始
newElement.addEventListener('touchstart', (e) => {
e.preventDefault();
newElement.classList.add('btn_active_7ree'); // 添加激活样式
// 立即执行一次动作
this.executeAction(action);
// 设置长按重复执行
this.longPressTimers[action] = setInterval(() => {
this.executeAction(action);
}, this.longPressInterval);
}, { passive: false });
// 触摸结束或取消时清除定时器并延迟移除样式
const endTouch = (e) => {
e.preventDefault();
// 延迟移除激活样式
setTimeout(() => {
newElement.classList.remove('btn_active_7ree');
}, 250); // 延迟增加到250毫秒
if (this.longPressTimers[action]) {
clearInterval(this.longPressTimers[action]);
this.longPressTimers[action] = null;
}
};
newElement.addEventListener('touchend', endTouch);
newElement.addEventListener('touchcancel', endTouch);
// 触摸移出元素区域时也清除 (立即清除,无需延迟)
newElement.addEventListener('touchleave', (e) => {
e.preventDefault();
newElement.classList.remove('btn_active_7ree');
if (this.longPressTimers[action]) {
clearInterval(this.longPressTimers[action]);
this.longPressTimers[action] = null;
}
});
return newElement;
},
// 执行游戏动作
executeAction: function(action) {
if (!this.game.isPlaying || this.game.isPaused) return;
switch (action) {
case 'moveLeft':
this.game.moveLeft();
break;
case 'moveRight':
this.game.moveRight();
break;
case 'moveDown':
this.game.moveDown();
break;
}
},
// 设置滑动控制(可选功能)
setupSwipeControls: function() {
const gameBoard = document.getElementById('game_board_7ree');
if (!gameBoard) return;
let touchStartX = 0;
let touchStartY = 0;
const minSwipeDistance = 30; // 最小滑动距离,小于这个距离不触发
gameBoard.addEventListener('touchstart', (e) => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
});
gameBoard.addEventListener('touchend', (e) => {
if (!this.game.isPlaying || this.game.isPaused) return;
const touchEndX = e.changedTouches[0].clientX;
const touchEndY = e.changedTouches[0].clientY;
const deltaX = touchEndX - touchStartX;
const deltaY = touchEndY - touchStartY;
// 确定是水平滑动还是垂直滑动
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// 水平滑动
if (Math.abs(deltaX) >= minSwipeDistance) {
if (deltaX > 0) {
// 向右滑动
this.game.moveRight();
} else {
// 向左滑动
this.game.moveLeft();
}
}
} else {
// 垂直滑动
if (Math.abs(deltaY) >= minSwipeDistance) {
if (deltaY > 0) {
// 向下滑动
this.game.moveDown();
} else {
// 向上滑动 - 旋转
this.game.rotate();
}
} else {
// 轻点 - 旋转
this.game.rotate();
}
}
});
}
};
// 移动端游戏界面增强器
const MobileUIEnhancer_7ree = {
game: null,
init: function(gameInstance) {
this.game = gameInstance;
// 注册视图模式变化事件监听器
document.addEventListener('viewModeChanged', this.handleViewModeChanged.bind(this));
// 监听窗口大小变化,动态调整布局
window.addEventListener('resize', this.adjustLayoutForScreenSize.bind(this));
// 如果是移动端,则应用移动端增强功能
if (DeviceHandler_7ree.isMobile()) {
this.applyMobileEnhancements();
}
// 初始调整一次
setTimeout(() => this.adjustLayoutForScreenSize(), 100);
},
// 处理视图模式变化
handleViewModeChanged: function(event) {
if (event.detail.isMobile) {
// PC端切换到移动端
this.applyMobileEnhancements();
} else {
// 移动端切换到PC端
this.removeMobileEnhancements();
}
},
// 应用移动端增强功能
applyMobileEnhancements: function() {
// 显示移动控制按钮
const mobileControls = document.querySelector('.mobile_controls_7ree');
if (mobileControls) {
mobileControls.style.display = 'flex';
}
// 显示移动端标题和数据区
const mobileTitle = document.querySelector('.mobile_title_7ree');
const mobileStats = document.querySelector('.mobile_stats_7ree');
if (mobileTitle) mobileTitle.style.display = 'block';
if (mobileStats) mobileStats.style.display = 'flex';
// 隐藏左侧状态栏
const sidebarLeft = document.querySelector('.sidebar_left_7ree');
if (sidebarLeft) {
sidebarLeft.style.display = 'none';
}
// 调整游戏面板的布局
this.adjustGameBoardForMobile();
this.adjustLayoutForScreenSize();
// 添加移动端振动反馈
this.setupVibrationFeedback();
},
// 移除移动端增强功能
removeMobileEnhancements: function() {
// 隐藏移动控制按钮
const mobileControls = document.querySelector('.mobile_controls_7ree');
if (mobileControls) {
mobileControls.style.display = 'none';
}
// 隐藏移动端标题和数据区
const mobileTitle = document.querySelector('.mobile_title_7ree');
const mobileStats = document.querySelector('.mobile_stats_7ree');
if (mobileTitle) mobileTitle.style.display = 'none';
if (mobileStats) mobileStats.style.display = 'none';
// 显示左侧状态栏
const sidebarLeft = document.querySelector('.sidebar_left_7ree');
if (sidebarLeft) {
sidebarLeft.style.display = 'flex';
}
},
// 调整游戏面板布局以适应移动端
adjustGameBoardForMobile: function() {
const gameBoard = document.getElementById('game_board_7ree');
if (!gameBoard) return;
// 调整游戏面板到合适的大小
const container = document.querySelector('.container_7ree');
const windowWidth = window.innerWidth;
// 减少边距计算,增加硬上限
const maxWidth = Math.min(windowWidth - 10, 400);
gameBoard.style.maxWidth = `${maxWidth}px`;
// 确保下一个方块预览区在合适的位置
const nextPiece = document.getElementById('next_piece_7ree');
if (nextPiece) {
nextPiece.style.width = '80px'; // 保持预览大小或按比例调整
nextPiece.style.height = '80px';
}
},
// 设置振动反馈
setupVibrationFeedback: function() {
// 检查是否支持振动API
if ('vibrate' in navigator) {
// 保存原始方法引用
const originalRotate = this.game.rotate;
const originalHardDrop = this.game.hardDrop;
const originalClearLines = this.game.clearLines;
const game = this.game; // 保存游戏引用,避免this指向问题
// 旋转时短振动
this.game.rotate = function() {
const result = originalRotate.apply(this, arguments);
if (result) {
navigator.vibrate(20);
// 确保旋转声音播放
if (typeof this.playSound === 'function') {
this.playSound(this.rotateSound);
}
}
return result;
};
// 落到底时中等振动
this.game.hardDrop = function() {
const result = originalHardDrop.apply(this, arguments);
navigator.vibrate(40);
// 确保落到底声音播放
if (typeof this.playSound === 'function') {
this.playSound(this.dropSound);
}
return result;
};
// 消除行时根据消除的行数振动
this.game.clearLines = function() {
const linesCleared = originalClearLines.apply(this, arguments);
if (linesCleared > 0) {
navigator.vibrate(linesCleared * 30);
// 确保消除行声音播放
if (typeof this.playSound === 'function' && linesCleared > 0) {
this.playSound(this.clearSound);
}
}
return linesCleared;
};
console.log(getText_7ree('logMobileVibrateSet'));
} else {
console.log(getText_7ree('logMobileVibrateNotSupported'));
}
},
// 根据屏幕大小调整整体布局
adjustLayoutForScreenSize: function() {
if (!DeviceHandler_7ree.isMobile()) return;
const windowHeight = window.innerHeight;
const windowWidth = window.innerWidth;
const container = document.querySelector('.container_7ree');
const gameBoard = document.getElementById('game_board_7ree');
const mobileTitle = document.querySelector('.mobile_title_7ree');
const mobileStats = document.querySelector('.mobile_stats_7ree');
const controlsArea = document.querySelector('.controls_7ree');
const mobileControls = document.querySelector('.mobile_controls_7ree');
// 计算可用高度
let availableHeight = windowHeight;
if (container) {
// 减去容器内边距
availableHeight -= parseInt(getComputedStyle(container).paddingTop);
availableHeight -= parseInt(getComputedStyle(container).paddingBottom);
}
if (mobileTitle) {
// 减去标题高度
availableHeight -= mobileTitle.offsetHeight;
}
if (mobileStats) {
// 减去统计区域高度
availableHeight -= mobileStats.offsetHeight;
}
if (controlsArea) {
// 减去控制区域高度
availableHeight -= controlsArea.offsetHeight;
}
if (mobileControls) {
// 减去移动控制区域高度
availableHeight -= mobileControls.offsetHeight;
}
// 减去安全边距
availableHeight -= 20;
// 计算游戏面板的最佳高度
if (gameBoard) {
// 计算宽度限制 - 减少边距计算
const maxWidth = Math.min(windowWidth - 10, windowHeight / 2); // 调整边距
const aspectRatio = 10 / 20; // 列/行 (注意: 原始是11列,确认是否是10或11)
// 根据宽高比计算高度
let boardHeight = maxWidth / aspectRatio;
// 确保高度不超过可用高度
if (boardHeight > availableHeight) {
boardHeight = availableHeight;
// 根据高度反算宽度
const boardWidth = boardHeight * aspectRatio;
gameBoard.style.width = `${boardWidth}px`;
} else {
gameBoard.style.width = `${maxWidth}px`;
}
// 确保高度也不超过CSS的最大高度限制 (vh单位)
// gameBoard.style.height = `${boardHeight}px`; // 由CSS的max-height控制更好
gameBoard.style.height = 'auto'; // 让CSS的max-height和aspect-ratio生效
}
// 调整控制按钮大小
this.adjustButtonSizeForMobile();
},
// 调整按钮大小以适应移动屏幕
adjustButtonSizeForMobile: function() {
const windowWidth = window.innerWidth;
const dirButtons = document.querySelectorAll('.direction_controls_7ree .btn_7ree');
const actionButtons = document.querySelectorAll('.action_controls_7ree .btn_7ree');
// 计算按钮大小
const buttonSize = Math.min(45, windowWidth / 8);
// 设置方向按钮大小
dirButtons.forEach(button => {
button.style.width = `${buttonSize}px`;
button.style.height = `${buttonSize}px`;
button.style.fontSize = `${buttonSize / 2.5}px`;
});
// 设置操作按钮大小
actionButtons.forEach(button => {
button.style.fontSize = `${Math.max(12, buttonSize / 3)}px`;
button.style.padding = `${Math.max(5, buttonSize / 8)}px`;
});
}
};
// 页面加载后初始化移动端特定功能
document.addEventListener('DOMContentLoaded', function() {
// 使用事件监听器等待游戏实例创建
document.addEventListener('tetrisGameInitialized', function(e) {
if (DeviceHandler_7ree.isMobile()) {
// 初始化移动端处理器
MobileTouchHandler_7ree.init(e.detail.gameInstance);
MobileUIEnhancer_7ree.init(e.detail.gameInstance);
}
});
});