关于Leancloud Play匹配同段位玩家的一个方案讨论

准备使用Leancloud Play的Unity SDK配合云引擎SDK做一个多人(例如4人)回合制卡牌游戏(为方便说明,这里假设是4人版本炉石),关于匹配机制文档和案例中写的不多,所以自己根据现有知识设计了如下方案,希望听听大家意见看是否可行。

首先大架构方面,用云引擎和存储服务负责存储账号、各玩家卡组数据、天梯匹配分数和段位数、开卡包等功能。游戏具体进行是使用leancloud的play服务,第一个加入房间的玩家作为Master client,负责一切重要的游戏逻辑,各个客户端负责用户操作、动画展示。这里目前暂不使用托管Master到Lean Engine,因为不会node.js。日后可以考虑再升级为使用服务器作为Master端。

匹配方案:使用各玩家的分数段位作为匹配条件。例如默认房间大小为4,即使个在线同段位的(rank=5)的玩家匹配时,使用JoinOrCreateRandomRoom(条件rank=5)。

玩家A先加入了room1;成为该room的master随后玩家B、C、D也加入了该房间;各玩家记录roomID,用于掉线重连。
假设游戏是4人房间,Master在前3个新玩家加入时,记录该3个玩家的ID并发送event JoinRoomValid。
Master在发现重连后,根据记录的前4个player ID判断是否合法,通过event告知各客户端是否valid,如果是其他用户则踢出。
掉线用户可以按自己客户端记录的room ID重连,当重连后如果收到valid event,则说明进入房间正确。

目前已知问题
1 JoinOrCreateRoom无法设定条件;而JoinRadomRoom虽然可以设定条件,但好像无法Create,只能加入。
2 房间断线重连的方案是否可行?在有人短线后,必然会有其他正在寻找随机房间同为rank=5的用户加入进来,如何将其踢出房间?

整个方案感觉还是有些糙,不知道是否有更好的建议?谢谢!

从业务角度来看,单纯以「段位」匹配可能并不太合适。
比如以 100 分为一个段位,其实 99 和 101 分的玩家水平是接近的;而如果以 10 分为一个段位,同一段位的玩家数可能太少,无法快速匹配成功。
以王者荣耀为例,他的排行匹配规则也不强制同一段位的,大概是上下一两个段位的玩家都有可能匹配到。

谢谢回复,这方面会根据各段位玩家数量做动态调整,比如最后可能就根据段位分成2个匹配条件,低段位和高段位。

这里的讨论其实重点是放在技术方面,我是第一次做类似的匹配和实时交战。感觉我设计的方案里断线重连部分好像不太稳妥,比如会有其他新匹配的玩家进入有掉线的房间,然后被踢出来,我总感觉这个不太好,有没有办法能让房价master把那个空位只允许之前离线的玩家匹配进来;或者让master有办法设置自己的房间不被JoinRandomRoom寻找到,这样其他玩家寻找新房间的时候不会考虑这些已经开始游戏但人数不满的房间。

不知道使用Lean play时正确、普遍的方案是什么样子的?示例项目里都是直接手动填写房间号,没有涉及这部分。

JoinRadomRoom虽然可以设定条件,但好像无法Create,只能加入。

如果 JoinRadomRoom 失败了,就创建一个新房间。参见 文档 > 自定义房间匹配规则

只允许之前离线的玩家匹配进来

如果是游戏开始前,有其他玩家匹配进来,替换到之前等待游戏开始的玩家,似乎也没有什么问题。如果游戏开始了,那么通常来说应该把房间关掉 ,同时设定保留断线玩家的时间 ,如果长时间不能重连,服务器会将玩家移除房间并销毁玩家数据,一般这种情况游戏可以直接判负,然后其他玩家继续进行游戏。

谢谢!原来如此,我有些头绪了。梳理了以下几个细节小问题:

  • 问题1
    JoinRandomRoom失败后的处理代码示例,我没看太明白,这个play是什么的实例(试过client、LeanCloud.Play都不对)?而这个On的调用又该写在何处呢?
play.On(Event.ROOM_JOIN_FAILED, (error) => {
  if (error["code"] == 4301) 
  {
    var props = new Dictionary<string, object>();
    props.Add("level", 2);
    var options = new RoomOptions()
    {   
      // 设置最大人数,当房间满员时,服务端不会再匹配新的玩家进来。
      MaxPlayerCount = 3,
      // 设置玩家掉线后的保留时间为 120 秒
      PlayerTtl = 120,
      // 房间的自定义属性
      CustomRoomProperties = props,
      // 从房间的自定义属性中选择匹配用的 key
      CustoRoomPropertyKeysForLobby = new List<string>() { "level" },
    };
    play.CreateRoom(roomOptions: options);
  }
});

该如何与JoinRandomRoom的Try Catch代码结合呢?

    try {
        await client.JoinRandomRoom(matchProps);
    } catch (PlayException e) {
        // 加入房间失败
        Debug.LogErrorFormat("{0}, {1}", e.Code, e.Detail);
        // 这里加入试着加入play.On代码块,失败了;而且`e["code"]`的用法也会报错
    }
  • 问题2
    在房间关掉后await client.SetRoomOpened(false);,之前断线及未来断线的玩家是否还可以通过断线重连的方式重新键入?

  • 问题3
    在房间未关闭时,看你的描述,新玩家也是可以通过Random的方式连入该房间顶替掉断线的玩家;所谓“在房间内保留断线用户”意思就是保存该Player.CustomProperties,而不是说保留该位置作为expectedPlayer,只允许该玩家重连。这样理解有问题吗?

  • 问题4
    我在LeanCloud.Play.Client里发现了一个MatchRandom接口,文档里没有对这个接口的介绍。这个接口是否对此问题有帮助?

谢谢!