玩家排行榜
这一章我们新增一个游戏最常见的功能:玩家胜利次数排行榜。
看上去好像很复杂,先要记录每局的数据,再去排序一下,然后再进行前十名的截取,但其实使用Redis
的某种数据结构的话可以非常容易实现这个功能,那就是Sorted Set
有序集合。
Redis Sorted Set:doc.redisfans.com/sorted_set/…
Sorted Set
是什么东西呢?顾名思义,其实他就是一个Set
结构,也就是里面的元素都是唯一的。那么他是怎么进行排序呢?这是因为在保存一个元素时,还可以为这个元素设定一个设定一个score
,当批量获取这个Set
里数据的时候,就可以获取到根据score
排序后的结果。
下面我们举几个例子:
操作指令:zadd key score member
127.0.0.1:6379> zadd page_rank 10 google.com
(integer) 1
127.0.0.1:6379> zadd page_rank 20 baidu.com
(integer) 1
127.0.0.1:6379> zadd page_rank 15 bing.com
(integer) 1
127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
1) "google.com"
2) "10"
3) "bing.com"
4) "15"
5) "baidu.com"
6) "20"
可以看到,通过zadd
添加元素后,使用zrange
指令就可以获取到经过排序后的结果。
有童鞋就要问了,我们的胜利次数是逐渐增加的呀,zadd
并不能满足需求,zrange
返回的结果也是顺序排列,排行榜应该要按倒序来排。
是的,所以Sorted Set
还有zincrby
、zrevrange
等指令,应该是能满足大部分需求的。
做题时间
- 参考
Redis
文档,使用Sorted Set
完成玩家排行榜功能。
DataCenter
类:
<?php
...
class DataCenter
{
...
public static function addPlayerWinTimes($playerId)
{
$key = self::PREFIX_KEY . ':player_rank';
self::redis()->zIncrBy($key, 1, $playerId);
}
public static function getPlayersRank()
{
$key = self::PREFIX_KEY . ':player_rank';
return self::redis()->zRevRange($key, 0, 9, true);
}
...
}
Logic
类:
<?php
...
class Logic
{
...
private function checkGameOver($roomId)
{
...
if ($gameManager->isGameOver()) {
...
DataCenter::addPlayerWinTimes($winner);
...
}
}
...
}
代码写出来了,我们玩几局游戏,再到Redis
中查看一下是否正常。
127.0.0.1:6379> zrevrange game:player_rank 0 9 withscores
1) "player_789"
2) "2"
3) "player_951"
4) "1"
5) "player_655"
6) "1"
7) "player_351"
8) "1"
可以看到,排行榜数据正确,下一步就是要把排行榜显示到页面上,我们采用一个最简单的方式:新增一个接口返回数据。
做题时间
- 新增一个接口,返回排行榜前十名数据。
- 前端调用接口,并渲染在页面上。
Server
类:
<?php
...
class Server
{
...
public function onRequest($request, $response)
{
...
if ($action == 'get_online_player') {
...
} elseif ($action == 'get_player_rank') {
$data = [
'players_rank' => DataCenter::getPlayersRank()
];
$response->end(json_encode($data));
}
}
}
...
...
<div id="app">
...
<div v-else>
<div v-if="onlinePlayer">
当前在线玩家:{{onlinePlayer}}
</div>
<div v-if="playersRank">
<br>
游戏排行榜:
<br>
<template v-for="times, player in playersRank">
玩家:{{player}} 胜利次数:{{times}}
<br>
</template>
</div>
</div>
...
</div>
<script>
var app = new Vue({
...
data: {
...
playersRank:null
},
...
methods: {
getServerInfo() {
...
$.ajax({
url: 'http://192.168.3.41:8812',
type: 'get',
dataType: 'json',
data: {
'a': 'get_player_rank'
},
success: function (result) {
that.playersRank = result.players_rank
},
error: function () {
}
})
},
...
}
})
</script>
...
代码写完后,重启服务器并访问游戏首页。
本章对应Github Commit
:扩展四:玩家排行榜