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

[网页五子棋][匹配模式]创建房间类、房间管理器、验证匹配功能,匹配模式小结

文章目录

  • 创建房间类
    • 创建房间类
    • 实现房间管理器
  • 实现匹配器(3)
  • 验证匹配功能
    • 问题:匹配按钮不改变
    • 验证多开
  • 小结

创建房间类

LOL,通过匹配的方式,自动给你加入到一个房间,也可手动创建游戏房间

  • 这一局游戏,进行的“场所”就可以称为是一个“游戏房间”,游戏房间中最关键的信息,就是玩家信息
  • 一个游戏服务器,有同时存在了多个游戏房间

我们就需要一个“游戏房间管理器”来管理多个游戏房间image.png|429

  • 键值对的方式,给每个 room 生成一个唯一的 roomId,以键值对 (哈希表) 在 room manager 中来进行管理

创建房间类

匹配成功之后,需要把对战的两个玩家放到同一个房间对象中

创建 game.Room

  • 一个房间要包含一个房间 ID,使用 UUID 做为房间的唯一身份标识
  • 房间内要记录对弈的玩家双方信息

UUID 表示“世界上唯一的身份标识”

  • 通过一系列的算法,能够生成一串字符串(一组十六进制表示的数字)
  • 两次/任意次调用这个算法,生产的这个字符串都是不同的
package org.example.java_gobang.game;  import org.example.java_gobang.model.User;  import java.util.UUID;  // 表示一个游戏房间  
public class Room {  // 此处我们使用字符串的类型来表示,方便生成唯一值  private String roomId;  private User user1;  private User user2;  public String getRoomId() {  return roomId;  }  public void setRoomId(String roomId) {  this.roomId = roomId;  }  public User getUser1() {  return user1;  }  public void setUser1(User user1) {  this.user1 = user1;  }  public User getUser2() {  return user2;  }  public void setUser2(User user2) {  this.user2 = user2;  }  public Room() {  // 构造 Room 的时候,生成一个唯一的字符串来表示房间 id        roomId = UUID.randomUUID().toString();  }  
}

实现房间管理器

Room 对象会存在很多,每两个对弈的玩家,都对应一个 Room 对象,需要创建一个管理器对象来管理所有的 Room

创建 game.RoomManager

  • 使用一个 Hash 表,保存所有房间对象
    • key:roomId
    • value:Room对象
  • 再使用一个 Hash 表,保存 userId -> RoomId 的映射,方便根据玩家来查找所在的房间
  • 提供增、删、查的 API
    • 查询包含基于房间 ID 的查询和基于用户 ID 的查询
package org.example.java_gobang.game;  import org.springframework.stereotype.Component;  import java.util.concurrent.ConcurrentHashMap;  // 房间管理器,这个类也希望有唯一实例  
@Component  
public class RoomManager {  private ConcurrentHashMap<String, Room> rooms = new ConcurrentHashMap<>();  // 通过这个哈希表,把玩家和房间之间的关系维护起来  private ConcurrentHashMap<Integer, String> userIdToRoomId = new ConcurrentHashMap<>();  public void add(Room room, int userId1, int userId2) {  rooms.put(room.getRoomId(), room);  userIdToRoomId.put(userId1, room.getRoomId());  userIdToRoomId.put(userId2, room.getRoomId());  }  public void remove(String roomId, int userId1, int userId2) {  rooms.remove(roomId);  userIdToRoomId.remove(userId1);  userIdToRoomId.remove(userId2);  }  public Room getRoomByRoomId(String roomId) {  return rooms.get(roomId);  }  // 根据用户id 定位房间  public Room getRoomByUserId(int userId) {  String roomId = userIdToRoomId.get(userId);  if(roomId == null) {  // userId -> roomId 映射关系不存在,直接返回 null            return null;  }  return rooms.get(roomId);  }  
}

实现匹配器(3)

完善刚才匹配逻辑中的 TODO,并把玩家放到一个房间中 image.png|353

  • 先给 Matcher 注入 RoomManager 对象
@Component
public class Matcher {//......// 房间管理器@Autowiredprivate RoomManager roomManager;// ......
}然后修改 Matcher.handlerMatch,补完之前 TODO 的内容
private void handlerMatch(Queue<User> matchQueue) {// 4. 把这两个玩家放到一个游戏房间中  Room room = new Room();  roomManager.add(room, player1.getUserId(), player2.getUserId());// ......
}

验证匹配功能

问题:匹配按钮不改变

当前发现,玩家点击匹配之后,匹配按钮的文本不发生改变

  • 分析之前写的代码,点击按钮的时候,仅仅是给服务器发送了一个 websocket 请求,告诉服务器我要开始匹配了
  • 服务器会立即返回一个响应,“进入匹配队列成功”,然后页面再修改按钮的文本image.png|372

出现问题的原因:

  • 服务器在处理匹配请求的时候,按理说是要立即就返回一个 websocket 响应的
  • 实际上在服务器代码这里构造了响应对象,但是忘记 sendMessage,给发回去了image.png|338
    在红框中加入如下逻辑代码
// 将 response 先转换成 JSON 字符串,然后将其通过 sendMessage 发回客户端  
String jsonString = objectMapper.writeValueAsString(response);  
session.sendMessage(new TextMessage(jsonString));

就类似于:你网购买了个东西,商家都已经打包好了,但是最后忘记发货了

image.png

验证匹配功能的时候,模拟多个用户登录的情况,最好使用多个浏览器,避免同一个浏览器中的 cookie/session 信息互相干扰

  • 如果只有一个浏览器,并且是 chrome 的话,chrome 有个无痕模式(不会记录历史记录,也不会记录 cookie,页面关闭的时候会自动清空)

验证多开

当我们打开两个页面,登录同一个账号的时候,后登录的页面的检查页面会出现提示,但是正常用户多开了在页面中却没有显示 image.png

  • 当用户多开之后,连接就会直接关闭,不能再进行匹配了image.png
    image.png|449

当前情况下,防多开机制起到了作用,但是又感觉差了点意思

  • 要是在第二个账号登录的时候,在页面中直接有提示就更好了

此时我们就可以调整前端代码,当检测到多开的时候,就给用户一个更加明确的提示 image.png|422

这样,在我们登录的时候,要是出现了多开的情况,就直接报错了,返回重新登录页面image.png|492

  • 当我们修改了 css 样式/ JS 文件之后,往往要在浏览器中使用 cmd+shift+R(Windows:ctrl+f5)强制刷新,才能生效
  • 否则浏览器可能仍然在执行旧版本的代码(浏览器自带缓存)

小结

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

http://www.lryc.cn/news/2392995.html

相关文章:

  • 实验设计与分析(第6版,Montgomery)第3章单因子实验:方差分析3.11思考题3.7 R语言解题
  • 【知识点】第2章:Python程序实例解析
  • 从解决一个分享图片生成的历史bug出发,详解LayoutInflater和View.post的工作原理
  • Ubuntu 22.04 上使用 Docker 安装 RagFlow
  • 每日Prompt:指尖做画
  • Python打卡训练营day40——2025.05.30
  • Java八股-数据类型转换有哪些?类型互转会有什么问题?为什么用bigDecimal 不用double ?自动装箱和拆箱?包装类?
  • redis未授权(CVE-2022-0543)
  • 【运维实战】Linux 中su和sudo之间的区别以及如何配置sudo!
  • LevelDB、BoltDB 和 RocksDB区块链应用比较
  • c/c++的opencv图像金字塔缩放
  • PDF文件转换之输出指定页到新的 PDF 文件
  • 浏览器之禁止打开控制台【F12】
  • 进阶智能体实战九、图文需求分析助手(ChatGpt多模态版)(帮你生成 模块划分+页面+表设计、状态机、工作流、ER模型)
  • GEARS以及与基础模型结合
  • SFINAE(替换并不是错误)机制详解详解
  • 怎么用外网打开内网的网址?如在异地在家连接访问公司局域网办公网站
  • 计算机网络 | 1.1 计算机网络概述思维导图
  • AI对软件工程的影响及未来发展路径分析报告
  • redis缓存与数据库协调读写机制设计
  • 最悉心的指导教程——阿里云创建ECS实例教程+Vue+Django前后端的服务器部署(通过宝塔面板)
  • 【Python】os模块
  • Syslog 全面介绍及在 C 语言中的应用
  • windows中Redis、MySQL 和 Elasticsearch启动并正确监听指定端口
  • Paimon远程文件系统连接机制解析
  • 学者观察 | Web3.0的技术革新与挑战——北京理工大学教授沈蒙
  • pycharm终端遇不显示虚拟环境的问题
  • 聊聊网络变压器的浪涌等级标准是怎样划分的呢?
  • 2025年Google I/O大会上,谷歌展示了一系列旨在提升开发效率与Web体验的全新功能
  • ONLYOFFICE文档API:编辑器的品牌定制化