如何通过XMLHttpRequest实现同棋盘尺寸的游戏玩家匹配?
解决方案:基于XMLHttpRequest实现同尺寸棋盘玩家匹配与游戏同步
一、先修正join方法的异步问题
你当前的join用了同步请求(xhr.open第三个参数为false),会阻塞浏览器线程,建议改成异步,并补充请求头和错误处理:
// 全局存储当前游戏ID,供后续操作使用 let currentGameId = null; let pollInterval = null; function join(size) { const joinData = { 'group': user.group, 'nick': user.username, 'password': user.password, 'size': size }; const xhr = new XMLHttpRequest(); console.log("JOIN"); xhr.open("POST", url + '/join', true); // 必须设置请求头,确保服务器能解析JSON格式的请求体 xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { console.log("JOIN OK"); const response = JSON.parse(xhr.responseText); currentGameId = response.gameId; // 拿到gameId后启动后续匹配监听流程 startGamePolling(currentGameId); } else { console.error("JOIN FAILED", xhr.statusText); // 给用户显示错误提示,比如"加入游戏失败,请重试" showGameError('加入游戏失败,请检查输入或重试'); } } }; xhr.send(JSON.stringify(joinData)); }
二、轮询监听游戏匹配状态
拿到gameId后,需要定期向服务器查询游戏是否已凑齐2名玩家,这是XMLHttpRequest下实现"等待匹配"的核心方式:
function startGamePolling(gameId) { // 显示等待界面,比如"正在寻找同尺寸的玩家..." showWaitingUI(); // 每秒查询一次游戏状态 pollInterval = setInterval(() => { checkGameStatus(gameId); }, 1000); } function checkGameStatus(gameId) { const xhr = new XMLHttpRequest(); xhr.open("GET", url + `/game/status/${gameId}`, true); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { const gameStatus = JSON.parse(xhr.responseText); // 检查是否已有2名玩家加入 if (gameStatus.players.length === 2) { // 匹配成功,停止轮询,初始化游戏棋盘 clearInterval(pollInterval); initGameBoard(gameStatus); } else { // 继续等待,可更新UI提示"等待另一名玩家加入..." updateWaitingText(); } } else if (xhr.readyState === 4 && xhr.status !== 200) { // 请求失败,停止轮询并提示 clearInterval(pollInterval); showGameError('获取游戏状态失败,请重新加入'); } }; xhr.send(); }
三、游戏内操作同步
当两名玩家都进入游戏后,所有棋盘操作(比如落子)都需要通过gameId同步到服务器,同时继续轮询获取最新状态更新UI:
// 玩家落子时调用 function makeMove(position) { if (!currentGameId) return; const moveData = { gameId: currentGameId, playerNick: user.username, position: position // 比如{x: 2, y: 3} }; const xhr = new XMLHttpRequest(); xhr.open("POST", url + '/game/move', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { // 落子成功,立即刷新游戏状态 checkGameStatus(currentGameId); } else if (xhr.readyState === 4) { showGameError('落子失败,请重试'); } }; xhr.send(JSON.stringify(moveData)); } // 初始化游戏棋盘,渲染状态 function initGameBoard(gameStatus) { // 隐藏等待界面,显示棋盘 hideWaitingUI(); // 根据gameStatus渲染初始棋盘、玩家信息等 renderBoard(gameStatus.board); renderPlayerInfo(gameStatus.players); }
四、清理与异常处理
在游戏结束、玩家退出或发生错误时,需要清理定时器,避免无效请求:
// 退出游戏时调用 function exitGame() { if (pollInterval) { clearInterval(pollInterval); pollInterval = null; } currentGameId = null; // 重置UI到初始状态 resetGameUI(); }
内容的提问来源于stack exchange,提问作者miguelcgo
相关产品推荐
相关产品推荐

