まあ、上の画像はとりあえず作って貼っとけ的な心の内を見透かされそうな匂いがぷんぷんしちゃってますが。
本日二度目の投稿です。今いろいろとリファレンスを見ていじってるという状況なんで、やり方見つけたら忘れないうちに書きたくなっちゃうんで。。
cocos2d-xでのデータの保存方法って載ってるところがほとんどなくて、大抵が「プリファレンスやSQLiteを使えばいいよ」的な感じになってて、そこが気になって他の方法を調べてました。SQLiteは設定が面倒だし、わざわざデータベースを扱うほどのデータ量も(ぼくが作るゲームは)ないんで。というよりも、会社でMysqlを使いまくってるんで、家ではなるべく使いたくないというのが本音だけど(´・ω・`)SQL文なんて見たくもない。。
まあ、プリファレンスを使えばぼくが作ってるようなのなら全然事足りるんですが、CCDicrionaryでも結構簡単に保存と読み込みができたので、それをまとめておきます。
※記事の訂正(2014/06/30)
記事「ファイルの書き込み」中で、CCDictionaryと書くところを一部CCDirectoryと書いていました。
CCDirectoryというクラスはcocos2d-x内には存在しません。まぎらわしくしてしまってごめんなさい(´・ω・`)
※現在記事は訂正しています。
まずはプリファレンスデータから
あちこちに載ってるんですが、一応。
cocos2d-xはCCUserDefaultを使って非常に簡単にクロスプラットフォームでプリファレンスデータを扱うことができます。
読み込み方法
非常に簡単です。
//std::string読み込み std::string str = CCUserDefault::sharedUserDefault()->getStringForKey("strKey","defaultValue"); //数値の読み込み int i = CCUserDefault::sharedUserDefault()->getIntegerForKey("intKey",0); //float値の読み込み float f = CCUserDefault::sharedUserDefault()->getFloatForKey("floatKey",0.0f); //double値の読み込み double d = CCUserDefault::sharedUserDefault()->getDoubleForKey("doubleKey",0.0f); //booleanの読み込み bool b = CCUserDefault::sharedUserDefault()->getBoolForKey("boolKey",false);
どれも第一引数がキーで、第二引数が指定したデフォルト値となります。
書き込み方法
ほとんど変わりません。最後にflush()を行うくらいです。
CCUserDefault* user = CCUserDefault::sharedUserDefault(); user->setStringForKey("strKey","string1"); user->setIntegerForKey("intKey",1); user->setFloatForKey("floatKey",1.0f); user->setDoubleForKey("doubleKey",1.0f); user->setBoolForKey("boolKey",1.0f); //最後に保存を反映させる user->flush();
これも第一引数がキーとなり、第二引数が値となります。
CCDictionaryで保存と読み込み
ここからが今回の本題です。いつのバージョンからかはわかりませんけど、今年の4月くらいにCCDictionaryの中にwriteToFileというメソッドが追加され、結構簡単に保存ができるようになったぽいです。
結構制約はあるんですけど、プリファレンスより多少(FOREACHできたりCCArrayも保存できる分)データとして扱いやすいかもしれません。プリファレンスはやっぱり設定だけに留めておきたいですし。
CCDictionaryで保存するにあたっての制約
その1.適切な場所に保存する
セーブデータなどを扱う場合、iPhoneなんかは適切な場所におかないとリジェクトの対象になったりするそうです。
ただ、保存場所のパスは以下のような感じで簡単に取得することができます。
CCFileUtils::sharedFileUtils()->getWritablePath();
一応、iPhoneの場合「Documents」というディレクトリに入ってたら大丈夫みたいです。Androidの場合よくわからないけど、以下のようになってたら大丈夫みたい。
/* (cocos2d-x2.0以降の話で) /cocos2dx/platform/android/java/src/org/cocos2dx/lib/Cocos2dxHelper.java 以下の部分を確認 */ public static void init(final Context pContext , final Cocos2dxHelperListener pCocos2dxHelperListener){ ... Cocos2dxHelper.sFileDirectory = pContext.getFilesDir().getAbsolutePath(); ... } ... public static String getCocos2dxWritablePath(){ return Cocos2dxHelper.sFileDirectory; }
デフォルトではちゃんとなってるっぽいです。
その2.CCArrayまたはCCDictionary、CCString以外は保存できない
この3つ以外ははじかれます。CCIntegerやCCFloatなども使えるといいのですが、CCString以外はないものにされちゃいます。多分スーパークラスにCCStringを実装しつつ、getCString()をオーバーライドしたら使えるようにできるかもしれません。
その3.String型でしかキーは保存できない(追記:9月9日)。
CCDictionaryといえば整数型でもキーを設定できるけど、保存する場合は全部文字列型に統一しておかないとできないみたい。
制約はありますが、CCArrayとCCDictionaryが使えるというのがかなり強いですね。プリファレンス涙目です。
ファイルの書き込み
結構びっくりするくらい簡単です。
手順としては、
- CCDictionaryを作成
- 中にいろいろ入れる(CCString、CCArray、CCDictionaryのみ)
- writeToFileメソッドを呼び出す
ちなみにplist形式で書き出されるらしいのですが、拡張子は何でもOKみたいです。
CCDictionary* savedir = CCDictionary::create(); //保存する配列を作成 //ccs = CCString::createと同じです。CCString.h内で定義されています。 CCArray* ary = CCArray::create(ccs("arytest1"),ccs("arytest2"),NULL); savedir->setObject(ary , "testArray"); //保存する辞書を作成 CCDictionary* dic = CCDictionary::create(); dic->setObject(ccs("1"),"dic1"); dic->setObject(ccs("2"),"dic2"); savedir->setObject(dic , "testDic"); //保存するCCStringを作成 CCString* str = CCString::create("true"); savedir->setObject(str , "testBool"); //保存箇所のフルパスを取得 std::string savepath = CCFileUtils::sharedFileUtils()->getWritablePath() + "savadata.svd"; //保存 if(savedir->writeToFile(savepath)){ CCLOG("save Success:%s" , savepath); }else{ CCLOG("save Failed:%s" , savepath); }
実行すると、iOS、androidそれぞれで以下のように出ました。
[iOS]
save Success:/Users/(省略)/Documents/savadata.svd
[Android]
save Success:/data/data/(省略)/files/savadata.svd
拡張子に特に意味はありません。
ファイルの読み込み
これもとっても簡単です。フルパスでcreateWithContentsOfFileを呼び出せば、あとは普段のCCDictionaryと同じように扱えます。
std::string savepath = CCFileUtils::sharedFileUtils()->getWritablePath() + "savadata.svd"; //存在するかどうか確認 CCDictionary* dic = NULL; if(CCFileUtils::sharedFileUtils()->isFileExist(savepath)){ dic = CCDictionary::createWithContentsOfFile(savepath.c_str()); }else{ dic = CCDictionary::create(); }
以上になります。
ただデータの格納が基本CCStringだけとなってしまう為、何かしら管理するクラスを作ったら更に使いやすくなるかもですね。
CCDirectory*というクラスが見つかりません。
どのバージョンにありますか?
宜しくお願い致します。
ご指摘ありがとうございます。
CCDirectory*はぼくの脳内にしか存在しないポインタ及びクラスでしたので
全てCCDictionaryに訂正しました。。
紛らわしくてすみません(>_<)
www