2013年7月21日日曜日

【cocos2d-x】CCSeqenseがリリースビルドで動かなかったお話。

cocos2d-x2.1.3でのお話です。
例えば0.5秒後にメソッドを呼びたいとき。
CCSequence *seq = CCSequence::create(CCDelayTime::create(0.5),
                                                                CCCallFunc::create(this, callfunc_selector(HogeScene::hoge)));
runAction(seq);
とか書いたりします。
これ、本来なら動きません。クラッシュします。
CCSeqenseには最後にNULLを入れなければいけないからです。
CCSequence *seq = CCSequence::create(CCDelayTime::create(0.5),
                                                                CCCallFunc::create(this, callfunc_selector(HogeScene::hoge)),
                                                                NULL);
runAction(seq);

正しくはこっちですね。
CCSequence *seq = CCSequence::createWithTwoActions(CCDelayTime::create(0.1),
                                                                                         CCCallFunc::create(this, callfunc_selector(MainScene::pressBtn)));
runAction(seq);
もしくはこう。
しかし、一番上のコード、動いちゃいます。
debugビルドのみ。
シミュレーターでも実機でもふつうに動きます。
ただ、リリースビルドでクラッシュします。かなりの罠です。
なので、CCSeqenseで2つのActionしか使わないときは
CCSequence::createWithTwoActions() を使いましょう。
もしくは単に遅延させてメソッド呼びたいならscheduleOnce使ってもいいです。というかそっちのがいいかも。

2013年6月19日水曜日

【cocos2d-x】アプリがバックグラウンドから復帰した時にSceneのメソッドを呼ぶ。

アプリがバックグラウンドから復帰した時などに現在のシーンにアクセスする方法です。 時間をとって画面を変化させたいときなどに使えます。
viewDidAppearとかviewWillAppearみたいなのが無さそうなので。(あったら教えて下さい)
HelloWorldSceneのhogeメソッドを読んでいます。

AppDelegate.cpp
void AppDelegate::applicationWillEnterForeground()
{
    CCDirector::sharedDirector()->startAnimation();
    SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
    SimpleAudioEngine::sharedEngine()->resumeAllEffects();

     // getRunningSceneでCCSceneをとってその上のレイヤーにアクセスする。
    CCLayer *sceneLayer = (CCLayer*)CCDirector::sharedDirector()->getRunningScene()->getChildren()->lastObject();
    if (typeid(*sceneLayer) == typeid(HelloWorld)) {
        HelloWorld *helloWold = (HelloWorld*)sceneLayer;
        helloWold->hoge();
    }
} 
getRunningSceneでそのままアクセスできると思ってしばらくハマってました。
sceneメソッド見て納得。

2013年6月5日水曜日

【cocos2d-x】前回の時間から"日付上"1日以上経過してるかチェックする。

0時更新のログインボーナスなどで使う感じ。 なんか便利な関数とかあるかも。

bool HogeScene::init() {
    if (!CCLayer::init()) {
        return false;
    }
    // 前回の時間をとる
    time_t previousTime = (time_t)CCUserDefault::sharedUserDefault()->getIntegerForKey("previousTime", 0);
    
    if (isOneDayCourse(previousTime)) {
        // 一日経過してたなら現在時刻をセット(初回時も)
        CCUserDefault::sharedUserDefault()->setIntegerForKey("previousTime", (int)time(NULL));
    }
    
    return true;
}
bool HogeScene::isOneDayCourse(time_t time)
{
    // 現在の日付
    struct tm *nowDate;
    time_t now;
    time(&now);
    nowDate = localtime(&now);
    int nowDay = nowDate->tm_mday;
    int nowMon = nowDate->tm_mon;
    int nowYear = nowDate->tm_year;
    // 前回の日付
    struct tm *previousDate;
    time_t previousTime = time;
    previousDate = localtime(&previousTime);
    int previousDay = previousDate->tm_mday;
    int previousMon = previousDate->tm_mon;
    int previousYear = previousDate->tm_year;
    // 差分
    int diffDay = nowDay - previousDay;
    int diffMon = nowMon - previousMon;
    int diffYear = nowYear - previousYear;
    
    // 日付上一日以上経過でtrue
    if (diffDay || diffMon || diffYear) {
        return true;
    }
    return false;
}

2013年1月13日日曜日

【cocos2d-x】CCARRAY_FOREACHの使い方(一例)

addChildされてるCCNode等を継承したHogeクラスだけを操作したい時のコードです。

CCArray *children = this->getChildren();
CCObject *obj;
    
CCARRAY_FOREACH(children, obj){
    if (typeid(*obj) == typeid(Hoge)) {
        // Hogeクラスを操作
    }
}

2013年1月9日水曜日

【cocos2d-x】androidでのハードキー対応

androidでのハードキー対応の方法です。
Sceneでキーパッドを有効にしてメソッドをオーバーライドするだけです(余計なとこは省いてます)。

HogeScene.h
class HogeScene : public cocos2d::CCLayer {
public:
    void keyBackClicked();
    void keyMenuClicked();
};
HogeScene.m
bool HogeScene::init() {
    if (!CCLayer::init()) {
        return false;
    }
    // キーパッドを有効に
    setKeypadEnabled(true);

    return true;
}
 
void HogeScene::keyBackClicked() {
    // ハードキー
}
 
void HogeScene::keyMenuClicked() {
    // メニューキー
}

【C++】クラス名を取得する

C++でクラス名を取得する方法です。
#include <typeinfo>
#include <cxxabi.h>

void HogeScene::hoge()
{
int status;
const char* className = abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status);
}
なんかよくわかりませんが__cxa_demangleでデマングルってのをしてるみたいです。