標籤:style blog http io ar os 使用 sp for
1.熱門排行榜的需求
我有做了一個網站 http://www.cgame360.com/,專門放一些簡單的html5遊戲。現在有2個需求,我想獲得一個遊戲的top 10的使用者的分數,還有一個是某個使用者的排名,加上前後4名的人員。中少了名字,那個cocos2d js輸入框有點問題就沒加了。 現在的問題是用什麼資料庫來儲存比較好?我想要儘可能快的尋找出資料。 我搞過mysql這種關係型的資料庫,第一感覺用在這裡會很慢。資料量一大就會很慢,因為它排序的時候會對所有資料進行處理。還有第二個需求用sql語句會很蛋疼,我還沒想到高效的實現方式。第一個前10名的,可以搞一個表來專門存前10名的。主要就是卡在第二個需求。 我google了下,發現nosql比較適合現在的需求。nosql比較有名的是Hadoop,MongoDB。但我發現一個更加適合這個需求的資料庫redis.
2.redis中的有序集合
2.1redis有序集合插入一條資料
這裡沒時間再從安裝redis講起了。我記得好像Mac系統比較容易用,windows好像不太好用redis。 redis的有序集合插入一條資料非常容易: ZADD key score memeber具體例子: ZADD game1 89 tom這樣game1中就有一條資料了Tom的分數是89
2.2 redis得到排名在某個範圍的元素列表
ZRANGE key start stop [withscores]ZREVRANGE key start stop [withscores]
具體例子:ZRANGE game1 0 -1 withscores這樣就可以得到game1中所有的記錄了,從小到大排序,-1表示最後一個元素的意思。那麼我們想要得到前10的記錄用什麼命令呢?非常簡單:ZRANGE game1 -10 -1 withscores -10表示往數10個的意思。下面是我mac機執行的輸出:
127.0.0.1:6379> zrange g_1 -10 -1 withscores 1) "tom5" 2) "506" 3) "tom6" 4) "507" 5) "hug" 6) "600" 7) "tom" 8) "5000" 9) "tom8"10) "5088"11) "tom9"12) "5089"13) "tom10"14) "5090"15) "tom11"16) "5091"17) "tom12"18) "5092"19) "tom13"20) "5093"
zrevrange 是表示逆向的意思,會從大到小輸出。
2.3 redis得到一個元素的排名
ZRANK key member ZREVRANK key memeber具體例子: zrank game1 tom
2.4 redis 得到一個元素的分數
ZSCORE key member具體例子:zscore game1 tom
3.PHP 中使用redis
上面講的redis命令已經夠我們使用了,接下來就是用redis與java或者php等伺服器語言來組成一個服務了。我這裡選擇了PHP,我感覺使用者提交一個分數用http的post,得到熱門排行榜的分數用php的get夠用了。php中使用redis有兩種方式,分別是predis 和phpredis,前者是完全使用php的,後者是c語言編寫的php擴充。後者效能會好些,但需要安裝php擴充比較麻煩。predis非常簡單,就是一些php檔案,扔到網站目錄下就能工作了。這裡選擇使用了predis.
3.1 插入一條資料
<?phprequire ‘./predis/autoload.php‘;$redis = new Predis\Client( array( ‘scheme‘=>‘tcp‘, ‘host‘=>‘127.0.0.1‘, ‘port‘=>6379, ));//header("content-type:text/html;charset=utf-8");if(trim($_POST[‘game_id‘]) == ‘‘ || trim($_POST[‘user_name‘]) == ‘‘ || trim($_POST[‘score‘]) == ‘‘){ echo ‘need more information!‘; exit;}else{ // echo ‘OK‘; // echo $_POST[‘game_id‘]; // echo $_POST[‘user_name‘]; // echo $_POST[‘score‘]; $game_id = "g_" . $_POST[‘game_id‘]; $name = $_POST[‘user_name‘]; $score = $_POST[‘score‘]; if($score > 0){ $beforeScore = $redis->zscore($game_id, $name); if($score > $beforeScore){ $itemScore = array($name => $score); $redis->zadd($game_id, $itemScore); } } }
主要這裡我就簡單地判斷了下他現在的分數是不是比以前的高,比以前的高就插入一條資料。非常簡單。
3.2 得到前10的玩家分數
<?phprequire ‘./predis/autoload.php‘;$redis = new Predis\Client( array( ‘scheme‘=>‘tcp‘, ‘host‘=>‘127.0.0.1‘, ‘port‘=>6379, ));if(trim($_GET[‘game_id‘]) == ‘‘){ echo ‘need game_id‘;}else{$game_id = "g_" . $_GET[‘game_id‘]; $board_score = $redis->zrange($game_id, -10, -1, ‘withscores‘); //print_r($board_score); echo json_encode($board_score); //echo $board_score;}
這裡看起來非常簡單,最後我用了json_encode把php中的數群組轉換成json了。這樣方便處理。
3.3得到我的排名
<?phprequire ‘./predis/autoload.php‘;$redis = new Predis\Client( array( ‘scheme‘=>‘tcp‘, ‘host‘=>‘127.0.0.1‘, ‘port‘=>6379, ));if(trim($_GET[‘game_id‘]) == ‘‘ || trim($_GET[‘user_name‘]) == ‘‘){ echo ‘need game_id and name‘;}else{$game_id = "g_" . $_GET[‘game_id‘]; $user_name = $_GET[‘user_name‘]; $userCurrentRange = $redis->zrevrank($game_id, $user_name); //echo ‘current range:‘ . $userCurrentRange; $result = array(); if(true){ $halfCount = 4; $leftRank = $userCurrentRange - $halfCount; $rightRank = $userCurrentRange + $halfCount; if($leftRank < 0){ $leftRank = 0; } $board_score = $redis->zrevrange($game_id, $leftRank, $rightRank, ‘withscores‘); $index = 0; foreach($board_score as $name => $score){ if($name == $user_name){ break; }else{ $index = $index + 1; } } $firstRank = $userCurrentRange - $index + 1; foreach($board_score as $name => $score){ $eachItem = array(); $eachItem[‘name‘] = $name; $eachItem[‘score‘] = $score; $eachItem[‘rank‘] = $firstRank; $result[] = $eachItem; $firstRank = $firstRank + 1; } echo json_encode($result); }else{ echo json_encode($result); } }
這裡稍微複雜了一點點,我先得到這個玩家的排名,這樣就可以得到他前後4名玩家的排名區間了,用下zrevrange就ok了。就是要注意left是負數的話是其他的意思,所以要避免是負數。最後我對php數組中加入了排名資訊,再次以json返回。
4.0 講下cocos2d js中的http
php已經可以返回json的資料了,講下cocos2d js中如何使用http 顯示top 10的玩家資訊。這裡直接給出代碼了,也比較簡單。主要要注意的是要對返回的資料進行JSON.parse處理。插入資料用post,得到熱門排行榜資訊用get就OK了。我也沒加反作弊功能。
getJsonFromUrl:function(){ var xhr = cc.loader.getXMLHttpRequest(); var args = "?game_id=" + gameId; xhr.open("GET", rankBoardURL + args, true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && (xhr.status >= 200 && xhr.status <= 207)) { var response = xhr.responseText; cc.log("res:" + response); cc.log("send success"); var obj = JSON.parse(response); this.initContent(obj); } }.bind(this); xhr.send(); }, initContent:function(jsonValue){ var size = cc.director.getWinSize(); var fontDefBlueStroke = new cc.FontDefinition(); fontDefBlueStroke.fontName = "Arial"; fontDefBlueStroke.fontSize = 50; fontDefBlueStroke.textAlign = cc.TEXT_ALIGNMENT_LEFT; var jsonLength = 0; for(var name in jsonValue){ jsonLength++; } cc.log("jsonlength:" + jsonLength); var nameMargin = 50; var nameStartPositionY = 800 - nameMargin * jsonLength; var lastRank = jsonLength; for(var name in jsonValue){ cc.log(name); cc.log(jsonValue[name]); this.rankLabel = new cc.LabelTTF(lastRank + ‘:‘, fontDefBlueStroke); this.addChild(this.rankLabel); this.rankLabel.x = 100; this.rankLabel.y = nameStartPositionY; this.rankLabel.setAnchorPoint(cc.p(0, 0.5)); this.nameLabel = new cc.LabelTTF(name, fontDefBlueStroke); this.addChild(this.nameLabel); this.nameLabel.x = size.width * 0.5 - 100; this.nameLabel.y = nameStartPositionY; this.nameLabel.setAnchorPoint(cc.p(0, 0.5)); this.scoreLabel = new cc.LabelTTF(parseFloat(jsonValue[name]).toFixed(2), fontDefBlueStroke); this.addChild(this.scoreLabel); this.scoreLabel.x = size.width * 0.5; this.scoreLabel.y = nameStartPositionY; this.scoreLabel.setAnchorPoint(cc.p(0, 0.5)); nameStartPositionY = nameStartPositionY + nameMargin; lastRank = lastRank - 1; } }
最後大家玩下這個使用了上面講到的技術的html5遊戲,用cocos2d js開發的。http://www.cgame360.com/halloweengame/
整個熱門排行榜的PHP服務我已經打包成一個檔案了,點擊下面的連結下載。包含了predis,如果你有mac系統或者linux系統,安裝好php,redis等等,把這個解壓到網站根目錄應該就可以用了的.我也是第一次使用redis,哪裡用錯請評論中指出,謝謝。http://www.waitingfy.com/?attachment_id=1421
http://www.waitingfy.com/archives/1420
休閒遊戲中使用redis作為熱門排行榜資料存放區