要实现一个用于服务器的双人战斗匹配类,可以使用双端队列来管理玩家的匹配请求。以下是基于参考资料中相关接口和机制的一个实现示例:
```lua
-- 双人战斗匹配类实现
local DoubleBattleMatch = {}
DoubleBattleMatch.__index = DoubleBattleMatch
-- 初始化匹配队列
function DoubleBattleMatch.new()
local obj = {}
setmetatable(obj, DoubleBattleMatch)
obj.matchQueue = {} -- 双端队列,存储等待匹配的玩家
obj.matchedPairs = {} -- 已匹配的玩家对
return obj
end
-- 玩家请求匹配
function DoubleBattleMatch:requestMatch(actor)
if not actor then return false end
-- 检查玩家是否已在队列中
for i, player in ipairs(self.matchQueue) do
if targetinfo(player, "UID") == targetinfo(actor, "UID") then
sendmsg(actor, 6, "您已在匹配队列中")
return false
end
end
-- 将玩家加入队列
table.insert(self.matchQueue, actor)
sendmsg(actor, 6, "已加入双人战斗匹配队列")
-- 尝试匹配
self:tryMatch()
return true
end
-- 尝试匹配玩家
function DoubleBattleMatch:tryMatch()
while #self.matchQueue >= 2 do
-- 从队列前端取出两个玩家
local player1 = table.remove(self.matchQueue, 1)
local player2 = table.remove(self.matchQueue, 1)
-- 检查玩家是否在线
if isonline(player1) and isonline(player2) then
-- 创建匹配对
local matchId = #self.matchedPairs + 1
self.matchedPairs[matchId] = {
player1 = player1,
player2 = player2,
matchTime = os.time()
}
-- 通知玩家匹配成功
sendmsg(player1, 6, string.format("匹配成功!对手:%s", targetinfo(player2, "NAME")))
sendmsg(player2, 6, string.format("匹配成功!对手:%s", targetinfo(player1, "NAME")))
-- 可以在这里触发战斗开始逻辑
self:startBattle(matchId)
else
-- 如果有玩家离线,重新将在线玩家放回队列前端
if isonline(player1) then
table.insert(self.matchQueue, 1, player1)
end
if isonline(player2) then
table.insert(self.matchQueue, 1, player2)
end
end
end
end
-- 开始战斗
function DoubleBattleMatch:startBattle(matchId)
local pair = self.matchedPairs[matchId]
if not pair then return end
local player1 = pair.player1
local player2 = pair.player2
-- 设置玩家为战斗状态(示例)
sethumvar(player1, "BATTLE_STATE", "1")
sethumvar(player2, "BATTLE_STATE", "1")
sethumvar(player1, "OPPONENT_ID", targetinfo(player2, "UID"))
sethumvar(player2, "OPPONENT_ID", targetinfo(player1, "UID"))
-- 传送到战斗场景(示例地图ID 1001)
local mapId = 1001
local x1, y1 = 100, 100 -- 玩家1出生点
local x2, y2 = 200, 200 -- 玩家2出生点
changemap(player1, mapId, x1, y1)
changemap(player2, mapId, x2, y2)
-- 发送战斗开始消息
sendmsg(player1, 6, "战斗开始!")
sendmsg(player2, 6, "战斗开始!")
end
-- 取消匹配
function DoubleBattleMatch:cancelMatch(actor)
if not actor then return false end
local uid = targetinfo(actor, "UID")
-- 从队列中移除
for i, player in ipairs(self.matchQueue) do
if targetinfo(player, "UID") == uid then
table.remove(self.matchQueue, i)
sendmsg(actor, 6, "已取消匹配")
return true
end
end
-- 从已匹配中移除(如果还没开始战斗)
for matchId, pair in pairs(self.matchedPairs) do
if targetinfo(pair.player1, "UID") == uid or targetinfo(pair.player2, "UID") == uid then
-- 通知对手
local opponent = targetinfo(pair.player1, "UID") == uid and pair.player2 or pair.player1
if isonline(opponent) then
sendmsg(opponent, 6, "对手已取消匹配,战斗取消")
-- 将对手重新加入队列前端
table.insert(self.matchQueue, 1, opponent)
end
self.matchedPairs[matchId] = nil
sendmsg(actor, 6, "已取消匹配")
return true
end
end
sendmsg(actor, 6, "您不在匹配队列中")
return false
end
-- 获取匹配队列信息
function DoubleBattleMatch:getQueueInfo()
local info = {
waitingCount = #self.matchQueue,
waitingPlayers = {}
}
for i, player in ipairs(self.matchQueue) do
table.insert(info.waitingPlayers, {
name = targetinfo(player, "NAME"),
level = targetinfo(player, "LEVEL"),
job = targetinfo(player, "JOB")
})
end
return info
end
-- 清理过期匹配(超过5分钟未开始)
function DoubleBattleMatch:cleanupExpiredMatches()
local currentTime = os.time()
local expired = {}
for matchId, pair in pairs(self.matchedPairs) do
if currentTime - pair.matchTime > 300 then -- 5分钟
table.insert(expired, matchId)
end
end
for _, matchId in ipairs(expired) do
local pair = self.matchedPairs[matchId]
if pair then
if isonline(pair.player1) then
sendmsg(pair.player1, 6, "匹配超时,已取消")
table.insert(self.matchQueue, 1, pair.player1)
end
if isonline(pair.player2) then
sendmsg(pair.player2, 6, "匹配超时,已取消")
table.insert(self.matchQueue, 1, pair.player2)
end
self.matchedPairs[matchId] = nil
end
end
return #expired
end
-- 使用示例
--[[
local matchSystem = DoubleBattleMatch.new()
-- NPC脚本中调用
function onNPCClick(actor)
local choice = select(actor, "双人竞技场",
"开始匹配",
"取消匹配",
"查看队列状态",
"退出")
if choice == 1 then
matchSystem:requestMatch(actor)
elseif choice == 2 then
matchSystem:cancelMatch(actor)
elseif choice == 3 then
local info = matchSystem:getQueueInfo()
sendmsg(actor, 6, string.format("当前等待人数:%d人", info.waitingCount))
end
end
-- 定时清理(可在QF中设置)
function onTimer()
matchSystem:cleanupExpiredMatches()
end
]]
return DoubleBattleMatch
```
这个匹配类实现了以下核心机制:
1. **双端队列管理**:使用Lua表模拟双端队列,支持从队列前端取出玩家进行匹配
2. **匹配逻辑**:当队列中有至少2名玩家时,自动进行匹配
3. **状态管理**:区分等待匹配和已匹配两种状态
4. **超时处理**:自动清理超过5分钟未开始的匹配
5. **取消机制**:玩家可以随时取消匹配
6. **信息查询**:可以查看当前匹配队列状态
可以根据实际需求调整匹配条件(如等级差限制、职业平衡等)和战斗开始逻辑。