cocos2d-x-3.3-rc0から、AssetsMangerExというファイルのバージョンをチェックして、アップデートされていたらファイルをダウンロードしてくるという機能のクラスが追加された。
そのクラスで利用されている、3.3rc0のリリース記事にすら通知されず、こっそり追加されていたDownloaderクラス。
これが想像以上に便利で、かつ簡単にファイルの非同期ダウンロードが実装できたのでメモ。
タイムアウトやエラー、終了のコールバックだけでなく、進行度のコールバックも受け取れるので、ダウンロード容量が多いときに進行度をグラフで見せたい時などにも簡単に対応できる。
試しにyahooのトップのロゴを表示してみたが、画像に限らずどんな形式でも可能な上、バイナリデータでのダウンロードも可能なのでいろいろと応用が利くと思われる。
以下、テストで実装してみたコード
.h
#include "cocos2d.h" #include "Macros.h" #include "cocos-ext.h" class DownloadScene : public cocos2d::Layer { public: CREATE_FUNC(DownloadScene); static cocos2d::Scene* createScene(); virtual bool init(); private: std::shared_ptr<cocos2d::extension::Downloader> _downloader; void onError(const cocos2d::extension::Downloader::Error &error); void onProgress(double total, double downloaded, const std::string &url, const std::string &customId); void onSuccess(const std::string &srcUrl, const std::string &storagePath, const std::string &customId); };
cpp
#include "DownloadScene.h" USING_NS_CC; Scene* DownloadScene::createScene() { auto scene = Scene::create(); auto layer = DownloadScene::create(); scene->addChild(layer); return scene; } bool DownloadScene::init() { if (!Layer::init()) { return false; } _downloader = std::make_shared<extension::Downloader>(); _downloader->setErrorCallback(CC_CALLBACK_1(DownloadScene::onError, this)); _downloader->setProgressCallback(std::bind(&DownloadScene::onProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); _downloader->setSuccessCallback(CC_CALLBACK_3(DownloadScene::onSuccess, this)); _downloader->setConnectionTimeout(DOWNLOAD_TIMEOUT); _downloader->downloadAsync("http://k.yimg.jp/images/top/sp2/cmn/logo-ns-131205.png", FileUtils::getInstance()->getWritablePath() + "yahoo.png"); return true; } void DownloadScene::onError(const cocos2d::extension::Downloader::Error &error) { //Downloader専用のErrorCode CCLOG("%d", error.code); //CURLcodeの値 CCLOG("%d", error.curle_code); //CURLMの値 CCLOG("%d", error.curlm_code); //エラーメッセージ CCLOG("%s", error.message.c_str()); } void DownloadScene::onProgress(double total, double downloaded, const std::string &url, const std::string &customId) { //総ファイルサイズ CCLOG("total %lf", total); //ダウンロード済みサイズ CCLOG("downloaded %lf", downloaded); } void DownloadScene::onSuccess(const std::string &srcUrl, const std::string &storagePath, const std::string &customId) { CCLOG("Success"); auto yahoo = Sprite::create(FileUtils::getInstance()->getWritablePath() + "yahoo.png"); yahoo->setPosition(Director::getInstance()->getVisibleSize() / 2); addChild(yahoo); }
これで、非同期でのダウンロードを実装できる
一つ問題があるとすれば、そのままのエラーコードがとれないので、細かいエラー処理が難しいところかと
バイナリデータのポインタがほしい場合はdownloadToBufferAsyncを呼べば良い