チュートリアル(Unity)
ハイスコアランキング機能を作る
Contents |
概要
このページでは、データストアに保存されたハイスコアを使って、ハイスコアランキングを実装する方法を学びます。ランキングは、全体の上位5件を表示したものと、自分の周囲だけを表示したものの2つを実装しましょう。下の画像が完成のイメージ図です。
なお、ログイン機能とハイスコアのサーバー管理機能を実装していない場合は、「ログイン機能を作る」「ハイスコアをサーバーに保存する」を先に済ませておいてください。
シーンファイルのダウンロード
ログイン画面実装時と同様に、今回もランキング表示画面とメインゲーム画面をそれぞれ別のシーンに分けて実装していきます。
下記リンクから、ランキング画面を実装するシーンファイルをダウンロードします。ダウンロードした「LeaderBoard.unity」を、プロジェクトの「Scenes」フォルダにドラッグしてコピーしてください。
シーンのコピーが完了したら、Unityの File → Build Settingsを開き、今コピーしたシーンを「Scenes In Build」に追加(ドラッグ&ドロップ)してください。
このシーンには、既に以下のものが実装されています。
- 各種見出しGUITextオブジェクト
- 順位とプレイヤー名、スコアを表示するGUITextオブジェクト
このページでは、以下の内容を実装していきます。
- メインシーン(Stage.unity)とランキングシーン(LeaderBoard.unity)を切り替える機能
- mobile backendと通信してハイスコアを取得し、ランキングとして表示する機能
メインゲーム画面とランキング画面を切り替える
Manager.csを開き、OnGUIメソッド内を以下のように編集してください。
void OnGUI() {
if( !IsPlaying() ){
drawButton();
// ランキングボタンが押されたら
if ( leaderBoardButton )
Application.LoadLevel("LeaderBoard");
// これ以降はそのまま
// ・・・
}
これで、タイトル画面の「Leader Board」ボタンを押すとランキングシーンが表示されるようになります(ただし中身は空の状態)。
mobile backendに接続してランキングを取得する機能を作る
つづいて、mobile backendからハイスコアを取得して、ランキングデータを作る機能を実装しましょう。
HighScoreクラスと同様、今回のクラスもMVCデザインでいうモデルクラスにあたるので、Unityに依存しない形でコードを書き、ゲームオブジェクトにアタッチしないで使います。
Scriptsフォルダの中に「LeaderBoard.cs」という名前のC#スクリプトを新規作成し、下記の内容を記述してください。
using NCMB;
using System.Collections.Generic;
public class LeaderBoard {
public int currentRank = 0;
public List<NCMB.HighScore> topRankers = null;
public List<NCMB.HighScore> neighbors = null;
// 現プレイヤーのハイスコアを受けとってランクを取得 ---------------
public void fetchRank( int currentScore )
{
// データスコアの「HighScore」から検索
NCMBQuery<NCMBObject> rankQuery = new NCMBQuery<NCMBObject> ("HighScore");
rankQuery.WhereGreaterThan("Score", currentScore);
rankQuery.CountAsync((int count , NCMBException e )=>{
if(e != null){
//件数取得失敗
}else{
//件数取得成功
currentRank = count+1; // 自分よりスコアが上の人がn人いたら自分はn+1位
}
});
}
// サーバーからトップ5を取得 ---------------
public void fetchTopRankers()
{
// データストアの「HighScore」クラスから検索
NCMBQuery<NCMBObject> query = new NCMBQuery<NCMBObject> ("HighScore");
query.OrderByDescending ("Score");
query.Limit = 5;
query.FindAsync ((List<NCMBObject> objList ,NCMBException e) => {
if (e != null) {
//検索失敗時の処理
} else {
//検索成功時の処理
List<NCMB.HighScore> list = new List<NCMB.HighScore>();
// 取得したレコードをHighScoreクラスとして保存
foreach (NCMBObject obj in objList) {
int s = System.Convert.ToInt32(obj["Score"]);
string n = System.Convert.ToString(obj["Name"]);
list.Add( new HighScore( s, n ) );
}
topRankers = list;
}
});
}
// サーバーからrankの前後2件を取得 ---------------
public void fetchNeighbors()
{
neighbors = new List<NCMB.HighScore>();
// スキップする数を決める(ただし自分が1位か2位のときは調整する)
int numSkip = currentRank - 3;
if(numSkip < 0) numSkip = 0;
// データストアの「HighScore」クラスから検索
NCMBQuery<NCMBObject> query = new NCMBQuery<NCMBObject> ("HighScore");
query.OrderByDescending ("Score");
query.Skip = numSkip;
query.Limit = 5;
query.FindAsync ((List<NCMBObject> objList ,NCMBException e) => {
if (e != null) {
//検索失敗時の処理
} else {
//検索成功時の処理
List<NCMB.HighScore> list = new List<NCMB.HighScore>();
// 取得したレコードをHighScoreクラスとして保存
foreach (NCMBObject obj in objList) {
int s = System.Convert.ToInt32(obj["Score"]);
string n = System.Convert.ToString(obj["Name"]);
list.Add( new HighScore( s, n ) );
}
neighbors = list;
}
});
}
}
順に解説します。まずfetchRankメソッドでは、現在の自分のハイスコア「より大きい」スコアを持つレコードをWhereGreaterThanメソッドで検索し、CountAsyncメソッドでその数を取得しています。たとえば自分より大きいスコアが3人いたら、自分は4位だということがわかります。
次にfetchTopRankersメソッドでは、OrderByDescendingメソッドでスコアを降順にしつつ、Limitプロパティを5に設定することで、スコアの高い上位5人だけを取得しています。取得した5件のレコードをHighScoreクラスのListとして保存します。
fetchNeighborsメソッドでは、先述した降順並び替えとLimitの設定に加えて、現在の自分の順位によってSkipプロパティを設定することで、自分の周囲5件だけを取得しています。このように、SkipやLimit、ソートの指定によって、様々なデータの取得が可能です。詳しくはSDKリファレンスをご覧下さい。
HighScoreクラスを拡張する
今回はランキングを、「HighScoreクラスを5つ含んだList」という形で実装しました。そこで、HighScoreクラスに「自分のプレイヤー名とハイスコア」を文字列として出力させるメソッドを追加しましょう。
HighScore.csを開き、以下のメソッドを追加してください。
// ランキングで表示するために文字列を整形 -----------
public string print()
{
return name + ' ' + score;
}
ランキングを画面に表示する機能の実装
最後に、ランキング画面に遷移したらランキングの取得を開始し、読み込みが完了したら画面に表示する機能を実装しましょう。
LeaderBoardシーンに「LeaderBoardManager」という名前で空のオブジェクトを作成し、同名のスクリプトを新規作成・アタッチしてください。その後、スクリプトを以下の内容に編集してください。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LeaderBoardManager : MonoBehaviour {
private LeaderBoard lBoard;
private NCMB.HighScore currentHighScore;
public GameObject[] top = new GameObject[5];
public GameObject[] nei = new GameObject[5];
bool isScoreFetched;
bool isRankFetched;
bool isLeaderBoardFetched;
// ボタンが押されると対応する変数がtrueになる
private bool backButton;
void Start ()
{
lBoard = new LeaderBoard();
// テキストを表示するゲームオブジェクトを取得
for( int i = 0; i < 5; ++i ) {
top[i] = GameObject.Find ("Top" + i);
nei[i] = GameObject.Find ("Neighbor" + i);
}
// フラグ初期化
isScoreFetched = false;
isRankFetched = false;
isLeaderBoardFetched = false;
// 現在のハイスコアを取得
string name = FindObjectOfType<UserAuth>().currentPlayer();
currentHighScore = new NCMB.HighScore( -1, name );
currentHighScore.fetch();
}
void Update()
{
// 現在のハイスコアの取得が完了したら1度だけ実行
if( currentHighScore.score != -1 && !isScoreFetched ){
lBoard.fetchRank( currentHighScore.score );
isScoreFetched = true;
}
// 現在の順位の取得が完了したら1度だけ実行
if( lBoard.currentRank != 0 && !isRankFetched ){
lBoard.fetchTopRankers();
lBoard.fetchNeighbors();
isRankFetched = true;
}
// ランキングの取得が完了したら1度だけ実行
if( lBoard.topRankers != null && lBoard.neighbors != null && !isLeaderBoardFetched){
// 自分が1位のときと2位のときだけ順位表示を調整
int offset = 2;
if(lBoard.currentRank == 1) offset = 0;
if(lBoard.currentRank == 2) offset = 1;
// 取得したトップ5ランキングを表示
for( int i = 0; i < lBoard.topRankers.Count; ++i) {
top[i].guiText.text = i+1 + ". " + lBoard.topRankers[i].print();
}
// 取得したライバルランキングを表示
for( int i = 0; i < lBoard.neighbors.Count; ++i) {
nei[i].guiText.text = lBoard.currentRank - offset + i + ". " + lBoard.neighbors[i].print();
}
isLeaderBoardFetched = true;
}
}
void OnGUI () {
drawMenu();
// 戻るボタンが押されたら
if( backButton )
Application.LoadLevel("Stage");
}
private void drawMenu() {
// ボタンの設置
int btnW = 170, btnH = 30;
GUI.skin.button.fontSize = 20;
backButton = GUI.Button( new Rect(Screen.width*1/2 - btnW*1/2, Screen.height*7/8 - btnH*1/2, btnW, btnH), "Back" );
}
}
Startメソッドでハイスコアの取得を開始し、ハイスコアの取得が終わったら自分の順位の取得を開始し、それが終わったらランキングの取得を開始しはじめます。それぞれの取得はAsync系のメソッド、つまり非同期に行われるので、処理の終了をフラグで判断し、同期処理化しています。ランキングの取得まで終わったら、GUITextに順位とプレイヤー名、スコアを表示しています。
OnGUIとdrawMenuメソッドでは、いつものようにボタンの描画と画面遷移を行っています。
動作確認
おつかれさまでした!以上でハイスコアランキング機能の実装が完了しました。LogInシーンを開いてゲームを実行し、ランキングが表示されることを確かめましょう。事前に5人以上プレイヤーを作ってスコアを登録しておくとよいでしょう。
- ボタンを押すことでランキング画面とメインゲーム画面を移動できる
- トップ5のスコアが表示されている
- 自分の前後2件のスコアが表示されている
お探しの内容が見つからなかった場合はユーザーコミュニティ
もご活用ください。(回答保証はいたしかねます)
なお、 Expertプラン以上のお客様はテクニカルサポートにてご質問を承らせて頂きます。
推奨画面サイズ1024×768px以上