ラベル アプリ の投稿を表示しています。 すべての投稿を表示
ラベル アプリ の投稿を表示しています。 すべての投稿を表示

2015年3月6日金曜日

cocos2d-xのメモリ対策について

どうも、俺@仕事中です。

昨年、cocos2d-x CCSprite(テクスチャ)の軽量化という記事を書きましたが、
今回も同じようにメモリ対策についてメモ。

■環境
・cocos2d-x 2.2.6
・Xcode 6.1.1

先に結論から言いますと、
CCSpriteFrameCacheやCCTextureCacheの使いすぎに注意、
または、メモリ不足に陥る前に正しくキャッシュデータを解放しましょう。
ということです。

CCSpriteFrameCacheCCTextureCacheは、
スプライトシートなどの画像データをメモリ上にキャッシュしてくれるため、
CCSpriteオブジェクトの生成時に高速&低負荷であることがメリットな反面、
メモリを消費します。(※1)

特にCCSpriteFrameCacheは大きなサイズは画像ファイル(スプライトシート)を
キャッシュすることがあるのでそのメモリ消費には要注意です。


例えば、
タイトル画面(TitleScene) → 遷移 → ゲーム画面(GameScene)
のような場合。

タイトル画面で表示するためのスプライトシートを読み込み、
またゲーム画面でもゲーム画面用のスプライトシートを読み込み、
といった処理を行うと、
両方の画面で読み込まれたスプライトシートはキャッシュされたままになります。




メモリが不足してくると、iOSでは
    AppController#applicationDidReceiveMemoryWarning:(UIApplication *)application; 
がコールされ、
cocos2d-xのバージョンによっては、
    CCDirector#purgeCachedData(void)
が呼ばれて、開発者が意図せず勝手にキャッシュデータが消去されます。

この状態だと、次にCCSpritFrameCacheからキャッシュデータを読み込もうとすると
エラーとなりアプリがクラッシュしてしまいます。


対応として、
1)CCDirector#purgeCachedData(void)を呼ばない。
2)不要になったタイミングでCCSpriteFrameCacheのキャッシュデータをクリアする。
が考えられます。

1)の方法は簡単&すぐに対応できますが、メモリ逼迫の原因は解消されません。
2)は、画面遷移の前などで
    CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile(const char *plist);
を呼べばOKです。

画面遷移の前というのは、
CCDirector#replaceScene(CCScene *pScene)
を呼ぶより前のタイミングです。
その該当するSceneのonExit()やデストラクタ内で、
    CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile(const char *plist);
を呼ぶと、
すでに遷移先のSceneオブジェクトが生成されてしまっているので、
タイミングとしてはちょっと遅いです。

※1) CCSpriteクラスのcreate(const char *fileName)メソッドや
initWithFile(const char *fileName)メソッドは、
内部でCCTextureCacheクラスのaddImage(const char *fileName)が呼ばれているため、
キャッシュされ、二回目以降の呼び出しは高速になる。


以上でぇぇぇぇぇす。

2014年10月3日金曜日

Androidアプリ Lintエラーの対応

どうも、俺です。
しばらくなかったブログ更新を埋めるかのように連日投稿しています。

今日はAndroidアプリをeclipseでビルドするときに出るLinのエラー対応についてです。

■エラーその1
"xxxxx" is not translated "......"

→解決方法
 無視しましょう。

プロジェクト名>Properties>Android Lint Preferences
を選択、
MissingTranslationを選択してそのSeverityを"Warning"にしましょう。



これは、外部のライブラリ等を組み込んだ時に、
そのライブラリで設定されているローカライズ情報が、
開発中アプリまたはその他ライブラリに影響するために出るエラー、だそうです。。
要約すると、「言語リソースが足りねぇよ」というエラーです。


■エラーその2
"xxxx" is translated here but not found in default locale

→解決方法
google-play-servicesプロジェクト内にある
res>values-en-rIN>auth_strings.xmlをコピーして、
同じくgoogle-play-servicesプロジェクトの
res>valuesフォルダにペースト。



google-play-servicesを導入してから出るようになったエラーなので、
おそらくそれが原因っぽい。。



以上でぇぇぇぇぇぇす。

2013年9月20日金曜日

cocos2d-xでスクロールするレイヤーCCScrollLayerを使う

どうも、俺@久しぶりの書き込みです。

最近もほぼ毎日iOS/Androidのゲームアプリ開発に精を出しています。

今日はcocos2d-xを使ってスクロール出来るレイヤーの紹介です。
画面をスワイプしてページングする、アレです。
先日リリースしたゲームアプリ「ゴー!ゴー!カート」のコース選択画面で使っています。


GitHubに上がっているyandongliu / CCScrollLayerを使わせて頂きましたが、やりたい事がほぼこれで全て実装できました。
※cocos2d-x v2.0.2での動作保証がされています。それ以上のバージョンのcocos2d-xを使う場合はしっかり動作検証が必要です。

基本的な使い方は、スクロールして表示するコンテンツ(Layer)を配列にaddObject()しておいて、その配列をCCScrollLayerにセットする、という流れです。


ではまずGitHubからCCScrollLayerをcloneします。

git clone https://github.com/yadongliu/CCScrollLayer.git
で、中のCCScrollLayer.hとCCScrollLayer.mをXCodeのプロジェクト内に放り込みます。
これで準備OKです。

それでは表示する各コンテンツ(Layer)を作成しておきます。

// ヘッダ ContentsLayer.h
class ContentsLayer: public cocos2d::CCLayer
{
public:
  ContentsLayer();
  virtual bool init();
};

// 実装 ContentsLayer.m
#include "ContentsLayer.h"

ContentsLayer::ContentsLayer()
{
}
bool ContentsLayer::init()
{
  if (!CCLayer::init()) {
    return false;
  }

  // 適当なSpriteでも載せておく
  CCSprite *sprite = CCSprite::create("hoge.png");
  sprite->setPosition(ccp(200,200));
  this->addChild(sprite);

  return true;
}

次にスクロールさせたいSceneのヘッダファイルでこのファイルを読み込み宣言しておきます。

#include "CCScrolLayer.h"
#include "ContentsLayer.h"
class MyScene: public: cocos2d::CCLayer
{
public:
  MyScene();
  static cocos2d::CCScene *scene();
  // その他の宣言
private:
  // CCScrollLayerをクラス変数としておく(あとあと操作しやすいので、、各自お好みで、、)
  cocos2d::CCScrollLayer *_myScrollLayer;
};

次に実装ファイルに処理を書いていきます。


// コンストラクタやinit()で
bool MyScene::init()
{
  if (!CCLayer::init()) {
    return false;
  }

  // とりあえず4画面スクロールさせる
  CCArray *contentsList = CCArray::create();
  ContentsLayer *contents1 = new ContentsLayer();
  ContentsLayer *contents2 = new ContentsLayer();
  ContentsLayer *contents3 = new ContentsLayer();
  ContentsLayer *contents4 = new ContentsLayer();

  contents1->init();
  contents2->init();
  contents3->init();
  contents4->init();

  contentsList->addObject(contents1);
  contentsList->addObject(contents2);
  contentsList->addObject(contents3);
  contentsList->addObject(contents4);

  // CCScrollLayerへセット
  _myScrollLayer = new CCScrollLayer();

  // 4画面分の配列をセット。
  _myScrollLayer->initWithLayers(contentsList, 0);

  // ページインジケーターのポジション(任意)
  _myScrollLayer->setPageIndicatorPosition(ccp(100, 20));

  // 最初に表示しておくページ番号
  _myScrollLayer->selectPage(0);

  this->addChild(_myScrollLayer);

  // レイヤーは解放しておく
  contents1->release();
  contents2->release();
  contents3->release();
  contents4->release();

  return true;
}

とりあえずこれだけで動きます。 4画面分スクロールできるはずです。 他にも使えそうなメソッドがいくつか用意されていて、
CCArray *getPages() // 表示できる画面を配列で返す
unsigned int getCurrentScreen() // 現在のページ番号を返す

や、CCScrollLayerDelegateという便利なデリゲートもあります。

詳しくはソースを読んでみてください。
すごく短くて読みやすいです。


以上でぇぇぇぇぇす。