(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

Unity+Parseでネットワークを介してデータ管理【Unity】【Parse】


このエントリーをはてなブックマークに追加

2016.04.28追記


残念がら、Parseのサービスは終了してしまいました……、

同様の機能が使いたい場合はニフティクラウドモバイルバックエンドがオススメです!



追記おわり


Parse

以下のような記事を見かけまして、

なにやらParseさんはDBを勝手に作ってくれて、データのやり取りやユーザ登録&認証も簡単!みたいな感じで「Parseってプッシュ通知だけじゃなかったの…!」となかなかの衝撃でした。


Unityにも対応

ただ、「俺Unity使ってるしな〜Unity対応してなきゃ無理だわ〜」と思ってたら

UnityのSDKが標準で準備されてる!便利!!

マジか!使うしかない!!という事で使ってみました。
結論から言うとめっちゃ簡単でした。


Parseとは

そもそもParseとはなんぞやってことで、上記の二つの記事でもあるように、自分でサーバー立てなくても楽に色々出来るよってモノです。
出来る事を列挙すると、

  • ユーザ登録&認証
  • データの保存、読み込み
  • データの保存はサイト上からも行える。
  • データの読み込みはクエリを指定して行える。
  • プッシュ通知が送れる
  • なんか色々分析できる?
  • クラウドコードとやらで機能が拡張できる?

なんとも多機能!サーバーサイドに興味がない人にはうってつけなサービスですね。


価格、制限

でもお高いでしょ〜?という事ですが、当たり前のように基本無料!いやはや良い時代です本当に。

もちろん制限はあります。無料で使える範囲は以下の通りです。

Parse | Announcement

  • 1秒間に30リクエスト
  • 同時に実行できるジョブは一つ
  • ファイルストレージは20GBまで
  • DBストレージは20GBまで
  • データ転送量は2TBまで
  • プッシュ通知は月に100万端末(同じ端末なら送り放題?)

ファイルストレージとDBストレージの違いが良く分からない…と思ったら、DBにデータを登録するのとは別に画像とかのファイルもアップ出来るみたいです!スゲー

見ての通り、普通にアプリ作ってる分にはまず越えない制限なので、安心して使えますね。というかむしろこの制限を越えたい!!


もし仮にこの制限を越える状況になった場合は越えた分だけ従量課金するようです。以下の記事が分かり易かったので丸投げ!

Parseの新しい料金プランでは、特定の月内で任意のタイミングで秒毎のAPIリクエスト制限を変更することができ、 その利用料金は「時間単位の日割り計算で請求される」ということです。

どうやら制限を越えても時間単位で課金されるため、そこまで高くならない様子。これはイイネ!
ただ、越えたら自動で課金されるというわけでは無く、あくまで設定するのは自分のようです。


Unity+Parseでネットワークを介してデータ管理

長い前置きでしたが、ここからが本題。
今回はUnity+Parseでデータベースを作って、ネットワーク上でデータを管理していきたいと思います。

アカウント作成

まずはParseが使えるようにアカウント作成を以下のサイトで行います。


f:id:kan_kikuchi:20150103201440p:plain


右上のSign upから登録が行えます。
GitHubアカウント等でも使えるみたい。


アプリ登録、設定

Parseを実装したいアプリを先ほどのサイトから登録します。


f:id:kan_kikuchi:20150103201449p:plain


ログインした後、[Create a new App]を押し、その下に出てきたウィンドウにアプリ名を記入し[Create]を押します。

なお、登録したアプリの削除は[Setting]-[General]-[Delete App]から行えます。


f:id:kan_kikuchi:20150104082729p:plain


次に、作成したアプリの[quickstart guide]を押した後、[Data]-[Unity]-[Existing project]と順番に選択していくと、


f:id:kan_kikuchi:20150103202447p:plain


f:id:kan_kikuchi:20150103202452p:plain


f:id:kan_kikuchi:20150103202455p:plain


f:id:kan_kikuchi:20150103202458p:plain


[Download the Parse Unity SDK]というのが表示されるのこれをクリック。


f:id:kan_kikuchi:20150103213718p:plain


ダウンロードしたファイルを解凍し、解凍されたフォルダの中にある[Parse.Unity]-[Parse.Unity.dll]だけUnityのProjectにドラック&ドロップ。AndroidやiOSで動かす場合もこのファイルのみで大丈夫です。


f:id:kan_kikuchi:20150103213911p:plain


その後、てきとうなオブジェクトに[Parse Initialize Behaviour]をアタッチし、[Application ID]と[Dotnet Key]を設定します。


f:id:kan_kikuchi:20150103223532p:plain


[Application ID]と[Dotnet Key]はParseのサイトにログインし任意のアプリを選択した後、[Settings]-[Keys]から確認できます。


f:id:kan_kikuchi:20150103223619p:plain


これで設定完了!


データ形式の設定とデータ登録

Parseではデータ形式の設定やデータの登録をParseのサイト上、スクリプト上の両方から行えます
ここでは、サイト上から行う手順を紹介します。

まず、データの形式であるクラスを作成します。
クラスの作成は[Core]-[Data]-[Add Class]から行えます
今回はSampleClassという名前にしました。


f:id:kan_kikuchi:20150104084848p:plain


次にどんなデータを保存するか、という設定を[+Col]から列を追加して行います。
この際、データの型を[Select a type]、データの名前を[Column name]から設定します。
今回はColumn1(string)とColumn2(number)を追加しました。


f:id:kan_kikuchi:20150104084854p:plain


データ形式の登録は以上です。
この形式に沿ったデータを登録する時は[+Row]をクリックして行を追加します。


f:id:kan_kikuchi:20150104084900p:plain


追加された行には何も値が設定されていないので、先ほど設定したColumn1やColumn2をクリックして、値を入力します。


f:id:kan_kikuchi:20150104084904p:plain


これでデータの登録も完了!


スクリプトからデータ登録

今度はスクリプトからデータを登録する方法です。
なお、データ形式は上記のサイト上で行ったものと同じですが、いきなりスクリプトからデータを登録しても問題ありません。

コードは以下の通りです。


入力

NGUIを使って登録するデータを入力しています。


f:id:kan_kikuchi:20150104090510p:plain


例えば、上記の[aaa]をStringInput.valueで取得できる感じです。


ParseObject

ParseObjectがサイト上で登録した時のクラスになります。
インスタンスを作成する際にstringでクラス名を指定します。

ParseObject parseObject = new ParseObject (PARSE_OBJECT_NAME);

データを登録する時は、ParseObject[データ名]またはParseObject.Add(データ名, 値)を使います。

parseObject[PARSE_COLUMN_NAME_1] = StringInput.value;
parseObject.Add (PARSE_COLUMN_NAME_1, StringInput.value);

登録するデータはobject型なので、stringでもintでも問題ありません。
そして、ParseObject.SaveAsync()でデータの保存が行えます。


f:id:kan_kikuchi:20150104093348p:plain


実際に登録してみたデータをサイト上で見ると上記のようになります。


ParseQuery

データを取得する時はParseQueryでクエリを作成します。クエリとは「どういうデータが欲しいか」といった条件の事です。
ParseQueryもstringでクラス名を指定を指定して作成します。

ParseQuery<ParseObject> query = new ParseQuery<ParseObject> (PARSE_OBJECT_NAME);

上記の例が一番簡単なクエリで、登録されたSampleClassのデータを全て取得します。
そして、ParseQuery.FindAsync()でデータの取得が行えます。


ContinueWith

SaveAsync()やFindAsync()の後に.ContinueWithを付けると、その処理結果を取得する事ができます。

今回はCheckTask()で処理結果taskを見て処理が成功したかを見ています。
Unity上で何度実行しても失敗する場合、Unityを再起動すると改善する事があります。

また、FindAsyncでは取得したデータはtask.Resultに入っており、foreachを使う事で各データをParseObject型で取得できます。データの取得は、ParseObject[データ名]またはParseObject.Get<型名>(データ名)を使います。

//取得した値をログで表示する
IEnumerable<ParseObject> results = task.Result;

foreach(ParseObject parseObject in results){
  Debug.Log(parseObject[PARSE_COLUMN_NAME_1]);
  Debug.Log(parseObject[PARSE_COLUMN_NAME_2]);

  //Getを使うと型を指定して取得出来る
  Debug.Log(parseObject.Get<string> (PARSE_COLUMN_NAME_1));
}


f:id:kan_kikuchi:20150104093821p:plain


取得したデータをログで出力した結果が上記の通りです。
こんな簡単に出来てしまうとは…!


クエリの条件

上記では特に条件を付けずにクエリを投げていましたが、これだと大量のデータを取得してしまうので、普通は何かしらの条件を設定します。
上限の設定方法はParseQuery.○○()とするだけです。複数条件がある場合でもParseQuery.○○().△△()と繋げて行けばOK

なお、以下の説明にあるqueryは全て、

ParseQuery<ParseObject> query = new ParseQuery<ParseObject> (PARSE_OBJECT_NAME);

と初期化されたものとします。
また、ここに記載していないものもあるので詳しくはリファレンスを見てください。


データ数の上限

取得するデータ数に上限を設定します。

query = query.Limit (10);

上記の例だと最高でも10件しかデータを取得しません。


一致、不一致

あるデータを持っているかを指定して取得します。

//PARSE_COLUMN_NAME_1のデータが"value"のものだけ取得
query = query.WhereEqualTo      (PARSE_COLUMN_NAME_1, "value");

//PARSE_COLUMN_NAME_1のデータが"value"ではないものだけ取得
query = query.WhereNotEqualTo (PARSE_COLUMN_NAME_1, "value");

上記の例はだと、PARSE_COLUMN_NAME_1というkeyで登録されているデータが"value"か否かで取得するデータを判定しています。


一致、不一致(複数)

上記の一致、不一致の条件を複数設定して取得します。

//取得する条件
var names = new[] { "test", "Hello Word"};

//PARSE_COLUMN_NAME_1のデータがnamesで設定した値のものだけ取得
query = query.WhereContainedIn(PARSE_COLUMN_NAME_1, names);

//PARSE_COLUMN_NAME_1のデータがnamesで設定した値でないものだけ取得
query = query.WhereNotContainedIn(PARSE_COLUMN_NAME_1, names);

WhereContainsAllというのもあったのですが、全部の条件に合うってありえないような…リファレンスにも解説が無かったのでスルー


GetAsync

クエリの設定では無いのですが、「自分が保存した特定データが欲しい」みたいな時に、一意に決まるobjectidとWhereEqualToを使ってデータを持ってきたい所ですが、どうやら出来ないっぽいです…
そんな時はGetAsyncを使います。GetAsyncはobjectidを指定してデータを1件だけ取得します。

  //クエリ作成
  ParseQuery<ParseObject> query = new ParseQuery<ParseObject> (PARSE_OBJECT_NAME);

  //クエリを投げる OwgjCc7QIuがobjectid
  query.GetAsync("OwgjCc7QIu").ContinueWith(task =>
  {
    if(CheckTask("Load", task)){

      //取得した値をログで表示する
      ParseObject parseObject = task.Result;

      Debug.Log(parseObject[PARSE_COLUMN_NAME_1]);
      Debug.Log(parseObject[PARSE_COLUMN_NAME_2]);

    }
  });

もしかしたら正攻法じゃないかもしれませんが、とりあえずこれで出来るということで。


部分一致

特定の値の一部分だけ一致しているモノを取得します。

//PARSE_COLUMN_NAME_1のデータが"te"から始まっているものだけ取得
query = query.WhereStartsWith (PARSE_COLUMN_NAME_1, "te");

//PARSE_COLUMN_NAME_1のデータが"te"から終わっているものだけ取得
query = query.WhereEndsWith   (PARSE_COLUMN_NAME_1, "st");


"t"がどこかに含まれている。みたいな最初と最後以外に含まれてるモノは出来ないっぽいです。


設定されているか否か

特定のkeyで値が設定されているか否かを指定して取得します。

//PARSE_COLUMN_NAME_1のデータが設定されているもの全て取得
query = query.WhereExists(PARSE_COLUMN_NAME_1);

//PARSE_COLUMN_NAME_1のデータが設定されていないもの全て取得
query = query.WhereDoesNotExist(PARSE_COLUMN_NAME_1);

全てのkeyが設定されているとかで指定は出来ないのかしら…


閾値

指定した閾値に合うデータを持つものだけ取得します。

//PARSE_COLUMN_NAME_2のデータが10より上 
query = query.WhereGreaterThan(PARSE_COLUMN_NAME_2, 10);
//PARSE_COLUMN_NAME_2のデータが10より以上
query = query.WhereGreaterThanOrEqualTo(PARSE_COLUMN_NAME_2, 10);

//PARSE_COLUMN_NAME_2のデータが10より下
query = query.WhereLessThan(PARSE_COLUMN_NAME_2, 10);
//PARSE_COLUMN_NAME_2のデータが10より以下
query = query.WhereLessThanOrEqualTo(PARSE_COLUMN_NAME_2, 10);

OrEqualToを付けると指定したデータも範囲に含まれるようになるので、使い分けに注意が必要です。


スキップ

指定した件数分、最初のデータを無視します。

query = query.Skip(5);

イマイチ使い道が分からない…


並び替え

特定のkeyを基準に取得結果を並び変えます。

//昇順 小さい値が先
query = query.OrderBy (PARSE_COLUMN_NAME_1);
//降順 大きい値が先
query = query.OrderByDescending (PARSE_COLUMN_NAME_1);

//一つ目が同じ値だった時に二つ目の条件を昇順で設定する
query = query.OrderBy (PARSE_COLUMN_NAME_1).ThenBy(PARSE_COLUMN_NAME_2);
//一つ目が同じ値だった時に二つ目の条件を降順で設定する
query = query.OrderBy (PARSE_COLUMN_NAME_1).ThenByDescending(PARSE_COLUMN_NAME_2);

二つ目の条件は別のメソッドになっているの注意が必要です。


おわりに

データの設定がサイト上からも行えるので、簡易SSPみたいのも簡単に作れますねー。
こんなに便利で簡単なら早く使えば良かった…!データベースに限らず他にも機能がたくさんあるので機を見てどんどん使って行こうかと思います。