mBaaSお役立ちブログ

Monacaで作ったゲームにランキング機能を追加してみよう

ゲームとmBaaSを組み合わせて使えるものとして、主に以下が考えられます。

  • ランキング
  • チャット(メッセージ)

今回はその一つ、ランキング機能を実装してみたいと思います。題材として使うのはMonacaのサンプルプロジェクトにあるブロック崩しになります。これをベースにすることで、ランキング機能だけを手軽に実装できます。

必要なもの

  • Monacaのアカウント(無料で作成できます)
  • ニフティクラウド mobile backendのアカウント(無料で作成できます)

ブロック崩しのプロジェクトを作成

まずはMonacaにてブロック崩しプロジェクトを作成します。これはサンプルで並んでいる中のブロック崩しを選択するだけです。

これをベースに進めていきます。

ニフティクラウド mobile backendの準備

アカウントを作成した後に新しいアプリを作成しますので、アプリケーションキーとクライアントキーはすでにあるものとします。

Monacaの設定メニュー>JS/CSSコンポーネントの追加と削除を選択します。

検索キーワードにncmbと入力します。そして出てくるダイアログを順番に進めていけばニフティクラウド mobile backendのJavaScript SDKが読み込まれるようになります。ローダーに追加するファイルとして、 ncmb.min.js を忘れずに選択しておいてください。

www/jsフォルダ以下に、ncmbController.jsというファイルを作成して、index.htmlで読み込むようにします。

<script src="js/ncmbController.js"></script>

これで準備は完了です。

mBaaSの初期設定を行う

まず最初に初期設定だけを行います。 ncmbController.js を開いて次のように編集します。アプリケーションキーとクライアントキーはそれぞれ読み替えてください。

var ncmbController = {
    APPLICATION_KEY: "YOUR_APPLICATION_KEY",
    CLIENT_KEY: "YOUR_CLIENT_KEY",

    ncmb: null,

    // 初期化
    init: function(screenSize) {
        var self = this;
        // mobile backendの初期化
        self.ncmb = new NCMB(self.APPLICATION_KEY, self.CLIENT_KEY);
    },
}

次に js/main.js を開いてこのinit処理を呼び出します。

function init() {
  :
  BB.screenSize = setBound();
  // この下に追加
  ncmbController.init();

これでmBaaSの初期化が行われるようになりました。

ゲーム終了時にスコアを保存する

次にゲームオーバーやクリアした時にスコアを保存するようにします。 ncmbController.js を開いて処理を追加します。この中で行っているのは主に3つの処理になります。

  1. ユーザ名(username)が設定されていなかったら、ダイアログを出す。入力されたユーザ名はlocalStorageに保存
  2. スコアオブジェクト(ScoreClass)を新規作成してデータを保存
  3. 保存したらスコアの高い順にデータを取得して、自分が何位か表示する

このように自分の得点より高いデータ数を調べることで簡単に順位を調べることができます。

var ncmbController = {
  :
  // スコア送信
  sendScore: function(score) {
      var self = this;
      
      // ユーザ名を保存します
      var username = localStorage.getItem("username");
      if (username === null || username === "") {
          username = prompt("ユーザ名を指定してください");
          localStorage.setItem("username", username);
      }
      
      // スコアを保存します
      var Score = self.ncmb.DataStore("ScoreClass");
      var scoreData = new Score({score: score, username: username});
      scoreData.save()
          .then(function (saved) {
              
              // 自分よりスコアの高いデータの数を調べて、+1したものを自分の順位としています
              Score.greaterThan("score", score)
                  .count()    // 件数を結果に含める
                  .fetchAll()
                  .then(function(scores){
                      // 0件のとき正しく動作するように条件分岐
                      var rank = (scores.count !== undefined) ? parseInt(scores.count) + 1 : 1;
                      alert("スコア送信完了!\n今回の順位は #" + rank + " でした!");
                  })
          })
         .catch(function(err){
              console.log(err);
          });
  },

js/main.js を開いてsendScoreを呼び出します。

// Game Over        
endGame: function() {
    BB.gameState = GAMESTATE_STOP;
    vibrate();
    // 追加
    ncmbController.sendScore(BB.score);
},

// Game Clear
clearGame: function() {
    // 以下をコメントアウト
    // if(typeof navigator.notification !== 'undefined') navigator.notification.alert("Cleared!", function(){}, "Congraturations");
    // else alert("Cleared!");
    BB.gameState = GAMESTATE_STOP;
    // 追加
    ncmbController.sendScore(BB.score);
}

これでスコアの保存が完了です。

ランキングを表示する

最後にランキングの表示です。ブロック崩しの画面はCanvasで作られていますので、画面部分を修正します。 js/main.js を開きます。以下をreset処理の中に追加します。タップした時のイベントとして、ncmbController.showRanking(); を実行する指定を行っておきます。

reset: function() {
  :
  var rankingLabel = new PIXI.Text("RANKING", {font: "24px/1.2 vt", fill: "red"});
  rankingLabel.position.x = 80;
  rankingLabel.position.y = BB.renderer.height - 52;
  BB.stage.addChild(rankingLabel);
  rankingLabel.buttonMode = true;
  rankingLabel.interactive = true;
  rankingLabel.click = rankingLabel.tap = function(data) {
      ncmbController.showRanking();
  };
  setTimeout(function() {
      rankingLabel.setText("RANKING"); //for Android
  }, 1000, rankingLabel);
  :

では js/ncmbController.js を開いて showRankingを実装します。ここでは次の処理を行っています。

  1. スコアの高い順に10件取得
  2. ランキング表のHTMLを生成
  3. ランキング画面を表示
showRanking: function() {
    var self = this;

    //スコア情報を取得するため、クラスを作成
    var Score = self.ncmb.DataStore("ScoreClass");

    //スコアを降順に10件取得
    Score.order("score", true)
        .include("user")
        .limit(10)
        .fetchAll()
        .then(function(results){
    
            //ランキング表のHTML生成
            var tableSource = "";
            if(results.length > 0){
                for(i=0; i<results.length; i++){
                    var score = results[i],
                        rank = i + 1,
                        value = parseInt(score.score),
                        displayName = "NO NAME";
    
                    tableSource += "<li class=\"list__item list__item--inset\">"
                        + rank + ":"
                        + score.username
                        + " (" + value + ")</li>";
                }
            } else {
                tableSource += "<li class=\"list__item list__item--inset\">ランキングはありません</li>";
            }
            document.getElementById("rankingTable").innerHTML = tableSource;
            //ランキング画面を表示する
            document.getElementById("ranking").style.display = 'block';
        })
        .catch(function(err){
          console.log(err);
        });
},

これが終わったら最後にHTMLを追加します。 index.html を開いて、次のように変更します。

<body>
  <div id="ranking" class="ranking">
    <h2>ランキング</h2>
    <ul id="rankingTable" class="list list--inset rankingTable">
    </ul>
    <ons-button class="login-button" id="closeRanking">閉じる</ons-button>
  </div>
</body>

ランキングを閉じた時の処理を追加する

HTMLにあるcloseRankingについて実装します。js/ncmbController.js を開いて init処理の中に追加します。

init: function(screenSize) {
    var self = this;
    self.ncmb = new NCMB(self.APPLICATION_KEY, self.CLIENT_KEY);    // mobile backendの初期化
    
    // 下記を追加
    document.getElementById("closeRanking").addEventListener("click", function () {
        self.closeRanking();
    });
},

ボタンを押した時の処理を追加したので、その実装を行います。

var ncmbController = {
  :
  //ランキング画面を閉じる
  closeRanking:function() {
     document.getElementById("ranking").style.display = 'none';
   }
}

最後にランキング表示部分のデザインを整えます。 css/style.css を開いて、次の内容を追加します。

.ranking{
    display: none;
    position: absolute;
    width: 100%;
    min-height: 100%;
    color: #fff;
    background: #000;
    text-align: center;
    z-index: 3;
}

.rankingTable{
    margin: 10px 0;
}

これで完了です。

試してみる

では実際に試してみます。ブロック崩しゲームがはじまります。

クリアしたりゲームオーバーになるとダイアログが出ます(初回のみ)。

ここでユーザ名を入力すると、データが保存されてランクが何番目だったか表示されます。続けてゲームを遊ぶと結果のランキングが上下します。

画面下にはRANKINGという表示があり、それをタップするとランキング順位が表示されます。閉じるという文字をタップすると、ランキングが閉じます。


このようにしてゲームにランキング機能が簡単に追加できます。今回のソースコードはNIFTYCloud-mbaas/brakeout_rankingにアップしてあります。皆さんのゲームにもランキング機能を追加して、オンライン上で他のユーザと競えるようにしてみてはいかがでしょう?

今回は簡易版ですが、ユーザ登録を含めた本格的なものはチュートリアル (JavaScript) : Monacaアプリのゲームにランキング機能をつける | ニフティクラウド mobile backendに掲載されています。こちらも合わせてご覧ください。

バックナンバー