接着继续开始写我们的文章,千万不要以为只是随便的两篇文章就结束了我们的匹配大厅。我说过匹配是一个大话题。始终困扰着开发人员, 玩家,策划!话不多说,我们开始上课,下面要开始我们最烧脑瓜子的部分了。不懂得,请提前预习 ELO, Truekill,Glicko,平均值,加权平均值以方便加深理解。
既然,我们决定了要实现自己的匹配算法,就有付出大量的时间与精力。
上文提到,我们想要一个足够灵活的算法,来满足大量玩家与少量玩家都可以匹配的情况!
那么,下面,我们正式开始进入我们的积分排名系统!我们需要某种打分系统,来筛选玩家。作为服务器应该如何选择出十位势均力敌的玩家。侧重点在哪里?那些是影响游戏对局最关键的因素统一列举出来,进行量化打分。
比赛质量评分
- 段位分段限制。 首先我最能先想到的事,玩家的段位分数,我们在设计之初就给了玩家一定数量的分数,0分或500分。假定500分,就是我们的起点(青铜)。那么,可以这样做,服务器创建玩家匹配池或匹配队列,对点下匹配的玩家,进行计算ta的分数,ta可以匹配+500 -500上下这个区间分数的玩家。比如,玩家1500分,可以匹配2000~1000分数位置的玩家。俗称就是,黄金可以匹配铂金跟白银的玩家。我们可以调整这个区间。当然,前提是,我们必须保证能有大量玩家的情况下。
- Ping 值。我们从简单的区间中,找到了合适的玩家,再对玩家与敌方的Ping值一次进行筛选他们的网络值。简单的设定50ms以下的网络值是满分 100分,100ms左右的60分,大于250ms 的0分(因为你确实无法流畅的体验游戏)。
- 水平相当的玩家。即使两支队伍完全平衡,比赛也可能不平衡。例如,如果两支队伍都包含两名职业选手和一名新手,那么两支队伍的平均水平相同,但比赛不会很有趣。因此,我们使用一个单独的分数,忽略队伍,只看所有玩家之间的技能差异。在 6 人比赛中,有 15 种玩家组合,我们只是对所有这些组合进行平均。差异越大,分数越低。
- 玩家组队。理想情况下,5人组队开黑应该遇上的也是5人,如果两队一样的情况下,分数就是100%。假如遇上的是,5人与4人+1人的队伍那就是80%,以此类推,5人团队对5人单人结果就是0分,会是一场比较差的比赛。
- 对手变化。由于我们的匹配系统基本上寻找技能相似且彼此联系良好的玩家,因此它倾向于反复让相同的玩家互相对抗。我们原本以为这种情况很少发生,这样当它发生时会很有趣,但实际上我们的玩家遇到相同的人太频繁了。为了解决这个问题,如果玩家在上一场比赛中也遇到过对方,我们会给这场比赛较低的分数。如果他们以对手的身份遇到对方,但 现在是队友(反之亦然),我们会给这场比赛比他们在相同情况下相遇(之前是对手,现在是对手;或者之前是队友,现在是队友)的分数略高。这让匹配系统略微倾向于交换队伍,尽管有这条规则,但最终还是与相同的玩家进行了另一场比赛。这条规则的权重很低,因为我们更看重其他规则,但这条规则仍然大大改善了情况,我们收到的玩家投诉也少了很多。
合并分数
现在我们每场比赛都有一个分数,我们可以计算我们正在匹配的 100 多名玩家的总分。我们只需对所有比赛的分数取平均值即可。结果是一个很大的总分。 由于我们看的是总分,所以算法会有一定的偏好。如果交换两个玩家会使一场比赛的分数增加 5%,但会使另一场比赛的分数降低 10%,那么它就不会这样做,因为总的来说这会使情况变得更糟。这听起来很明显,但在某些情况下,人们可能想偏离这一点。例如,也许你可能更愿意将得分为 50%(非常糟糕)的比赛提高到 55%,但代价是将 90% 的比赛降低到 80%(这仍然相当不错)。实现此目的的一种方法可能是先对所有匹配得分取平方根,然后再取平均值。这样,改进糟糕的匹配就变得相对更重要。对于 Awesomenauts,我们决定不这样做,因为我们认为单个得分已经足以代表匹配质量改进的真正程度。
找到得分最高的比赛
现在我们有了一个计分系统来定义最佳匹配(得分最高的匹配),我们进入了问题的算法部分:如何真正找到最佳匹配。在 100 多名玩家的情况下,我们可以做出的组合数量非常多,因此我们无法通过简单地尝试所有组合来强行解决这个问题。
我认为这实际上可能是一个图论问题,所以我尝试寻找可以帮助我的节点图算法,但问题太具体了,我找不到任何算法。即使在咨询了一位学术算法专家后,也没有找到任何结果,所以我决定寻找一些好的估计,并接受实际的最佳匹配可能无法找到的事实。这个问题甚至可能是 NP 完全的,但我实际上并没有尝试证明这一点。寻找更好的算法可能是某个地方计算机科学专业学生的有趣论文主题。
我最终采用的方法是首先使用一个简单的规则创建一个有点合理的匹配。我为此尝试了几条规则,例如简单地按技能对所有玩家进行排序,然后根据该排序将玩家安排到比赛中。因此,排名前六的玩家一起参加一场比赛,然后是接下来的六场比赛,依此类推。这很容易构建,并产生最佳的技能得分。由于它完全忽略了所有其他分数,因此在 ping 和预赛方面表现非常糟糕。
我们现在每场比赛有 6 名玩家,但我们尚未决定谁在红队,谁在蓝队。因此,下一步是如何将每场比赛中的六名玩家分配到两支队伍中。在这里,我们可以强行解决问题:我们只需尝试所有可能的组合并选择最佳组合。在这里,我们考虑所有 6 个分数,而不仅仅是技能。组合的数量非常少,特别是因为玩家在每个团队中的顺序并不重要。由于我们尝试了每种组合,我们确信玩家将以最佳方式分配到各个团队中。
我们现在有一个很好的起点。下一步是寻找改进:我们将寻找可以提高总分的球员交换方式。我们每次只交换一次。在这里,我们可以再次使用蛮力来解决这个问题:我们只需尝试所有交换,然后执行最佳交换。有很多不同的可能交换方式,我们还需要为每次交换重新计算两支球队的分红,因此这会占用大量的处理能力。但是,现代计算机速度非常快,因此通过一些优化,我们可以通过这种方式每秒进行几百次交换。
尤其是第一次交换将大大改善比赛,但我们开始看到收益递减,直到找不到真正有所改善的交换。那里可能仍然有一些不好的比赛,但没有一次交换会整体上有所改善。换句话说:我们已经达到了局部最优。我们几乎肯定没有为这 100 多名玩家找到最佳匹配,但我们无法使用当前的交换算法进一步改善这一匹配。
等待时长
同时匹配所有人。这样做可以让我们的匹配算法拥有最大的灵活性来找到最佳匹配,但事实证明,玩家在世界各地的分布比我事先估计的更加不均匀,从而造成了问题。
解决这个问题需要每轮拥有更多的玩家:我认为 300 人左右是理想的。然而,这意味着要么等待时间极长,要么拥有庞大的玩家群。我们希望拥有像英雄联盟一样庞大的玩家群,但不幸的是,除了最热门的游戏之外,这对于其他游戏来说都不现实。结果是我们选择了一个中间立场:我们等待这 100 名玩家,这可能需要 5 分钟甚至更长时间,然后我们只进行匹配并接受结果不会像我们期望的那样好。如果玩家数量太少,那么在某个时候我们还是会进行匹配,这样等待时间就不会超过最大值。
在那个游戏的某个时候,系统会尽快开始匹配,只要匹配质量足够好。在我们的例子中