データをサーバーにアップしてVRレーシングゲームのスコアとする

[この記事](http://qiita.com/fumishitan/items/2b60f27b79fdb4772be4)の７回目。

今回からオンラインランキングを作る運びになります。
そのために、ゴールタイムをサーバーに保存することから記事を書いていきます。
利用するサーバーは[ニフティクラウドmobile backend](http://mb.cloud.nifty.com/)というクラウドサービスを使います。
無料から利用でき、DB構築・サーバースクリプト開発をしなくてもデータ保存が行えることもありこれを選びました。

今回やることは以下です
・NCMB（Nifty Cloud Mobile Backend）の設定
・ゴールタイムの保存ロジックを書く
・動作確認

## NCMBの設定

まずは無料登録になります。
下記から行えます。


ログインしたのち、利用規約などを終えると下記のような画面が出ます

![スクリーンショット 2015-07-27 23.15.41.png](https://qiita-image-store.s3.amazonaws.com/0/55227/e9edb6e0-5eba-8c6a-81db-4f94a92754aa.png)


これは今回作るアプリ用のサーバー環境を作るぐらいの意味にとっておきましょう。
そうしたら空欄に「ncmb_hacoscon」とでも入力して「新規作成ボタン」を押してください
（実際のところなんでもいいです）

すると下記のような画面が出ます。

![スクリーンショット 2015-07-27 23.16.54.png](https://qiita-image-store.s3.amazonaws.com/0/55227/96d749e4-6471-2d75-789f-e36140eee2f0.png)


ここの赤丸のキーによりサーバーへの接続認証などが行えますのでこちらをUnityのプロジェクトに設定します

以下設定方法

まず、SDKのDLとUnityプロジェクトへのインポートを行います。
SDKのDLは以下のGithubのページから行ってください

https://github.com/NIFTYCloud-mbaas/ncmb_unity/releases

DLしたZIPを展開すると以下のようなファイル構成になっています。

![スクリーンショット 2015-07-27 23.23.38.png](https://qiita-image-store.s3.amazonaws.com/0/55227/a3b2cdc8-7bd5-738b-3e3e-ebd67d9f1ae2.png)


インポートしたいUnityプロジェクトを開いた状態で
上記の赤丸で囲われた部分のファイルをダブルクリックしてください
すると下記のようなダイアログが出てきます

![スクリーンショット 2015-07-27 23.25.15.png](https://qiita-image-store.s3.amazonaws.com/0/55227/add5aa30-f296-4f63-c5ee-a7b7f28d775f.png)


右下のImportをクリックするとインポートが行えます。

するとAssetにncmbのフォルダが現れます

次にキーの設定に移ります
キーはスタートシーンに設定します。
スタートシーンを開いてください。

スタートシーンにGameobjectを作っていただき、
NCMBSettingsとご入力ください

そしてncmbフォルダ内のNCMBSettings.csをアタッチしてください

![スクリーンショット 2015-07-27 23.27.30.png](https://qiita-image-store.s3.amazonaws.com/0/55227/2279fa4b-9170-3949-f800-aa7254480fd8.png)


インスペクタが下記のような表示になるかと思います

![スクリーンショット 2015-07-27 23.35.17.png](https://qiita-image-store.s3.amazonaws.com/0/55227/daf5111b-7c3e-bdfe-cae5-0612ea2f8f0e.png)


赤丸部分に上から順にAPPKEYとClientKeyをコピペしてください

これでNCMBの設定は終了です

## ゴールタイムの保存ロジックを書く

ゴールタイムを保存するロジックは
Timer.cs内に書きます
OnGoalメソッドに以下のコードを追記してください

```csharp
//クラスの指定
NCMBObject timeClass = new NCMBObject("Time"); //カラムと挿入するデータの指定
timeClass["time"] = lapTime; //非同期でのアップロード
timeClass.SaveAsync();
```

１行目クラスを指定しています
2行目でカラムと挿入するデータを指定しています
3行目で非同期でデータを入れています。

では実際に動作してみて、コンパネで確認してみましょう！

![スクリーンショット 2015-07-27 23.40.19.png](https://qiita-image-store.s3.amazonaws.com/0/55227/0e418708-034f-da80-b244-f6fe0b2a76ed.png)


赤丸部をクリックすると下記のようなデータが見えているかと思います
そうしたら成功です！

最後にTimer.csの全部のコードを載せておきます。

```csharp:Timer.cs

using UnityEngine;
using System.Collections;
using NCMB;

public class Timer : MonoBehaviour {
 float startTime;
 float lapTime;
 bool goal = false;
 bool ranking = false;
 private LeaderBoard lBoard;
 bool isRankFetched;
	
 void Start () {
  startTime = Time.time;
  lBoard = new LeaderBoard();
   // フラグ初期化
   isRankFetched  = false;
  }
	
	
  void Update () {
   if (goal == false) {
     // 現在の経過時間を算出
     lapTime = Time.time - startTime;
   }
  }
	
  void OnGUI(){
   if (goal == false) {
    // 現在の経過時間を表示
    float timer_x = Screen.width * 8 / 10;
    float timer_y = Screen.height / 10;
    float timer_w = Screen.width * 3 / 10;
    float timer_h = Screen.height / 2;
    GUI.Label (new Rect (timer_x, timer_y, timer_w, timer_h), "Time" + lapTime.ToString ());
    } else {
     // ゴールタイムを表示
     float goal_x = Screen.width / 2;
     float goal_y = Screen.height / 5;
     float goal_w = Screen.width * 3/ 10;
     float goal_h = Screen.height / 10;
     if(ranking == false){
       GUI.Label (new Rect (goal_x - goal_w/2, goal_y, goal_w, goal_h), "Your Goal Time!");
       GUI.Label (new Rect (goal_x - goal_w/2, goal_y*2, goal_w, goal_h), lapTime.ToString ());
     if (GUI.Button(new Rect(goal_x - goal_w, goal_y*3, goal_w, goal_h), "ReStart")) {
       Application.LoadLevel ("run");
     }
    if(GUI.Button(new Rect(goal_x, goal_y*3, goal_w, goal_h), "Ranking")){
       ranking = true;
    }
  }else{
       // 現在の順位の取得が完了したら1度だけ実行
       if( !isRankFetched ){
         lBoard.fetchTopRankers();
         isRankFetched = true;
       }
       
       // ランキングを描画
       if( lBoard.topRankers != null ){
         GUI.Label (new Rect (goal_x-goal_w/2, 15, goal_w, goal_h),"Top Ranking");
         for( int i = 0; i < lBoard.topRankers.Count; ++i) {
           GUI.Label (new Rect (goal_x-goal_w/2, 10 + goal_y*(i+1)/2, goal_w, goal_h),"Time"+ (i+1) + "."+ lBoard.topRankers[i].print());
         }
       }
				
       if (GUI.Button(new Rect(goal_x - goal_w/2, 10 + goal_y*3, goal_w, goal_h), "Back")) {
         ranking = false;
       }
    }
   }
  }
	
	// Goal到着が検知されたとき
  void OnGoal(){
   goal = true;
   //クラスの指定
   NCMBObject timeClass = new NCMBObject("Time"); //カラムと挿入するデータの指定
   timeClass["time"] = lapTime; //非同期でのアップロード
   timeClass.SaveAsync();
  }
}

```