如何实现游戏中的段位排行榜?

该文分析了王者荣耀中段位排行榜的需求,提出了一种利用Redis有序集合实现高效排行榜的设计方案。在玩家完成排位赛后,通过领域事件更新多个排行榜,避免了登录时的大量计算,确保了玩家体验。Redis数据结构选择有序集合,解决了分数相同情况下的排名问题,并提供了分数封装和解析的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以王者荣耀例子来解释方案,并非是王者荣耀真实方案

业务需求分析

在王者荣耀中,我们会打排位,而且我们想展示我们的段位会有很多个排行榜,比如段位排行榜。而段位排行榜是我们经常关注的,我们会看我们的段位在区服的排名情况,在好友列表中的排名情况。

根据以上需求,我们可以分析出排行榜需要提供两个功能:

  1. 查看段位排行榜
  2. 查看自己的排名

设计方案

在做设计方案之前,有个细节得注意:段位在数据库和后端计算都是分数形式,比如青铜三,三颗星:13

那怎么设计这个方案呢?

有同学就会说,直接将数据保存在MySQL中,然后在玩家登录进行计算,得出各个所有排行榜。这种方案是可以,但是登录时需要计算,如果单个区服数据过多,就会导致玩家登录的RT太长了。

所以,对于现在来说比较好的设计方案是使用Redis的有序集合

方案细节

我们将段位保存在MySQL的个人排位信息表中,在Redis中会存储多个排行榜,比如全区段位榜,好友段位榜等等;当我们打完一局排位后我们在进行结算时同时也会更新多个段位排行榜(在DDD中一般用领域事件去更新排行榜)。

数据结构

Redis有序集合

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。

分数设计

对于分数设计,我们其实可以直接将段位的分数设置为score即可,但是需要考虑一种情况,就是两个玩家分数相同时,我们一般是将分数+时间戳进行组合,成为一个新的分数。

分数封装和解析代码如下:

//封装成分数
func packScore(score int64) float64 {
   now := time.Now().Unix()
   return float64(score*TimeLength +now)
   //如果排行榜支持负数
   //if score >= 0 {
   // return float64(score*TimeLength + now)
   //} else {
   // return float64(score*TimeLength + now - TimeLength)
   //}
}

//将分数解析
func parseScore(score float64) int64 {
   return int64(score / TimeLength)
}

Demo源码

https://github.com/Eternallyc/leaderboard

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值