要实现一个双人战斗匹配类,需要设计匹配队列、玩家信息管理、匹配规则和匹配成功后的处理逻辑。以下是一个基于Lua的服务器端匹配类示例,包含基本框架和关键方法:
```lua
-- 双人战斗匹配类
local BattleMatch = {}
BattleMatch.__index = BattleMatch
-- 匹配队列(按匹配值或等待时间排序)
local matchQueue = {}
-- 匹配池(玩家ID -> 玩家信息)
local playerPool = {}
-- 初始化匹配类
function BattleMatch.new()
local self = setmetatable({}, BattleMatch)
self.matchInterval = 5 -- 匹配检查间隔(秒)
self.maxMatchValueDiff = 100 -- 最大匹配值差异
self.minMatchValueDiff = 10 -- 最小匹配值差异(随时间扩大)
return self
end
-- 玩家加入匹配队列
function BattleMatch:joinMatch(playerId, playerInfo)
-- playerInfo 应包含:匹配值、职业、等级、等待时间等
if playerPool[playerId] then
return false, "玩家已在匹配队列中"
end
local playerData = {
id = playerId,
matchValue = playerInfo.matchValue or 1000, -- 默认匹配值
job = playerInfo.job or 0, -- 职业
level = playerInfo.level or 1, -- 等级
joinTime = os.time(), -- 加入时间
waitTime = 0 -- 已等待时间
}
playerPool[playerId] = playerData
table.insert(matchQueue, playerId)
-- 触发匹配检查
self:checkMatch()
return true, "加入匹配队列成功"
end
-- 玩家取消匹配
function BattleMatch:cancelMatch(playerId)
if not playerPool[playerId] then
return false, "玩家不在匹配队列中"
end
-- 从队列中移除
for i, id in ipairs(matchQueue) do
if id == playerId then
table.remove(matchQueue, i)
break
end
end
playerPool[playerId] = nil
return true, "取消匹配成功"
end
-- 检查并执行匹配
function BattleMatch:checkMatch()
if #matchQueue < 2 then
return
end
-- 按匹配值排序(简单实现,实际可能需要更复杂的算法)
table.sort(matchQueue, function(a, b)
local playerA = playerPool[a]
local playerB = playerPool[b]
if not playerA or not playerB then return false end
-- 考虑等待时间,等待时间越长匹配范围越宽
local expandFactor = math.min(playerA.waitTime, playerB.waitTime) / 10
local maxDiff = self.maxMatchValueDiff + expandFactor * 50
return math.abs(playerA.matchValue - playerB.matchValue) <= maxDiff
end)
-- 尝试匹配相邻玩家
local i = 1
while i <= #matchQueue - 1 do
local playerId1 = matchQueue[i]
local playerId2 = matchQueue[i + 1]
local player1 = playerPool[playerId1]
local player2 = playerPool[playerId2]
if player1 and player2 then
-- 计算匹配度
local matchScore = self:calculateMatchScore(player1, player2)
if matchScore >= 0.7 then -- 匹配阈值
-- 匹配成功,创建战斗
self:createBattle(player1, player2)
-- 从队列中移除
table.remove(matchQueue, i + 1)
table.remove(matchQueue, i)
playerPool[playerId1] = nil
playerPool[playerId2] = nil
else
i = i + 1
end
else
i = i + 1
end
end
-- 更新等待时间
for _, playerId in ipairs(matchQueue) do
local player = playerPool[playerId]
if player then
player.waitTime = os.time() - player.joinTime
end
end
end
-- 计算两个玩家的匹配分数
function BattleMatch:calculateMatchScore(player1, player2)
local score = 0
local totalWeight = 0
-- 1. 匹配值差异(权重最高)
local matchValueDiff = math.abs(player1.matchValue - player2.matchValue)
local matchValueScore = 1 - (matchValueDiff / 1000)
score = score + matchValueScore * 0.5
totalWeight = totalWeight + 0.5
-- 2. 等级差异
local levelDiff = math.abs(player1.level - player2.level)
local levelScore = 1 - (levelDiff / 50)
score = score + levelScore * 0.3
totalWeight = totalWeight + 0.3
-- 3. 职业平衡(可选:避免相同职业)
local jobScore = player1.job == player2.job and 0.5 or 1.0
score = score + jobScore * 0.2
totalWeight = totalWeight + 0.2
return score / totalWeight
end
-- 创建战斗实例
function BattleMatch:createBattle(player1, player2)
-- 这里应该调用战斗创建接口
-- 例如:createPvpBattle(player1.id, player2.id)
-- 通知玩家匹配成功
self:notifyMatchSuccess(player1.id, player2.id)
self:notifyMatchSuccess(player2.id, player1.id)
-- 记录匹配日志
self:logMatchResult(player1, player2)
end
-- 通知玩家匹配成功
function BattleMatch:notifyMatchSuccess(playerId, opponentId)
-- 使用服务器消息接口通知客户端
-- sendmymsg(actor, 消息ID, 参数...)
local opponentInfo = playerPool[opponentId] or {}
-- 构造通知消息
local matchInfo = {
opponentId = opponentId,
opponentName = opponentInfo.name or "对手",
opponentJob = opponentInfo.job or 0,
opponentLevel = opponentInfo.level or 1,
battleId = tostring(os.time()) .. "_" .. playerId .. "_" .. opponentId
}
-- 实际发送消息的代码(需要根据具体消息接口调整)
-- sendmymsg(playerActor, 90030001, 1, nil, nil, matchInfo)
end
-- 记录匹配结果
function BattleMatch:logMatchResult(player1, player2)
local logData = {
player1 = player1.id,
player2 = player2.id,
matchTime = os.time(),
player1MatchValue = player1.matchValue,
player2MatchValue = player2.matchValue,
waitTime1 = player1.waitTime,
waitTime2 = player2.waitTime
}
-- 记录到事件日志(如果需要)
-- seteventlog(player1.id, 事件ID, 日志内容)
end
-- 定时匹配检查(需要在服务器定时器中调用)
function BattleMatch:startMatchTimer()
-- 每5秒检查一次匹配
local function matchTimerFunc()
self:checkMatch()
end
-- 设置定时器(具体实现取决于服务器的定时器接口)
-- settimer("BattleMatchTimer", self.matchInterval * 1000, matchTimerFunc)
end
-- 获取匹配队列信息(用于监控)
function BattleMatch:getMatchQueueInfo()
local info = {
queueSize = #matchQueue,
avgWaitTime = 0,
players = {}
}
local totalWaitTime = 0
for _, playerId in ipairs(matchQueue) do
local player = playerPool[playerId]
if player then
totalWaitTime = totalWaitTime + player.waitTime
table.insert(info.players, {
id = playerId,
waitTime = player.waitTime,
matchValue = player.matchValue,
level = player.level,
job = player.job
})
end
end
if #matchQueue > 0 then
info.avgWaitTime = totalWaitTime / #matchQueue
end
return info
end
-- 清理长时间未匹配的玩家
function BattleMatch:cleanupStalePlayers(maxWaitTime)
maxWaitTime = maxWaitTime or 300 -- 默认5分钟
local removed = {}
for i = #matchQueue, 1, -1 do
local playerId = matchQueue[i]
local player = playerPool[playerId]
if player and player.waitTime > maxWaitTime then
table.remove(matchQueue, i)
playerPool[playerId] = nil
table.insert(removed, playerId)
-- 通知玩家匹配超时
self:notifyMatchTimeout(playerId)
end
end
return removed
end
-- 通知匹配超时
function BattleMatch:notifyMatchTimeout(playerId)
-- sendmymsg(playerActor, 90030001, 2, nil, nil, "匹配超时,请稍后重试")
end
return BattleMatch
```
## 使用示例:
```lua
-- 初始化匹配系统
local battleMatch = BattleMatch.new()
battleMatch:startMatchTimer()
-- 玩家加入匹配
function onPlayerJoinMatch(playerId, playerInfo)
local success, msg = battleMatch:joinMatch(playerId, {
matchValue = playerInfo.fightPower or 1000, -- 可以使用战斗力作为匹配值
job = playerInfo.job,
level = playerInfo.level,
name = playerInfo.name
})
if success then
sendmsg(playerActor, 6, "开始匹配,请稍候...")
else
sendmsg(playerActor, 6, msg)
end
end
-- 玩家取消匹配
function onPlayerCancelMatch(playerId)
local success, msg = battleMatch:cancelMatch(playerId)
if success then
sendmsg(playerActor, 6, "已取消匹配")
end
end
-- 获取匹配状态(GM命令或监控)
function getMatchStatus()
local info = battleMatch:getMatchQueueInfo()
print("当前匹配队列人数:", info.queueSize)
print("平均等待时间:", info.avgWaitTime)
-- 定期清理长时间等待的玩家
battleMatch:cleanupStalePlayers(600) -- 10分钟
end
```
## 关键特性:
1. **匹配值系统**:基于玩家战斗力或等级作为匹配基准
2. **动态匹配范围**:等待时间越长,匹配范围越宽
3. **多维度匹配**:考虑等级、职业等因素
4. **超时清理**:防止玩家长时间等待
5. **状态监控**:可查看匹配队列状态
6. **事件通知**:匹配成功或超时通知玩家
## 扩展建议:
1. **匹配算法优化**:可以实现ELO等级分系统
2. **多队列支持**:按不同战斗模式分队列
3. **机器人填充**:匹配超时时用AI机器人填充
4. **匹配偏好**:允许玩家设置匹配偏好(如只想匹配不同职业)
5. **战绩记录**:记录匹配历史,用于优化后续匹配
这个匹配类提供了基础框架,可以根据具体游戏需求进行调整和扩展。