当前位置: 首页 > wzjs >正文

加强意识形态建设 办好政协网站谷歌google中文登录入口

加强意识形态建设 办好政协网站,谷歌google中文登录入口,网页编辑用户信息原理,pageadmin安装教程目录 GameHandler 创建请求响应对象 处理连接成功 玩家下线处理 处理落子请求 handleTextMessage putChess 落子 胜负判定 构造落子响应并返回 更新玩家分数 修改客户端代码 对战模块测试 在本篇文章中,我们继续实现对战模块的后端逻辑 GameHandler…

目录

GameHandler

创建请求响应对象

处理连接成功

玩家下线处理

处理落子请求

handleTextMessage

putChess

落子 

胜负判定 

构造落子响应并返回

更新玩家分数

修改客户端代码

对战模块测试


在本篇文章中,我们继续实现对战模块的后端逻辑

GameHandler

我们创建 GameHandler 处理 WebSocket 请求

@Component
@Slf4j
public class GameHandler extends TextWebSocketHandler {@Autowiredprivate OnlineUserManager onlineUserManager;@Autowiredprivate RoomManager roomManager;/*** 连接建立(游戏准备)* @param session* @throws Exception*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {}/*** 处理落子请求* @param session* @param message* @throws Exception*/@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {}/*** 处理异常情况* @param session* @param exception* @throws Exception*/@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {}/*** 连接关闭* @param session* @param status* @throws Exception*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {}}

并注入 RoomManager OnlineUserManager 

修改 WebSocketConfig 将 GameHandler 进行注册

@EnableWebSocket
@Configuration
public class WebSocketConfig implements WebSocketConfigurer {@Autowiredprivate MatchHandler matchHandler;@Autowiredprivate GameHandler gameHandler;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(matchHandler, "/findMatch").addInterceptors(new HttpSessionHandshakeInterceptor()); // 添加拦截器registry.addHandler(gameHandler, "/game").addInterceptors(new HttpSessionHandshakeInterceptor());}
}

根据约定的前后端交互接口创建请求/响应对象

创建请求响应对象

落子请求 PutChessParam

@Data
public class PutChessParam implements Serializable {/*** 落子玩家 id*/private Long userId;/*** 落子位置——行*/private Integer row;/*** 落子位置——列*/private Integer col;
}

落子响应 MatchResult

@Data
public class MatchResult implements Serializable {/*** 匹配结果*/private String matchMessage;private Rival rival;@Datapublic static class Rival {/*** 对手姓名*/private String name;/*** 天梯分数*/private Long score;}public MatchResult() {}public MatchResult(String matchMessage) {this.matchMessage = matchMessage;}
}

游戏就绪响应 GameReadyResult

@Data
public class GameReadyResult implements Serializable {/*** 房间号*/private String roomId;/*** 玩家 id*/private Long thisUserId;/*** 对手 id*/private Long thatUserId;/*** 先手 id*/private Long whiteUserId;
}

 

处理连接成功

游戏房间 WebSocket 连接建立之后(afterConnectionEstablished)需要实现的业务逻辑:

1. 从 session 中获取登录时存储的用户信息(UserInfo),检查用户的登录情况

2. 通过 OnlineUserManager 进行多开判定

3. 判断当前玩家是否在游戏房间中

4. 将两个玩家放到对应的房间对象中,当两个玩家都建立了连接时,这个房间就满了,此时就可以通知双方准备就绪

5. 若有更多玩家尝试加入房间,提示游戏房间已满

    @Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {// 从 session 中获取用户信息UserInfo userInfo = (UserInfo) session.getAttributes().get(USER_INFO);// 用户是否登录if (null == userInfo) {session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.noLogin())));return;}// 判断用户是否处于在线状态if (null != onlineUserManager.getFromHall(userInfo.getUserId())) {session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.repeatConnection())));return;}// 获取游戏房间, 判断当前玩家是否在游戏房间中Room room = roomManager.getRoomByUserId(userInfo.getUserId());if (null == room) {session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.fail(HandlerErrorCodeConstants.GET_GAME_ROOM_ERROR))));return;}// 将用户设置为在线状态onlineUserManager.enterGameRoom(userInfo.getUserId(), session);// 将玩家加入到游戏房间(加锁)synchronized (room) {// 第一个玩家是否加入游戏房间if (null == room.getUser1()) {room.setUser1(userInfo);// 默认玩家1 作为先手room.setWhiteUserId(userInfo.getUserId());log.info("房间 {} 玩家1 {} 已就绪", room.getRoomId(), userInfo.getUserName());return;}// 第二个玩家是否加入游戏房间if (null == room.getUser2()) {room.setUser2(userInfo);log.info("房间 {} 玩家2 {} 已就绪", room.getRoomId(), userInfo.getUserName());// 通知玩家1 和 玩家2 游戏已就绪notifyGameReady(room, room.getUser1(), room.getUser2());notifyGameReady(room, room.getUser2(), room.getUser1());return;}}// 还有玩家尝试进入同一房间,提示房间已满// 理论上不会出现该情况,为了让程序更加的健壮, 还是进行判定和提示session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.fail(HandlerErrorCodeConstants.GAME_ROOM_IS_FULL))));// 日志打印log.info("玩家 {} 进入游戏房间", userInfo.getUserName());}

在将玩家加入游戏房间时,我们需要考虑到线程安全问题

若两个玩家同时与 WebSocket 建立连接,那么,在将玩家加入游戏房间时, 就很可能都判定 玩家1 为空,从而将其都设置为玩家1

因此,我们需要对 玩家加入游戏房间操作 进行加锁(可以直接对 Room 对象进行加锁)

 添加错误码:

public interface HandlerErrorCodeConstants {ErrorCode GET_GAME_ROOM_ERROR = new ErrorCode(300, "用户尚未匹配到游戏房间");ErrorCode GAME_ROOM_IS_FULL = new ErrorCode(301, "游戏房间已满");
}

实现通知玩家就绪 notifyGameReady 方法:

    /*** 通知玩家游戏已准备就绪* @param room 游戏房间* @param thisUser 玩家* @param thatUser 对手*/private void notifyGameReady(Room room, UserInfo thisUser, UserInfo thatUser) {try {// 构造游戏就绪响应GameReadyResult gameReadyResult = new GameReadyResult();gameReadyResult.setRoomId(room.getRoomId());gameReadyResult.setThisUserId(thisUser.getUserId());gameReadyResult.setThatUserId(thatUser.getUserId());gameReadyResult.setWhiteUserId(room.getWhiteUserId());// 发送游戏就绪响应WebSocketSession session = onlineUserManager.getFromRoom(thisUser.getUserId());session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.success(gameReadyResult))));} catch (Exception e) {log.warn("notifyGameReady 通知玩家游戏准备就绪异常 e: ", e);}}

接下来,我们先实现 连接关闭 和 异常关闭 的相关逻辑,最后再实现对落子请求的处理

玩家下线处理

我们实现 logoutFromRoom 方法,来对玩家下线进行处理:

1. 获取用户信息,判断用户是否登录

2. 获取游戏房间中存储的玩家信息,针对多开情况进行处理

3. 当玩家掉线时,此时对手直接胜利

4. 通知玩家对手胜利,并修改对应玩家分数

    /*** 退出游戏房间* @param session*/private void logoutFromRoom(WebSocketSession session) {// 获取用户信息UserInfo userInfo = (UserInfo) session.getAttributes().get(USER_INFO);// 判断用户是否登录if (null == userInfo) {return;}// 获取游戏房间中存储的玩家信息WebSocketSession onlineSession = onlineUserManager.getFromRoom(userInfo.getUserId());// 多开情况,直接退出if (session != onlineSession) {return;}// 玩家下线onlineUserManager.exitGameRoom(userInfo.getUserId());// 当前玩家下线,对手胜利notifyThatUserWin(userInfo);log.info("玩家 {} 从游戏房间退出", userInfo.getUserName());}

我们继续实现通知玩家对手胜利 notifyThatUserWin 方法:

要通知对手,我们首先需要查询到对手的相关 session 信息:

1. 查询玩家所在游戏房间

2. 判断游戏房间是否已经被销毁(表明此时游戏已经结束,或对手已经下线)

3. 判断对手是否下线

4. 为对手玩家返回响应

5. 销毁房间

6. 更新玩家分数

    /*** 通知对手胜利* @param userInfo*/private void notifyThatUserWin(UserInfo userInfo) {try {// 查找玩家下线所在房间Room room = roomManager.getRoomByUserId(userInfo.getUserId());// 判断游戏房间是否已经销毁if (null == room) {return;}// 判断对手是否已经下线UserInfo thatUser = (room.getUser1() == userInfo) ?room.getUser2() : room.getUser1();if (null == thatUser) {return;}// 对手会话是否存在WebSocketSession thatUserSession = onlineUserManager.getFromRoom(thatUser.getUserId());if (null == thatUserSession) {return;}// 返回响应PutChessResult result = new PutChessResult();result.setUserId(thatUser.getUserId());result.setRow(-1);result.setCol(-1);result.setWinner(thatUser.getUserId());thatUserSession.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.success(result))));log.info("房间{} 玩家 {} 胜利!", room.getRoomId(), thatUser.getUserId());// 销毁游戏房间roomManager.remove(room.getRoomId(), room.getUser1().getUserId(), room.getUser2().getUserId());// TODO 更新玩家分数} catch (IOException e) {log.warn("通知玩家下线异常 e: ", e);} catch (Exception e) {log.warn("玩家下线异常 e: ", e);}}

关于玩家分数的更新,我们后续再进行实现

异常情况处理:

    @Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {// 打印错误信息log.error("游戏过程中出现异常: ", exception);logoutFromRoom(session);}

连接关闭:

    @Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {log.info("游戏连接断开, code: {}, reason: {}",status.getCode(), status.getReason());// 玩家下线logoutFromRoom(session);}

接下来,我们就可以处理落子请求了

处理落子请求

handleTextMessage

handleTextMessage 主要用于接收落子请求并对其进行处理:

1. 判断用户是否登录

2. 获取游戏房间,判断游戏房间是否存在

3. 将接收到的数据转化为 PutChessParam 对象

4. 根据请求进行落子

关于落子相关逻辑,我们定义 GameService,并创建 putChess 方法来进行处理

    @Autowiredprivate GameService gameService;@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {UserInfo userInfo = (UserInfo) session.getAttributes().get(USER_INFO);// 用户是否登录if (null == userInfo) {session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.noLogin())));return;}// 获取游戏房间Room room = roomManager.getRoomByUserId(userInfo.getUserId());if (null == room) {session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.fail(HandlerErrorCodeConstants.GET_GAME_ROOM_ERROR))));}// 获取用户端发送的数据String payload = message.getPayload();// 将 JSON 字符串转化为 java 对象PutChessParam putChessParam = JacksonUtil.readValue(payload, PutChessParam.class);// 根据请求落子gameService.putChess(putChessParam, userInfo);}

GameService 接口:

@Service
public interface GameService {/*** 处理落子请求* @param param* @param userInfo*/void putChess(PutChessParam param, UserInfo userInfo);
}

在 GameServiceImpl 中实现具体逻辑:

@Service
@Slf4j
public class GameServiceImpl implements GameService {@Autowiredprivate RoomManager roomManager;@Autowiredprivate OnlineUserManager onlineUserManager;/*** 处理落子请求* @param param* @param userInfo*/@Overridepublic void putChess(PutChessParam param, UserInfo userInfo) {}

 

putChess

putChess 需要实现的业务逻辑:

1. 获取玩家所在游戏房间对象

2. 判断当前玩家是 玩家1 还是 玩家2

3. 从请求参数中获取落子位置

4. 判断当前位置是否有子

5. 若无,则落子

6. 进行胜负判定

7. 通知双方玩家落子结果

8. 若胜负已分,则更新相关分数,并销毁游戏房间

落子 

 我们先实现前四个部分相关逻辑:

    @Overridepublic void putChess(PutChessParam param, UserInfo userInfo) {try {// 获取游戏房间Room room = roomManager.getRoomByUserId(userInfo.getUserId());// 判断当前玩家是 玩家1 还是 玩家2int chess = userInfo.getUserId() == room.getUser1().getUserId()? 1 : 2;// 获取落子位置int row = param.getRow();int col = param.getCol();// 判断当前位置是否已经有子if (!room.isEmpty(row, col)) {log.info("已禁止 玩家 {} 在 {} 行 {} 列重复落子!",userInfo.getUserName(), row, col);return;}// 落子room.putChess(row, col, chess);// 打印棋盘信息,方便观察落子情况room.printBoard();}

在对应位置落子需要对 room 对象中 board 的进行修改,因此,我们在 Room 中提供对应方法:

    /*** 判断当前位置是否已经有子* @param row* @param col* @return*/public boolean isEmpty(int row, int col) {return board[row][col] == 0;}/*** 在当前位置落子* @param row* @param col* @param chess*/public void putChess(int row, int col, int chess) {board[row][col] = chess;piecesNumber++;}

为了方便观察落子请求,我们可以对棋盘进行打印,观察落子结果:

    /*** 打印棋盘*/public void printBoard() {System.out.println("------------------棋盘-----------------------");for (int i = 0; i < MAX_ROW; i++) {for (int j = 0; j < MAX_COL; j++) {System.out.print(board[i][j] + " ");}System.out.println();}System.out.println("------------------棋盘-----------------------");}

 

胜负判定 

落子成功后,我们进行胜负判定:

            // 进行胜负判断Long winner = room.checkWinner(row, col, chess);

若玩家1胜利,则返回玩家1 id;

若玩家2 胜利,则返回玩家2 id;

若为平局,则返回 -1;

若未决出胜负,则返回 0 

我们在每次落下棋子之后,进行胜负判定,也就是判定棋盘上形成连续的五个同色棋子(可以是横排、竖排 或 斜排

在进行判定时,我们并不需要遍历整个棋盘,只需要考虑新落棋子周围位置

若还未落子就已经出现了 连续五个同色棋子 的情况,则说明前面的判定出现了异常

因此,我们只需要以 (row, col) 为中心,判定其是否与周围棋子形成 五个同色棋子

我们首先来考虑 横排:

此时,需要考虑新落的子(x)能否与当前行周围棋子形成五个同色棋子:

新落棋子为 x

判定 x 与 左边 4 个棋子 是否为同色棋子

同理:

判定 x 与 左边 3 个棋子,右边 1 个棋子是否为同色棋子

判定 x 与 左边 2 个棋子,右边 2 个棋子是否为同色棋子

判定 x 与 左边 1 个棋子,右边 3 个棋子是否为同色棋子

判定 x 与 右边 4 个棋子是否为同色棋子

我们通过 for 循环来进行判定:

        // 行for (int c = col - 4; c <= col; c++) {try {if(board[row][c] == chess&& board[row][c + 1] == chess&& board[row][c + 2] == chess&& board[row][c + 3] == chess&& board[row][c + 4] == chess) {return chess == user1.getUserId() ?user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {continue;}}

在判定过程中可能会出现数组越界的异常情况,我们捕获 数组越界异常,并继续判定

我们继续看竖排:

需要判定:

 x 与 上方 4 个棋子 是否为同色棋子

 x 与 上方 3 个棋子,下方 1 个棋子是否为同色棋子

 x 与 上方 2 个棋子,下方 2 个棋子是否为同色棋子

 x 与 上方 1 个棋子,下方 3 个棋子是否为同色棋子

 x 与 下方 4 个棋子是否为同色棋子

        // 列for (int r = row - 4; r <= row; r++) {try {if(board[r][col] == chess&& board[r + 1][col] == chess&& board[r + 2][col] == chess&& board[r + 3][col] == chess&& board[r + 4][col] == chess) {return chess == 1 ?user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {// 若出现数据下标越界的情况,则继续判断continue;}}

再来看斜方:

 

 左对角线 和 右对角线 都需要进行判定:

        // 左对角线for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {try {if(board[r][c] == chess&& board[r + 1][c + 1] == chess&& board[r + 2][c + 2] == chess&& board[r + 3][c + 3] == chess&& board[r + 4][c + 4] == chess) {return chess == 1 ? user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {continue;}}// 右对角线for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {try {if(board[r][c] == chess&& board[r + 1][c - 1] == chess&& board[r + 2][c - 2] == chess&& board[r + 3][c - 3] == chess&& board[r + 4][c - 4] == chess) {return chess == 1 ? user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {continue;}}

此外,若未决出胜负,但此时棋盘已满,则为平局:

        if(piecesNumber >= MAX_ROW * MAX_COL) {return -1L;}

判断落子数量是否已达到最大数量

若以上情况都不满足,则表明当前未决出胜负,还需继续落子,因此返回 0

胜负判断完整代码:

    /*** 判断胜负* @param row* @param col* @param chess* @return 0:尚未分出胜负 -1:平局*/public Long checkWinner(int row, int col, int chess) {// 行for (int c = col - 4; c <= col; c++) {try {if(board[row][c] == chess&& board[row][c + 1] == chess&& board[row][c + 2] == chess&& board[row][c + 3] == chess&& board[row][c + 4] == chess) {return chess == user1.getUserId() ?user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {continue;}}// 列for (int r = row - 4; r <= row; r++) {try {if(board[r][col] == chess&& board[r + 1][col] == chess&& board[r + 2][col] == chess&& board[r + 3][col] == chess&& board[r + 4][col] == chess) {return chess == 1 ?user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {// 若出现数据下标越界的情况,则继续判断continue;}}// 左对角线for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {try {if(board[r][c] == chess&& board[r + 1][c + 1] == chess&& board[r + 2][c + 2] == chess&& board[r + 3][c + 3] == chess&& board[r + 4][c + 4] == chess) {return chess == 1 ? user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {continue;}}// 右对角线for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {try {if(board[r][c] == chess&& board[r + 1][c - 1] == chess&& board[r + 2][c - 2] == chess&& board[r + 3][c - 3] == chess&& board[r + 4][c - 4] == chess) {return chess == 1 ? user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {continue;}}// 平局if(piecesNumber == MAX_ROW * MAX_COL) {return -1L;}piecesNumber++;return 0L;}

构造落子响应并返回

接着,需要构造落子响应并返回:

1. 获取 session1 和 session2

2. 判断是否存在玩家掉线的情况:若双方玩家均掉线,则结果设置为平局;若玩家1掉线,则玩家2胜利;若玩家2掉线,则玩家1胜利

3. 构造响应并返回

            // 通知玩家WebSocketSession session1 = onlineUserManager.getFromRoom(room.getUser1().getUserId());WebSocketSession session2 = onlineUserManager.getFromRoom(room.getUser2().getUserId());if (null == session1 && null == session2) {// 玩家均掉线winner = -1L;log.info("游戏房间 {} 玩家1 和 玩家2 均掉线", room.getRoomId());} else if (null == session1) {winner = room.getUser2().getUserId();log.info("游戏房间 {} 玩家1 掉线", room.getRoomId());} else if (null == session2){winner = room.getUser1().getUserId();log.info("游戏房间 {} 玩家2 掉线", room.getRoomId());}// 构造响应并返回PutChessResult result = new PutChessResult(userInfo.getUserId(), row, col, winner);if (null != session1) {session1.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.success(result))));}if (null != session2) {session2.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.success(result))));}

判断胜负是否已分,若胜负已分,则更新玩家分数,并销毁游戏房间

            // 若胜负已分,则更新玩家分数,并销毁房间if (winner != 0) {if (winner == -1) {log.info("房间 {} 游戏结束, 结果为平局");} else {log.info("房间 {} 游戏结束, 获胜方id为 {}", room.getRoomId(), winner);// TODO 更新分数}// 销毁游戏房间roomManager.remove(room.getRoomId(),room.getUser1().getUserId(), room.getUser2().getUserId());}

 

更新玩家分数

创建 updateScore 接口,更新玩家分数:

@Service
public interface GameService {/*** 处理落子请求* @param param* @param userInfo*/void putChess(PutChessParam param, UserInfo userInfo);/*** 更新玩家分数* @param winner* @param loser*/void updateScore(Long winner, Long loser);
}

调用 UserMapper 相关方法,更新分数: 

    @Autowiredprivate UserMapper userMapper;@Overridepublic void updateScore(Long winner, Long loser) {userMapper.updateWinner(winner);userMapper.updateLoser(loser);}

UserMapper

    @Update("update user set total_count = total_count + 1, win_count = win_count + 1, score = score + 30 " +" where id = #{id}")int updateWinner(@Param("id") Long winner);@Update("update user set total_count = total_count + 1, score = score - 30 " +" where id = #{id}")int updateLoser(@Param("id") Long loser);

 更新分数:

putchess 完整代码:

    /*** 处理落子请求* @param param* @param userInfo*/@Overridepublic void putChess(PutChessParam param, UserInfo userInfo) {try {// 获取游戏房间Room room = roomManager.getRoomByUserId(userInfo.getUserId());// 判断当前玩家是 玩家1 还是 玩家2int chess = userInfo.getUserId() == room.getUser1().getUserId()? 1 : 2;// 获取落子位置int row = param.getRow();int col = param.getCol();// 判断当前位置是否已经有子if (!room.isEmpty(row, col)) {log.info("已禁止 玩家 {} 在 {} 行 {} 列重复落子!",userInfo.getUserName(), row, col);return;}// 落子room.putChess(row, col, chess);// 打印棋盘信息,方便观察落子情况room.printBoard();// 进行胜负判断Long winner = room.checkWinner(row, col, chess);// 通知玩家WebSocketSession session1 = onlineUserManager.getFromRoom(room.getUser1().getUserId());WebSocketSession session2 = onlineUserManager.getFromRoom(room.getUser2().getUserId());if (null == session1 && null == session2) {// 玩家均掉线winner = -1L;log.info("游戏房间 {} 玩家1 和 玩家2 均掉线", room.getRoomId());} else if (null == session1) {winner = room.getUser2().getUserId();log.info("游戏房间 {} 玩家1 掉线", room.getRoomId());} else if (null == session2){winner = room.getUser1().getUserId();log.info("游戏房间 {} 玩家2 掉线", room.getRoomId());}// 构造响应并返回PutChessResult result = new PutChessResult(userInfo.getUserId(), row, col, winner);if (null != session1) {session1.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.success(result))));}if (null != session2) {session2.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(CommonResult.success(result))));}// 若胜负已分,则更新玩家分数,并销毁房间if (winner != 0) {if (winner == -1) {log.info("房间 {} 游戏结束, 结果为平局");} else {log.info("房间 {} 游戏结束, 获胜方id为 {}", room.getRoomId(), winner);// 更新分数Long loser = (room.getUser1().getUserId() == winner) ?room.getUser2().getUserId() : room.getUser1().getUserId();updateScore(winner , loser);}// 销毁游戏房间roomManager.remove(room.getRoomId(),room.getUser1().getUserId(), room.getUser2().getUserId());}} catch (IOException e) {log.warn("发送落子响应异常 e: ", e);} catch (Exception e) {log.warn("落子异常 e: ", e);}}

此外,在玩家掉线时,我们还遗留了一个部分——更新玩家分数,我们将其补充完整:

至此,对战模块的后端代码就基本实现完毕了,我们修改客户端代码并进行测试

修改客户端代码

修改 code != 200 的情况:

根据我们约定的错误码:

当 code = 401 或 code = 402 时,我们让其跳转到 登录页面

当 code = 300 或 code = 301 时,我们让其跳转到 游戏大厅页面

    if (resp.code != 200) {if (resp.code == 300 || resp.code == 301) {location.replace("/game_hall.html");} else if (resp.code == 402 || resp.code == 401){location.replace("/login.html")} else {alert("异常情况:" + resp.errorMessage);}return;}

游戏就绪响应处理 和 落子响应处理都需进行修改

此外,当有玩家退出游戏房间时,我们返回的 row 和 col 为 -1

因此,在标记棋子时,我们需要先进行判断:

        // 标记此处有棋子if (gameRes.row >= 0 && gameRes.col >= 0) {chessBoard[gameRes.row][gameRes.col] = 1;} else {// 提示对手掉线,并返回游戏大厅alert("对方已掉线,恭喜你!你赢了!");location.replace("/game_hall.html");}

 接下来,我们就来对对战模块进行测试

对战模块测试

运行程序,登录两个账号,让其进行匹配,匹配成功后,跳转到游戏房间:

当 玩家1 进入游戏大厅时:

 玩家2 进入游戏大厅:

玩家1 落子:

玩家2 落子:

游戏胜利:

 观察后端落子情况:

与客户端落子情况相同,符合预期

 测试玩家掉线:

但此时还存在一个问题,那就是 用户信息显示

上述我们测试了两种情况——玩家胜利 和 玩家掉线

此时,已经进行了两场游戏,但我们观察游戏大厅显示的用户信息:

此时的用户信息并未进行更新,我们观察后端代码:

由于我们是直接从 session 中获取的信息,因此,当我们更新数据库中的对应信息时,session 存储的信息并未改变,因此,我们需要对其进行修改,从数据库中获取用户信息:

 

根据从 session 中获取的用户 id(用户 id 始终不变),从而在数据库中查询用户信息 

添加 selectByUserId 方法:

    @Select("select * from user where id = #{id}")UserDO selectByUserId(@Param("id") Long id);
http://www.dtcms.com/wzjs/8177.html

相关文章:

  • 在酒店做那个网站好域名解析ip地址查询
  • 英文网站域名注册百度金融
  • 做啊录音网站凡科网建站系统源码
  • 上海专门做网站的公司河南seo网站多少钱
  • 郑州企业网站建设费用企业网络营销
  • 货源之家官网宁波谷歌seo推广公司
  • 访问网站 流程图营销网站建设软件下载
  • ui是做网站的吗东莞seo网站优化排名
  • 怎么把网站上线长沙网红打卡景点排行榜
  • 衢州企业网站建设公司广州今天新闻
  • 网站建设合同定义域名查询
  • 网络推广及网站建设合作协议seo程序
  • 郑州网站建设案例长春百度快速优化
  • 贵金属网站模板东莞seo项目优化方法
  • 软路由系统如何做网站腾讯企点官网下载
  • 各大网站的软文怎么做站长
  • 怎么做国际网站首页seo推广一年要多少钱
  • 网站建设物美价廉千万别手贱在百度上搜这些词
  • 永嘉网站制作哪家好深圳网络推广的公司
  • 葡萄牙语网站设计哪家好软文范例大全
  • 商业网站建设软件seo搜索引擎优化课程总结
  • 济宁市精神文明建设委员会网站百度推广销售员好做吗
  • 盐山做网站价格惠州优化怎么做seo
  • 网站建设与管理案例教程在线阅读账号权重查询入口
  • php编程软件中文seo零基础教学
  • 天津网站建设方案外包营销活动策划方案
  • 地方网站做相亲赢利点在哪里百度的网址是什么呢
  • 外贸网站推广服务seo网络推广员招聘
  • 成都活动策划公司百家港 seo服务
  • 做地方网站需要什么部门批准营销推广策划及渠道