LOL
,通过匹配的方式,自动给你加入到一个房间,也可手动创建游戏房间
我们就需要一个“游戏房间管理器”来管理多个游戏房间
room
生成一个唯一的 roomId
,以键值对 (哈希表) 在 room manager
中来进行管理匹配成功之后,需要把对战的两个玩家放到同一个房间对象中
创建 game.Room
类
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
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);
}
}
完善刚才匹配逻辑中的 TODO
,并把玩家放到一个房间中
Matcher
注入 RoomManager
对象@Component
public class Matcher {
//......
// 房间管理器
@Autowired
private RoomManager roomManager;
// ......
}
然后修改 Matcher.handlerMatch,补完之前 TODO 的内容
private void handlerMatch(Queue<User> matchQueue) {
// 4. 把这两个玩家放到一个游戏房间中
Room room = new Room();
roomManager.add(room, player1.getUserId(), player2.getUserId());
// ......
}
当前发现,玩家点击匹配之后,匹配按钮的文本不发生改变
websocket
请求,告诉服务器我要开始匹配了出现问题的原因:
websocket
响应的sendMessage
,给发回去了在红框中加入如下逻辑代码
// 将 response 先转换成 JSON 字符串,然后将其通过 sendMessage 发回客户端
String jsonString = objectMapper.writeValueAsString(response);
session.sendMessage(new TextMessage(jsonString));
就类似于:你网购买了个东西,商家都已经打包好了,但是最后忘记发货了
验证匹配功能的时候,模拟多个用户登录的情况,最好使用多个浏览器,避免同一个浏览器中的
cookie/session
信息互相干扰
chrome
的话,chrome
有个无痕模式(不会记录历史记录,也不会记录 cookie
,页面关闭的时候会自动清空)当我们打开两个页面,登录同一个账号的时候,后登录的页面的检查页面会出现提示,但是正常用户多开了在页面中却没有显示
当前情况下,防多开机制起到了作用,但是又感觉差了点意思
此时我们就可以调整前端代码,当检测到多开的时候,就给用户一个更加明确的提示
这样,在我们登录的时候,要是出现了多开的情况,就直接报错了,返回重新登录页面
css
样式/ JS
文件之后,往往要在浏览器中使用 cmd+shift+R
(Windows:ctrl+f5
)强制刷新,才能生效