249 lines
10 KiB
JavaScript
249 lines
10 KiB
JavaScript
// 确保在DOM加载完成后执行
|
||
window.addEventListener('DOMContentLoaded', function() {
|
||
console.log('DOMContentLoaded - Joycon.js executing');
|
||
|
||
// 游戏手柄相关变量
|
||
let gamepad = null;
|
||
let lastDirection = 'stop';
|
||
// 使用全局变量,与control.js和record.js保持一致
|
||
// 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 = '<p>您的浏览器不支持游戏手柄API</p>';
|
||
console.log('Gamepad API not supported');
|
||
return;
|
||
}
|
||
|
||
// 连接游戏手柄
|
||
window.addEventListener('gamepadconnected', function(e) {
|
||
gamepad = e.gamepad;
|
||
status.innerHTML = `<p>已连接游戏手柄: ${gamepad.id}</p>`;
|
||
console.log('Gamepad connected:', gamepad);
|
||
// 开始监听游戏手柄输入
|
||
requestAnimationFrame(updateGamepad);
|
||
});
|
||
|
||
// 断开游戏手柄
|
||
window.addEventListener('gamepaddisconnected', function(e) {
|
||
status.innerHTML = '<p>游戏手柄已断开连接</p>';
|
||
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 (!window.isPlaying) {
|
||
if (window.isRecording) {
|
||
// 停止录制
|
||
window.isRecording = false;
|
||
status.innerHTML = `<p>录制完成,共记录 ${window.recordedActions.length} 个操作</p>`;
|
||
console.log('Recording stopped, actions:', window.recordedActions);
|
||
} else {
|
||
// 开始录制
|
||
window.isRecording = true;
|
||
window.recordedActions = [];
|
||
window.recordingStartTime = Date.now();
|
||
status.innerHTML = '<p>开始录制...</p>';
|
||
console.log('Recording started');
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
recordButtonPressed = false;
|
||
}
|
||
|
||
// 处理回放按钮 (十字键左键) - 修复:检测按键按下事件
|
||
if (buttons[14].pressed) { // 十字键左键 - 回放
|
||
if (!playbackButtonPressed) {
|
||
playbackButtonPressed = true;
|
||
if (!window.isRecording && !window.isPlaying && window.recordedActions.length > 0) {
|
||
window.isPlaying = true;
|
||
status.innerHTML = '<p>开始回放...</p>';
|
||
console.log('Starting playback');
|
||
|
||
// 按时间顺序回放操作
|
||
let currentTime = 0;
|
||
const totalDuration = window.recordedActions[window.recordedActions.length - 1].timestamp;
|
||
|
||
window.recordedActions.forEach((action, index) => {
|
||
if (index === 0) {
|
||
// 第一个操作立即执行
|
||
console.log('Executing action immediately:', action);
|
||
controlMotor(action.direction);
|
||
} else {
|
||
// 计算与前一个操作的时间差
|
||
const prevAction = window.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 = '<p>回放完成</p>';
|
||
console.log('Playback completed');
|
||
window.isPlaying = false;
|
||
}, totalDuration + 2000);
|
||
}
|
||
}
|
||
} else {
|
||
playbackButtonPressed = false;
|
||
}
|
||
|
||
// 如果方向改变,发送控制命令
|
||
if (direction !== lastDirection) {
|
||
// 如果正在录制,记录操作
|
||
if (window.isRecording) {
|
||
const action = {
|
||
direction: direction,
|
||
timestamp: Date.now() - window.recordingStartTime
|
||
};
|
||
window.recordedActions.push(action);
|
||
}
|
||
controlMotor(direction);
|
||
lastDirection = direction;
|
||
}
|
||
|
||
// 继续监听
|
||
requestAnimationFrame(updateGamepad);
|
||
}
|
||
|
||
// 控制电机的函数(与control.js中的相同)
|
||
function controlMotor(direction) {
|
||
// 根据方向设置状态消息
|
||
if (direction === 'stop') {
|
||
status.innerHTML = `<p>正在停止...</p>`;
|
||
} 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 = `<p>正在${actionText}...</p>`;
|
||
}
|
||
|
||
// 记录操作(如果正在录制)
|
||
if (window.isRecording) {
|
||
const timestamp = Date.now() - window.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 = `<p>${data.message}</p>`;
|
||
} else {
|
||
status.innerHTML = `<p>错误: ${data.message}</p>`;
|
||
}
|
||
})
|
||
.catch(error => {
|
||
status.innerHTML = `<p>通信错误: ${error.message}</p>`;
|
||
});
|
||
}
|
||
|
||
// 初始化
|
||
status.innerHTML = '<p>请连接游戏手柄...</p>';
|
||
console.log('Joycon.js initialized');
|
||
});
|