Files
InfoGenie/InfoGenie-frontend/public/smallgame/2048/controls.js
2025-09-15 19:08:47 +08:00

537 lines
17 KiB
JavaScript

// 游戏控制模块 - 处理键盘和触摸输入
class GameControls {
constructor() {
this.touchStartX = 0;
this.touchStartY = 0;
this.touchEndX = 0;
this.touchEndY = 0;
this.minSwipeDistance = 30; // 最小滑动距离
this.isGameActive = true;
this.initializeControls();
}
initializeControls() {
// 键盘控制
this.initKeyboardControls();
// 触摸控制
this.initTouchControls();
// 鼠标控制(用于电脑端测试)
this.initMouseControls();
// 防止页面滚动
this.preventScrolling();
}
initKeyboardControls() {
document.addEventListener('keydown', (e) => {
if (!this.isGameActive || !window.game2048) {
console.log('Game not ready:', { isGameActive: this.isGameActive, game2048: !!window.game2048 });
return;
}
// 防止默认行为
const preventKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'w', 'a', 's', 'd', 'W', 'A', 'S', 'D'];
if (preventKeys.includes(e.key)) {
e.preventDefault();
}
switch (e.key) {
case 'ArrowUp':
case 'w':
case 'W':
window.game2048.move('up');
break;
case 'ArrowDown':
case 's':
case 'S':
window.game2048.move('down');
break;
case 'ArrowLeft':
case 'a':
case 'A':
window.game2048.move('left');
break;
case 'ArrowRight':
case 'd':
case 'D':
window.game2048.move('right');
break;
case 'r':
case 'R':
// R键重新开始游戏
window.game2048.restart();
break;
case 'Escape':
// ESC键暂停/继续游戏
this.togglePause();
break;
}
});
}
initTouchControls() {
const gameContainer = document.querySelector('.game-container');
// 触摸开始
gameContainer.addEventListener('touchstart', (e) => {
if (!this.isGameActive) return;
e.preventDefault();
const touch = e.touches[0];
this.touchStartX = touch.clientX;
this.touchStartY = touch.clientY;
}, { passive: false });
// 触摸移动(可选:显示滑动方向提示)
gameContainer.addEventListener('touchmove', (e) => {
e.preventDefault();
}, { passive: false });
// 触摸结束
gameContainer.addEventListener('touchend', (e) => {
if (!this.isGameActive || !window.game2048) return;
e.preventDefault();
const touch = e.changedTouches[0];
this.touchEndX = touch.clientX;
this.touchEndY = touch.clientY;
this.handleSwipe();
}, { passive: false });
// 触摸取消
gameContainer.addEventListener('touchcancel', (e) => {
e.preventDefault();
this.resetTouch();
}, { passive: false });
}
initMouseControls() {
const gameContainer = document.querySelector('.game-container');
let isMouseDown = false;
let mouseStartX = 0;
let mouseStartY = 0;
// 鼠标按下
gameContainer.addEventListener('mousedown', (e) => {
if (!this.isGameActive) return;
isMouseDown = true;
mouseStartX = e.clientX;
mouseStartY = e.clientY;
e.preventDefault();
});
// 鼠标释放
gameContainer.addEventListener('mouseup', (e) => {
if (!this.isGameActive || !isMouseDown || !window.game2048) return;
isMouseDown = false;
const mouseEndX = e.clientX;
const mouseEndY = e.clientY;
// 使用鼠标坐标模拟触摸
this.touchStartX = mouseStartX;
this.touchStartY = mouseStartY;
this.touchEndX = mouseEndX;
this.touchEndY = mouseEndY;
this.handleSwipe();
e.preventDefault();
});
// 鼠标离开游戏区域
gameContainer.addEventListener('mouseleave', () => {
isMouseDown = false;
});
// 防止右键菜单
gameContainer.addEventListener('contextmenu', (e) => {
e.preventDefault();
});
}
handleSwipe() {
const deltaX = this.touchEndX - this.touchStartX;
const deltaY = this.touchEndY - this.touchStartY;
const absDeltaX = Math.abs(deltaX);
const absDeltaY = Math.abs(deltaY);
// 检查是否达到最小滑动距离
if (Math.max(absDeltaX, absDeltaY) < this.minSwipeDistance) {
this.resetTouch();
return;
}
// 确定滑动方向
let direction = null;
if (absDeltaX > absDeltaY) {
// 水平滑动
direction = deltaX > 0 ? 'right' : 'left';
} else {
// 垂直滑动
direction = deltaY > 0 ? 'down' : 'up';
}
// 执行移动
if (direction && window.game2048) {
window.game2048.move(direction);
// 添加触觉反馈(如果支持)
this.addHapticFeedback();
// 添加视觉反馈
this.addVisualFeedback(direction);
}
this.resetTouch();
}
resetTouch() {
this.touchStartX = 0;
this.touchStartY = 0;
this.touchEndX = 0;
this.touchEndY = 0;
}
addHapticFeedback() {
// 添加触觉反馈(仅在支持的设备上)
if (navigator.vibrate) {
navigator.vibrate(50); // 50ms的轻微震动
}
}
addVisualFeedback(direction) {
// 添加方向指示的视觉反馈
const gameContainer = document.querySelector('.game-container');
const feedback = document.createElement('div');
feedback.className = 'swipe-feedback';
feedback.textContent = this.getDirectionArrow(direction);
// 设置样式
feedback.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 48px;
color: rgba(255, 255, 255, 0.8);
pointer-events: none;
z-index: 1000;
animation: swipeFeedback 0.3s ease-out;
`;
gameContainer.appendChild(feedback);
// 添加动画样式(如果不存在)
if (!document.getElementById('swipe-feedback-styles')) {
const style = document.createElement('style');
style.id = 'swipe-feedback-styles';
style.textContent = `
@keyframes swipeFeedback {
0% {
opacity: 0;
transform: translate(-50%, -50%) scale(0.5);
}
50% {
opacity: 1;
transform: translate(-50%, -50%) scale(1.2);
}
100% {
opacity: 0;
transform: translate(-50%, -50%) scale(1);
}
}
`;
document.head.appendChild(style);
}
// 移除反馈元素
setTimeout(() => {
if (feedback.parentNode) {
feedback.remove();
}
}, 300);
}
getDirectionArrow(direction) {
const arrows = {
'up': '↑',
'down': '↓',
'left': '←',
'right': '→'
};
return arrows[direction] || '';
}
preventScrolling() {
// 防止页面滚动,特别是在移动设备上
document.addEventListener('touchmove', (e) => {
// 只在游戏容器内防止滚动
const gameContainer = document.querySelector('.game-container');
if (gameContainer && gameContainer.contains(e.target)) {
e.preventDefault();
}
}, { passive: false });
// 防止双击缩放
document.addEventListener('touchstart', (e) => {
if (e.touches.length > 1) {
e.preventDefault();
}
}, { passive: false });
// 防止长按选择文本
document.addEventListener('selectstart', (e) => {
const gameContainer = document.querySelector('.game-container');
if (gameContainer && gameContainer.contains(e.target)) {
e.preventDefault();
}
});
}
togglePause() {
this.isGameActive = !this.isGameActive;
const pauseOverlay = document.getElementById('pause-overlay') || this.createPauseOverlay();
if (this.isGameActive) {
pauseOverlay.style.display = 'none';
// 恢复计时器
if (window.game2048 && window.game2048.stats.startTime) {
const pausedTime = Date.now() - window.game2048.pauseStartTime;
window.game2048.stats.startTime += pausedTime;
}
} else {
pauseOverlay.style.display = 'flex';
// 记录暂停时间
if (window.game2048) {
window.game2048.pauseStartTime = Date.now();
}
}
}
createPauseOverlay() {
const overlay = document.createElement('div');
overlay.id = 'pause-overlay';
overlay.innerHTML = `
<div class="pause-content">
<h2>游戏暂停</h2>
<p>按ESC键或点击继续游戏</p>
<button class="resume-btn">继续游戏</button>
</div>
`;
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: none;
justify-content: center;
align-items: center;
z-index: 10000;
backdrop-filter: blur(5px);
`;
const pauseContent = overlay.querySelector('.pause-content');
pauseContent.style.cssText = `
background: white;
padding: 40px;
border-radius: 15px;
text-align: center;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
`;
const resumeBtn = overlay.querySelector('.resume-btn');
resumeBtn.style.cssText = `
background: linear-gradient(45deg, #4ecdc4, #44a08d);
color: white;
border: none;
padding: 12px 24px;
border-radius: 25px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
margin-top: 20px;
transition: all 0.3s ease;
`;
// 继续游戏按钮事件
resumeBtn.addEventListener('click', () => {
this.togglePause();
});
// 点击背景继续游戏
overlay.addEventListener('click', (e) => {
if (e.target === overlay) {
this.togglePause();
}
});
document.body.appendChild(overlay);
return overlay;
}
// 禁用控制(游戏结束时调用)
disable() {
this.isGameActive = false;
}
// 启用控制(游戏开始时调用)
enable() {
this.isGameActive = true;
}
// 显示控制提示
showControlHints() {
const hints = document.createElement('div');
hints.className = 'control-hints';
hints.innerHTML = `
<div class="hint-content">
<h3>操作说明</h3>
<div class="hint-section">
<h4>📱 手机操作</h4>
<p>在游戏区域滑动手指移动方块</p>
<div class="gesture-demo">
<span>👆 上滑</span>
<span>👇 下滑</span>
<span>👈 左滑</span>
<span>👉 右滑</span>
</div>
</div>
<div class="hint-section">
<h4>⌨️ 键盘操作</h4>
<div class="key-demo">
<div class="key-row">
<span class="key">↑</span>
<span class="key">W</span>
<span>上移</span>
</div>
<div class="key-row">
<span class="key">↓</span>
<span class="key">S</span>
<span>下移</span>
</div>
<div class="key-row">
<span class="key">←</span>
<span class="key">A</span>
<span>左移</span>
</div>
<div class="key-row">
<span class="key">→</span>
<span class="key">D</span>
<span>右移</span>
</div>
<div class="key-row">
<span class="key">R</span>
<span>重新开始</span>
</div>
<div class="key-row">
<span class="key">ESC</span>
<span>暂停/继续</span>
</div>
</div>
</div>
<button class="close-hints">知道了</button>
</div>
`;
// 添加样式
hints.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
backdrop-filter: blur(5px);
`;
document.body.appendChild(hints);
// 关闭按钮事件
hints.querySelector('.close-hints').addEventListener('click', () => {
hints.remove();
});
// 点击背景关闭
hints.addEventListener('click', (e) => {
if (e.target === hints) {
hints.remove();
}
});
}
}
// 创建全局控制实例
let gameControls;
// 页面加载完成后初始化控制
document.addEventListener('DOMContentLoaded', () => {
// 等待游戏对象初始化完成
const initControls = () => {
if (window.game2048) {
gameControls = new GameControls();
console.log('Game controls initialized successfully');
// 创建帮助按钮
createHelpButton();
} else {
console.log('Waiting for game2048 to initialize...');
setTimeout(initControls, 100);
}
};
initControls();
});
// 创建帮助按钮函数
function createHelpButton() {
const helpBtn = document.createElement('button');
helpBtn.textContent = '❓';
helpBtn.title = '操作说明';
helpBtn.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
border: none;
font-size: 20px;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
z-index: 1000;
transition: all 0.3s ease;
`;
helpBtn.addEventListener('click', () => {
gameControls.showControlHints();
});
helpBtn.addEventListener('mouseenter', () => {
helpBtn.style.transform = 'scale(1.1)';
});
helpBtn.addEventListener('mouseleave', () => {
helpBtn.style.transform = 'scale(1)';
});
document.body.appendChild(helpBtn);
}
// 导出控制实例
window.gameControls = gameControls;