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

article/2025/6/18 10:46:28

实现游戏房间页面

创建 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.hkcw.cn/article/fgXpAMNVjv.shtml

相关文章

利用nginx完成iframe请求的身份认证

需求说明 在dify中搭建了一个chatflow&#xff0c;搭建完成后&#xff0c;将其以iframe的方式&#xff0c;嵌入到自己开发的一个网站中。 嵌入完成后&#xff0c;效果如下图所示&#xff1a; 此时存在一个安全问题&#xff0c;如果用户知道了这个iframe的URL地址&#xff0c;…

t017-高校实习管理系统 【含材料源码!!!】

项目演示视频 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统高校实习管理系统信息管理难度大&#xff0…

【项目】在线OJ(负载均衡式)

目录 一、项目目标 二、开发环境 1.技术栈 2.开发环境 三、项目树 目录结构 功能逻辑 编写思路 四、编码 1.complie_server 服务功能 代码蓝图 开发编译功能 日志功能 ​编辑 测试编译模块 开发运行功能 设置运行限制 jsoncpp 编写CR 如何生成唯一文件名 …

B3623 枚举排列(递归实现排列型枚举)

B3623 枚举排列&#xff08;递归实现排列型枚举&#xff09; - 洛谷 题目描述 今有 n 名学生&#xff0c;要从中选出 k 人排成一列拍照。 请按字典序输出所有可能的排列方式。 输入格式 仅一行&#xff0c;两个正整数 n,k。 输出格式 若干行&#xff0c;每行 k 个正整数…

深入探讨redis:主从复制

前言 如果某个服务器程序&#xff0c;只部署在一个物理服务器上就可能会面临一下问题(单点问题) 可用性问题&#xff0c;如果这个机器挂了&#xff0c;那么对应的客户端服务也相继断开性能/支持的并发量有限 所以为了解决这些问题&#xff0c;就要引入分布式系统&#xff0c…

c++ typeid运算符

typeid运算符能获取类型信息。获取到的是type_info对象。type_info类型如下&#xff1a; 可以看到&#xff0c;这个类删除了拷贝构造函数以及等号操作符。有一些成员函数&#xff1a;hash_code、before、name、raw_name, 还重载了和!运算符。 测试&#xff1a; void testTyp…

一人住院不必全家奔波!免陪照护试点“全国版”

俗话说“久病床前无孝子”,这句话道出了很多家庭面对病人陪护时的无奈与压力。特别是现在每个人都在谈论的老龄化,再叠加上独生子女,父母住院时的陪护,就更是个越来越难的难题。这时候,如果能由医院来提供标准化的照护服务,估计很多人听了都会有一种如释重负的感觉。随着…

F1西班牙站排位赛:皮亚斯特里夺杆位,迈凯伦强势领跑

北京时间5月31日,F1西班牙大奖赛排位赛落下帷幕。皮亚斯特里夺得杆位,诺里斯和维斯塔潘分列二、三位。拉塞尔排名第四,汉密尔顿第五,安东内利第六,勒克莱尔第七,加斯利第八,哈贾尔第九,阿隆索第十。阿尔本第十一,塞恩斯第十八,科拉平托第十九,角田裕毅第二十。在首轮…

哈马斯回应加沙停火提案 美称“不可接受”

哈马斯回应加沙停火提案 美称“不可接受” 以称继续行动△美国中东问题特使威特科夫(资料图)央视记者获悉,特朗普政府提出的一项旨在促成加沙停火的新一轮提案,遭到巴勒斯坦伊斯兰抵抗运动(哈马斯)的修改要求。对此,美国中东问题特使威特科夫当地时间5月31日公开表示,哈…

uniapp与微信小程序开发平台联调无法打开IDE

经测试属于网络问题。本机需要联网。否则会出现Hbuilder运行微信小程序到模拟器时无法打开 微信开发者工具 这个页面出不来会一直显示异常。这期间微信小程序开发工具的端口是通的 需要先联网

Deseq2:MAG相对丰度差异检验

首先使用代码将contigs和MAG联系起来 https://github.com/MrOlm/drep/blob/master/helper_scripts/parse_stb.py ~/parse_stb.py --reverse -f ~/bin_dir/* -o ~/bin_dir/genomes.stb # 查看第一列的contigs有没有重复&#xff08;重复的话会影响后续比对&#xff09; awk {p…

自动驾驶系列—Monocular 3D Lane Detection for Autonomous Driving

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

这纳米手套能「传触感」,98% 准度+无线震动反馈

*本文只做阅读笔记分享* 一、研究背景与挑战 今天我们聚焦一项针对上肢感觉障碍的创新康复技术。创伤性脊髓损伤&#xff08;TSCI&#xff09;在儿童群体中危害显著&#xff0c;因其神经系统尚未发育成熟&#xff0c;常导致患肢失用、对侧肢体过度使用等问题。当前传统疗法如…

Java基础学习

输入输出 import java.util.*; public class Main {public static void main(String[] args) {int s 888;String s1 "Hello World"; // System.out.print(s); // System.out.print(s1);System.out.println(s);System.out.println(s1);Scanner sc ne…

异构边缘智能处理加速板

简介&#xff1a; TC-ATLAS200-K7325TI是一套FPGAGPU架构的异构边缘智能处理加速板。该板基于华为 ATLAS200 GPU及Xilinx K7高性能FPGA&#xff08;可替换为复旦微JFM7K325T&#xff09;设计而成。 GPU与FPGA之间通过PCIE2.0 X4 互连&#xff0c;实现两者之间数据的高速传输。板…

进程间通信(消息队列)

目录 一 原理 二 API 1. ftok 2. msgget 3. msgctl 4. msgsnd 5. msgrcv 三 demo代码 四 基于责任链模式和消息队列对数据处理 1. 什么是责任链模式 2. 下面基于责任链模式来对消息队列获取的消息进行处理 前置 其实system v 版本的进程间通信&#xff0c;设计的接…

解决8080端口被占问题

文章目录 1. 提出问题2. 解决问题2.1 查看占用8080端口的进程2.2 杀死占用8080端口的进程2.3 测试问题是否已解决3. 实战小结1. 提出问题 运行Spring Boot项目,报错8080端口被占 2. 解决问题 2.1 查看占用8080端口的进程 执行命令:netstat -ano | findstr :8080 2.2 杀死占用…

【harbor】--基础使用

推送 不同的管理工具都有说明 以docker为例 # 第一步--打标签 docker tag SOURCE_IMAGE[:TAG] 192.168.121.201:801/haohao_fist/REPOSITORY[:TAG] # 第二步--推送 docker push 192.168.121.201:801/haohao_fist/REPOSITORY[:TAG]默认push推送为https push会失败 解决办法…

论文略读:To the Globe (TTG): Towards Language-Driven Guaranteed Travel Planning

2024 Emnlp demo 提出了TTG&#xff0c;一个演示系统&#xff0c;它能够接收用户的自然语言指令&#xff0c;并在几秒钟内生成最优的旅行行程 结合了大语言模型&#xff08;LLMs&#xff0c;Llama-3 70B&#xff09;与现有的符号求解器&#xff08;例如混合整数线性规划&#…

《操作系统真相还原》——初探保护模式

BUG 果不其然出现bug b 0x900在进入loader的时候打个断点&#xff0c;看看什么情况&#xff0c;好吧突然想起来&#xff0c;可能弄错镜像了 重新执行 正确 info gdt看一下相关信息