房间匹配这块就没那么简单了,涉及到的东西掠夺,可能要分好几个部分才能复盘完整。
首先整理一下大体思路。网游一般是一键匹配,即玩家点击匹配,系统自动匹配。换成代码思路就是玩家向服务器提交匹配请求,服务器根据玩家的一些数据比如ip地址,玩家等级等,将玩家组成一个“房间队列”。当房间队列内的玩家已经满员且就绪后,开始游戏。
另一种就是类似于红警那种,玩家创建/加入房间。前者是商业化落地的考虑,这里只是复盘一个简单的房间系统。
首先明确:一个“房间”的主要责任:向一个房间内的所有玩家转发每个玩家的全部指令。
房间类
1.定义一个房间对象,其主要的一些属性及其备注。
public class Room {
//房间总数,从0开始按创建顺序增长
public static int roomCount = 0;
//房间哈希码列表,key是房间哈希值,value是房间号
public static Hashtable<Integer, Room> roomHashMap = new Hashtable<Integer,Room>();
public static Hashtable<Integer, Room> roomIdMap = new Hashtable<>();
//房主名称
public String hostName;
//房间容量:几v几
public int roomSize;
//当前玩家数量
public int playerCount = 0;
//房间序号
public int roomID;
//满员标识:满员后大厅不显示该房间
public boolean ifFull = false;
//空房标识:空房间大厅不显示该房间
public boolean ifEmpty = true;
//开始游戏标志:开始游戏后大厅不显示该房间
public boolean ifStartGame = false;
//当前房间的玩家的Id列表
public ArrayList<String> userIdsList;
//当前房间的玩家的名称列表
public ArrayList<String> userNameList;
//当前房间哈希值(唯一标志)
public int hashCode;
//当前房间线程池
private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
//每个玩家最后访问该房间的时间,用于超时判定
private Hashtable<String, Long> lastAccessTime = new Hashtable<>(); // 记录每个用户的最后访问时间
private static final long TIMEOUT = 10000; // 用户超时时间,单位为毫秒
//所有玩家最后访问的时间(一个房间超过多少秒没有任何玩家访问,则重置房间)
private long lastCmdTime = System.currentTimeMillis();
2.创建一个新的房间,创建的时候指定房间容量和房主名称
// 初始化
public Room(int roomSize,String hostName) {
synchronized (Room.class) {
Room.roomCount++;
}
roomID = Room.roomCount;
this.hashCode = generateUniqueHashCode();
roomHashMap.put(this.hashCode,this);
this.roomSize = roomSize;
this.userIdsList = new ArrayList<>();
this.userNameList = new ArrayList<>();
roomIdMap.put(roomID, this);
}
3.玩家进入房间,
将玩家注册到房间的玩家列表。当进入后玩家数量达到房间容量后,启动一个开始计时线程,准备开始
// 进房间
public synchronized boolean InRoom(String userId,String userName) {
if (ifFull)
return false;
else {
//首个进入房间的是房主
if (userNameList.size()==0)
hostName=userName;
//添加用户Id和用户名称
userIdsList.add(userId);
userNameList.add(userName);
playerCount++;
ifEmpty=false;
lastAccessTime.put(userId, System.currentTimeMillis()); // 更新用户的最后访问时间
if (userIdsList.size() >= roomSize) {
System.out.println("房间:" + roomID + "准备开始!当前玩家数量" + userIdsList.size());
LaterSetStartFlag(true, 5);
ifFull = true;
}
return true;
}
}
4.退出房间
删除该玩家数据
// 出房间
public synchronized void OutRoom(String userId) {
if (userIdsList.contains(userId)) {
playerCount--;
if (!ifStartGame)
ifFull = false;
userNameList.remove(userIdsList.indexOf(userId));
userIdsList.remove(userId);
lastAccessTime.remove(userId); // 移除用户的最后访问时间
}
System.out.println(userId+"退出房间");
if (userIdsList.size() <= 0)
resetRoom();
}