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

[网页五子棋][对战模块]实现游戏房间页面,服务器开发(创建落子请求/响应对象)

实现游戏房间页面

创建 css/game_room.css

  • #screen 用于显示当前的状态,例如“等待玩家连接中…”,“轮到你落子”,“轮到对方落子”等
#screen {  width: 450px;  height: 50px;  margin-top: 10px;  color: #8f4e19;  font-size: 28px;  font-weight: 700;  line-height: 50px;  text-align: center;  
}

实现 game_room.html,这个页面就是匹配成功之后,要跳转到的新页面image.png|439

<!DOCTYPE html>  
<html lang="en">  
<head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>游戏房间</title>  <link rel="stylesheet" href="css/common.css">  <link rel="stylesheet" href="css/game_room.css">  
</head>  
<body>  <div class="nav">五子棋对战</div>  <div class="container">  <div>            <!-- 棋盘区域,需要基于 canva 进行实现 -->  <canvas id="chess" width="450px" height="450px">  </canvas>             <!-- 显示区域 -->  <div id="screen">等待玩家连接中...</div>  </div>    </div>    <script src="js/app.js"></script>  
</body>  
</html>

页面效果

image.png|439

初始化 websocket

js/app.js 中,加入 websocket 的连接代码,实现前后端交互

  • 先删掉原来 initGame() 函数的调用,一会在获取到服务器反馈的就绪响应之后,再初始化棋盘
  • 创建 websocket 对象,并注册 onopen/onclose/onerror 函数
    • 其中在 onopen 中做一个跳转到大厅的逻辑,当网络断开时,则返回大厅
  • 实现 onmessage 方法,onmessage 先处理游戏就绪响应
// 此处写的路径要写作 /game,不要写作 /game/let websocket = new WebSocket("ws://127.0.0.1:8080/game");  websocket.onopen = function() {  console.log("连接游戏房间成功!");  
}  websocket.onclose = function() {  console.log("和游戏服务器断开连接!");  
}  websocket.onerror = function() {  console.log("和服务器的连接出现异常!");  
}  // 用户点击关闭关闭页面,就断开网络连接  
window.onbeforeunload = function() {  websocket.close();  
}  // 处理服务器返回的响应数据  
websocket.onmessage = function(event) {  console.log("[handlerGameReady] " + event.data);  let resp = JSON.parse(event.data);  if(resp.message != 'gameReady') {  console.log("响应类型错误!");  return;  }  if(!resp.ok) {  alert("连接游戏失败! reason: " + resp.reason);  // 如果出现连接失败的情况,就回到游戏大厅  location.assign("/game_hall.html");  return;  }  gameInfo.roomId = resp.roomId;  gameInfo.thisUserId = resp.thisUserId;  gameInfo.thatUserId = resp.thatUserId;  gameInfo.isWhite = resp.isWhite;  // 初始化棋盘  initGame();  // 设置显示区域的内容  setScreenText(gameInfo.isWhite);  
}

服务器开发

创建并注册 GameAPI 类

创建 api.GameAPI,处理 websocket 请求

  • 这里准备一个 ObjectMapper 类,让后面进行消息发送的时候进行序列化
  • 同时注入一个 RoomManagerOnlineUserManager
package org.example.java_gobang.api;  import org.springframework.stereotype.Component;  
import org.springframework.web.socket.CloseStatus;  
import org.springframework.web.socket.TextMessage;  
import org.springframework.web.socket.WebSocketSession;  
import org.springframework.web.socket.handler.TextWebSocketHandler;  @Component  
public class GameAPI extends TextWebSocketHandler {  @Autowired  private ObjectMapper objectMapper = new ObjectMapper();  @Autowired  private RoomManager roomManager;@Override  public void afterConnectionEstablished(WebSocketSession session) throws Exception {  }  @Override  protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {  }  @Override  public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {  }  @Override  public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {  }  
}

修改 WebSocketConfig,将 GameAPI 进行注册

package org.example.java_gobang.config;  import org.example.java_gobang.api.GameAPI;  
import org.example.java_gobang.api.MatchAPI;  
import org.example.java_gobang.api.TestAPI;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.web.socket.config.annotation.EnableWebSocket;  
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;  
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;  
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;  /**  * 这个类是用来注册 WebSocketHandler 的配置类  * 这个类是来告诉 Spring(websocket),哪一个类是和哪一个路径相匹配的  */  
@Configuration  
@EnableWebSocket // 让 Spring 框架知道这个类是用来配置 websocket 的  
public class WebSocketConfig implements WebSocketConfigurer {  @Autowired  private TestAPI testAPI;  @Autowired  private MatchAPI matchAPI;  @Autowired  private GameAPI gameAPI;  @Override  public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {  // 当我们的客户端连接到 /test 路径的时候,就会触发到当前的 TestAPI,然后调用执行里面的方法  webSocketHandlerRegistry.addHandler(testAPI, "/test");  // 通过 .addInterceptors(new HttpSessionHandshakeInterceptor() 这个操作,  // 来把 HttpSession ⾥的属性放到 WebSocket 的 session 中  // 然后就可以在 WebSocket 代码中 WebSocketSession ⾥拿到 HttpSession 中的 attribute        webSocketHandlerRegistry.addHandler(matchAPI,"/findMatch")  .addInterceptors(new HttpSessionHandshakeInterceptor());  webSocketHandlerRegistry.addHandler(gameAPI, "/game")  .addInterceptors(new HttpSessionHandshakeInterceptor());  }  
}

创建落子请求/响应对象

这部分内容要和约定的前后端交互接口匹配

创建 game.GameReadyResponse

package org.example.java_gobang.game;  // 客户端连接到游戏房间后,服务器返回的响应  public class GameReadyResponse {  private String message;  private boolean ok;  private String reason;  private String roomId;  private int thisUserId;  private int thatUserId;  private int whiteUser;  public boolean isOk() {  return ok;  }  public void setOk(boolean ok) {  this.ok = ok;  }  public String getMessage() {  return message;  }  public void setMessage(String message) {  this.message = message;  }  public String getReason() {  return reason;  }  public void setReason(String reason) {  this.reason = reason;  }  public String getRoomId() {  return roomId;  }  public void setRoomId(String roomId) {  this.roomId = roomId;  }  public int getThatUserId() {  return thatUserId;  }  public void setThatUserId(int thatUserId) {  this.thatUserId = thatUserId;  }  public int getThisUserId() {  return thisUserId;  }  public void setThisUserId(int thisUserId) {  this.thisUserId = thisUserId;  }  public int getWhiteUser() {  return whiteUser;  }  public void setWhiteUser(int whiteUser) {  this.whiteUser = whiteUser;  }  
}

创建 game.GameRequest

  • 表示落子请求
package org.example.java_gobang.game;  // 这个类表示落子请求  
public class GameRequest {  // 如果不给 message 设置 getter / setter, 则不会被 jackson 序列化private String message;  private int userId;  private int row;  private int col;  public String getMessage() {  return message;  }  public void setMessage(String message) {  this.message = message;  }  public int getUserId() {  return userId;  }  public void setUserId(int userId) {  this.userId = userId;  }  public int getRow() {  return row;  }  public void setRow(int row) {  this.row = row;  }  public int getCol() {  return col;  }  public void setCol(int col) {  this.col = col;  }  
}

创建 game.Response

  • 表示落子响应
package org.example.java_gobang.game;  // 这个类表示 落子响应  
public class GameResponse {  // 如果不给 message 设置 getter / setter, 则不会被 jackson 序列化  private String message;  private int userId;  private int row;  private int col;  private int winner;  public String getMessage() {  return message;  }  public void setMessage(String message) {  this.message = message;  }  public int getUserId() {  return userId;  }  public void setUserId(int userId) {  this.userId = userId;  }  public int getRow() {  return row;  }  public void setRow(int row) {  this.row = row;  }  public int getCol() {  return col;  }  public void setCol(int col) {  this.col = col;  }  public int getWinner() {  return winner;  }  public void setWinner(int winner) {  this.winner = winner;  }  
}
http://www.xdnf.cn/news/743869.html

相关文章:

  • 中文NLP with fastai - Fastai Part4
  • 新视角!经济学顶刊QJE用文本分析探究新技术扩散
  • 简单cnn
  • go|channel源码分析
  • c# 如何中的 ? 与 ??
  • “粽”览全局:分布式系统架构与实践深度解析(端午特别版)
  • 《信号与系统》第 5 章 离散时间傅里叶变换
  • 2025年- H61-Lc169--74.搜索二维矩阵(二分查找)--Java版
  • Qt -下载Qt6与OpenCV
  • Python训练营打卡Day41
  • 5G-A:开启通信与行业变革的新时代
  • 2025年渗透测试面试题总结-匿名[校招]渗透测试(打击黑灰产)(题目+回答)
  • Python实现P-PSO优化算法优化循环神经网络LSTM回归模型项目实战
  • 华为OD机试真题——文件目录大小(2025 A卷:100分)Java/python/JavaScript/C++/C语言/GO六种语言最佳实现
  • (11)课29--30:navicat 的用法;行转列的查询与典型算法,并涉及分组(学生各科成绩与比赛胜负);
  • 【Unity】AudioSource超过MaxDistance还是能听见
  • AI笔记 - 网络模型 - mobileNet
  • [蓝桥杯]机器人塔
  • Java 文件操作 和 IO(5)-- 综合案例练习 -- 示例一
  • antddesign使用iconfont的字体库和图标库
  • 微服务中引入公共拦截器
  • python从零开始实现四极场离子轨迹仿真——框架
  • 深入理解设计模式之访问者模式
  • 帕金森带来的生活困境
  • Centos系统搭建主备DNS服务
  • Java 数据处理 - 数值转不同进制的字符串(数值转十进制字符串、数值转二进制字符串、数值转八进制字符串、数值转十六进制字符串)
  • 【Bluedriod】蓝牙协议栈GD模块(GD_SHIM_MODULE)启动机制及源码解析
  • LXQt修改开始菜单高亮
  • 第12讲、Odoo 18 权限控制机制详解
  • kafka核心组件