游戏对战匹配逻辑小结

前言

近期接触了到了游戏后台的匹配逻辑,写此文作记录,也给后来者一些参考。
本文主要是对逻辑的一些整理,真正使用的时候还需根据实际场景来。

场景与需求

  1. 玩家去匹配战斗力与自己类似的其他玩家。如果在一定区间找不到对手,那就扩展区间。
  2. 连续匹配两次,不能匹配到相同的玩家。
  3. 如果已经战斗过的玩家,在一定时间内不能再被匹配到。(此处假设5分钟内不能再被匹配到,5分钟之后需要又可以被匹配到)

数据结构

根据上面几个需求,得出以下初步结论:

  1. 至少要有两个List,一个是可以匹配的玩家的List,另一个是已经战斗过的玩家的List。
  2. 由于需要根据不同战斗力来匹配不同的玩家,所以要根据不同战斗力,分出多个List。
  3. 需要随时可以获取到每个用户上次战斗的时间,这样才能让用户过了5分钟后又可以匹配到。

根据这三点,目前的结构是这样的:

    //上次战斗的时间
    private final HashMap<String,Long> battleTimeMap=new HashMap<>();
    //不能战斗的队列
    private final LinkedList<String> unableBattleList=new LinkedList<>();
    
     //根据战力分区
    private final HashMap<Integer,LinkedList<String>>  enableBattleMap=new HashMap<>();  

匹配逻辑

已经可以确定是从一个List中选出被对战的玩家,选择的方式其实是两种:顺序读和随机读。

由于随机匹配两次,不能匹配到相同的玩家,所以随机读是很不方便的,于是就确定使用顺序读。

匹配的时候有一个场景的问题是必须解决的:

用户匹配到的对手,不一定会选择战斗,也可能直接退出匹配界面,或者换一个匹配的对手。
这时候,被匹配到,但却没有战斗过的用户仍应该在可被匹配的List中。

于是结构就变成了这样:

    //上次战斗的时间
    private final HashMap<String,Long> battleTimeMap=new HashMap<>();
    //不能战斗的队列
    private final LinkedList<String> unableBattleList=new LinkedList<>();
    
     //根据战力分区
    private final HashMap<Integer,LinkedList<String>>  enableBattleMap=new HashMap<>();  
    //是否可以被匹配
    private final HashSet<String> enableBattleSet=new HashSet<>();

添加了一个enableBattleSet,如果战斗过了,那么就不会在这个Set中。
于是逻辑就变成了这样:

  1. 匹配的时候,如果一个玩家被匹配到,首先看下是否enableBattleSet中,如果在,那么就返回,如果不在,那就把这个玩家移出匹配List,并且匹配下一个。
  2. 返回之后不移出可匹配的List,而是放到队列末尾。(因为只有战斗了才会被认为不能匹配)
  3. 在战斗开始后,将这个用户从enableBattleSet中移出。(这样在匹配的时候就不会被匹配到)

战斗冷却结束逻辑

简单来说就是将战斗冷却结束的用户放到可匹配的List中。

这个大概有两种实现方案:

  1. 由玩家每次匹配,触发战斗冷却结束的逻辑。
  2. 后来放一个线程,定时去触发战斗冷却技术的逻辑。

由于随着玩家越来越多,战斗匹配的逻辑触发会越发频繁。但是战斗冷却结束的逻辑没有必要那么频繁触发,所以方案一是不合适的。

笔者最终选择的是方案二。

上锁的逻辑

如果两个玩家战斗力类似,他们同时触发匹配的话,可能会匹配到同样的对手,这样就会导致被匹配到的玩家在同一时间与两个玩家战斗。这样显然是不合理的,所以需要对逻辑上锁。
上锁也是有两种方案:

  1. 对可匹配玩家的List上锁
  2. 对匹配函数上锁

两种方案笔者评估下都是可行的,都各有利弊:

  1. 对List上锁。
    优势: 只有战斗力类似的玩家同时触发匹配逻辑才会阻塞,减小了由于“同时匹配”被阻塞的概率。
    劣势: 如果在匹配的时候触发了“战斗冷却结束逻辑”,那么也会被阻塞,存在请求超时风险。
  2. 对匹配函数上锁
    优势: 如果在匹配的时候触发了“战斗冷却结束逻辑”,不会被阻塞。而且结束战斗冷却的玩家是被放到List尾部,所以一般情况也不会影响匹配逻辑。
    劣势: 所有玩家中,只要有有两个人同时触发匹配逻辑,就会有玩家被阻塞,存在请求超时风险。

一致性问题

实际操作过程中,一个服务一般都会部署在多台服务器上,这样才能通过负载均衡提高并发,并且在有一台服务器出故障的时候,能保证服务正常运行。
在这种情况下,匹配逻辑的中间过程就不能仅仅放在缓存中,而应该使用redis放在redis服务器上,这样才能保证匹配数据只有一份,而不是每台服务器都有一份。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值