はじめに
これは Cocos2d-x Advent Calendar 2014 の第21日目の記事です。
予定で「横スクロールゲームについて書きます」と言ったな。 アレは嘘だ 。
すみません、他に書きたいネタが浮かんだのでそちらについて書きます。
Cocos2d-x で Resources のサブディレクトリ内のファイル一覧を取得する方法についてです。
バージョンは 3.2 を対象としています。
Cross Platform にできるか? → できない!
これはかなり必要な機会も多いはずなので、FileUtils あたりに API が準備されているだろうと思ったのですが、どうやらそうではないようです。
Stack Over Flow に、
There is no cross platform API in cocos2dx for listing directory contents. You can store file names in an array while creating them.
と答えている方がいらっしゃいます。
今回は iOS と Android についてやりたかったので、それぞれ別々の方法が必要になりますね...
なんとか両方のプラットフォームで実現できたので、以下に書いていこうと思います。
対象のディレクトリは Cocos2d-x の Resources に含まれていることを前提とします。
iOS ではどうやるの?
iOS のほうが素直に実装できます。
フルパスを取得したら、C言語標準の opendir
関数でディレクトリを開きます。戻り値として受け取ることができる、DIR
構造体から readdir()
してディレクトリーの中身を表す構造体 dirent
で受け取れば、中身のファイル名が調べられます。
サンプルコードは次のとおりです:
std::vector<std::string> getDirContents(std::string dirname) {
FileUtils* fu = FileUtils::getInstance();
std::string dir = fu->fullPathForFilename(dirname);
std::vector<std::string> list;
DIR* dp;
struct dirent* ent;
if ((dp = opendir(dir.c_str()), "r") == NULL) {
CCLOGERROR("ディレクトリが開けません。:%s", dir.c_str());
perror(dir.c_str());
return list;
}
while ((ent = readdir(dp)) != NULL) {
CCLOG("ファイル:%s", ent->d_name);
list.push_back(ent->d_name);
};
closedir(dp);
return list;
}
Android ではどうやるの?
Android では fullPathForFilename()
メソッドでフルパスがうまく取れませんでした。
そうすると、opendir()
関数も使えません。Android/C++ では Resources 配下は JNI のAssetsManager というもので扱うようです。
AssetsManager のインスタンスの取得にはアプリケーションの Context が必要になるようで、少々厄介です。今回は Cocos2d-x の FileUtils が private 変数として持っているインスタンスを借りてきました。(とりあえず public に書き換えました。)
サンプルコードはつぎのとおりです:
std::vector<std::string> getDirContents(std::string dirname) {
std::vector<std::string> list;
AAssetManager* mgr = FileUtilsAndroid::assetmanager;
AAssetDir* assetDir = AAssetManager_openDir(mgr, dirname.c_str());
if (!assetDir) {
CCLOGERROR("ディレクトリが開けません:%s", dirname.c_str());
return list;
}
const char* filename = NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
CCLOG("ファイル:%s", filename);
list.push_back(filename);
}
AAssetDir_close(assetDir);
return list;
}
おわりに
Cocos2d-x で Resources ディレクトリ内のファイル一覧を取得するお話を iOS, Android について書きました。自分としては必要になる機会も多いと思うので、FileUtils
あたりに実装されたらいいなーと思った次第。
お読みいただきありがとうございました。