// 确保在DOM加载完成后执行 window.addEventListener('DOMContentLoaded', function() { console.log('DOMContentLoaded - Joycon.js executing'); // 游戏手柄相关变量 let gamepad = null; let lastDirection = 'stop'; let isRecording = false; let isPlaying = false; let recordedActions = []; let recordingStartTime = 0; // 按键状态标志(用于检测按键按下事件) let recordButtonPressed = false; let playbackButtonPressed = false; // 获取状态元素 const status = document.getElementById('status'); // 检查浏览器是否支持游戏手柄API if (!('getGamepads' in navigator)) { status.innerHTML = '

您的浏览器不支持游戏手柄API

'; console.log('Gamepad API not supported'); return; } // 连接游戏手柄 window.addEventListener('gamepadconnected', function(e) { gamepad = e.gamepad; status.innerHTML = `

已连接游戏手柄: ${gamepad.id}

`; console.log('Gamepad connected:', gamepad); // 开始监听游戏手柄输入 requestAnimationFrame(updateGamepad); }); // 断开游戏手柄 window.addEventListener('gamepaddisconnected', function(e) { status.innerHTML = '

游戏手柄已断开连接

'; console.log('Gamepad disconnected:', e.gamepad); gamepad = null; }); // 游戏手柄输入更新函数 function updateGamepad() { if (!gamepad) { requestAnimationFrame(updateGamepad); return; } // 获取游戏手柄状态 const gamepads = navigator.getGamepads(); gamepad = gamepads[gamepad.index]; if (!gamepad) { requestAnimationFrame(updateGamepad); return; } // 处理摇杆输入 (通常是0号摇杆,左摇杆) const leftStickX = gamepad.axes[0]; const leftStickY = gamepad.axes[1]; // 处理按键输入 const buttons = gamepad.buttons; // 摇杆死区 const deadzone = 0.3; // 确定移动方向 let direction = 'stop'; if (Math.abs(leftStickX) > deadzone || Math.abs(leftStickY) > deadzone) { // 计算角度 const angle = Math.atan2(leftStickY, leftStickX) * 180 / Math.PI; // 根据角度确定方向(修复:交换前后方向,修复:使用下划线分隔的方向值) if (angle >= -22.5 && angle < 22.5) { direction = 'right'; // 右 } else if (angle >= 22.5 && angle < 67.5) { direction = 'backward_right'; // 右后 } else if (angle >= 67.5 && angle < 112.5) { direction = 'backward'; // 后 } else if (angle >= 112.5 && angle < 157.5) { direction = 'backward_left'; // 左后 } else if (angle >= 157.5 || angle < -157.5) { direction = 'left'; // 左 } else if (angle >= -157.5 && angle < -112.5) { direction = 'forward_left'; // 左前 } else if (angle >= -112.5 && angle < -67.5) { direction = 'forward'; // 前 } else if (angle >= -67.5 && angle < -22.5) { direction = 'forward_right'; // 右前 } } // 处理旋转按钮 (X键和Y键) if (buttons[2].pressed) { // X键 - 左旋转 direction = 'rotate_left'; } else if (buttons[3].pressed) { // Y键 - 右旋转 direction = 'rotate_right'; } // 处理录制按钮 (十字键上键) - 修复:检测按键按下事件 if (buttons[12].pressed) { // 十字键上键 - 录制 if (!recordButtonPressed) { recordButtonPressed = true; if (!isPlaying) { if (isRecording) { // 停止录制 isRecording = false; status.innerHTML = `

录制完成,共记录 ${recordedActions.length} 个操作

`; console.log('Recording stopped, actions:', recordedActions); } else { // 开始录制 isRecording = true; recordedActions = []; recordingStartTime = Date.now(); status.innerHTML = '

开始录制...

'; console.log('Recording started'); } } } } else { recordButtonPressed = false; } // 处理回放按钮 (十字键左键) - 修复:检测按键按下事件 if (buttons[14].pressed) { // 十字键左键 - 回放 if (!playbackButtonPressed) { playbackButtonPressed = true; if (!isRecording && !isPlaying && recordedActions.length > 0) { isPlaying = true; status.innerHTML = '

开始回放...

'; console.log('Starting playback'); // 按时间顺序回放操作 let currentTime = 0; const totalDuration = recordedActions[recordedActions.length - 1].timestamp; recordedActions.forEach((action, index) => { if (index === 0) { // 第一个操作立即执行 console.log('Executing action immediately:', action); controlMotor(action.direction); } else { // 计算与前一个操作的时间差 const prevAction = recordedActions[index - 1]; const delay = action.timestamp - prevAction.timestamp; currentTime += delay; console.log('Scheduling action:', action, 'at delay:', currentTime); setTimeout(() => { console.log('Executing action:', action); controlMotor(action.direction); }, currentTime); } }); // 回放完成后,确保发送停止请求 setTimeout(() => { console.log('Playback completed, sending stop command'); controlMotor('stop'); status.innerHTML = '

回放完成

'; console.log('Playback completed'); isPlaying = false; }, totalDuration + 2000); } } } else { playbackButtonPressed = false; } // 如果方向改变,发送控制命令 if (direction !== lastDirection) { // 如果正在录制,记录操作 if (isRecording) { const action = { direction: direction, timestamp: Date.now() - recordingStartTime }; recordedActions.push(action); } controlMotor(direction); lastDirection = direction; } // 继续监听 requestAnimationFrame(updateGamepad); } // 控制电机的函数(与control.js中的相同) function controlMotor(direction) { // 根据方向设置状态消息 if (direction === 'stop') { status.innerHTML = `

正在停止...

`; } else { let actionText = ''; switch (direction) { case 'forward': actionText = '前进'; break; case 'backward': actionText = '后退'; break; case 'left': actionText = '左移'; break; case 'right': actionText = '右移'; break; case 'rotate_left': actionText = '左旋转'; break; case 'rotate_right': actionText = '右旋转'; break; case 'forward_left': actionText = '左前移动'; break; case 'forward_right': actionText = '右前移动'; break; case 'backward_left': actionText = '左后移动'; break; case 'backward_right': actionText = '右后移动'; break; default: actionText = '移动'; break; } status.innerHTML = `

正在${actionText}...

`; } // 记录操作(如果正在录制) if (isRecording) { const timestamp = Date.now() - recordingStartTime; // 注意:这里不再重复记录,因为已经在updateGamepad中记录了 console.log('Recorded action:', { direction, timestamp }); } else { console.log('Not recording, action:', direction); } // 发送AJAX请求到后端服务器 fetch('/control', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ direction: direction }) }) .then(response => response.json()) .then(data => { if (data.status === 'success') { status.innerHTML = `

${data.message}

`; } else { status.innerHTML = `

错误: ${data.message}

`; } }) .catch(error => { status.innerHTML = `

通信错误: ${error.message}

`; }); } // 初始化 status.innerHTML = '

请连接游戏手柄...

'; console.log('Joycon.js initialized'); });