読者です 読者をやめる 読者になる 読者になる

夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

【cocos2d】パーティクルを表示中にパーティクルバッチノードからRemoveするとクラッシュ!どうするか?

cocos2d BeeCluster

cocos2dのCCParticleBatchNodeって、パーティクル表示中にremoveAllChildrenで子ノードを削除するとクラッシュしませんか?

いろいろ調べたのですが、結局クラッシュの原因は分かりませんでした。
もしかするとcocos2dのバグかもしれません。同じ現象が報告されています。

私のゲーム、BeeClusterでは、ドンパチ打ち合って爆発のパーティクルが表示されているときを見計らってポーズボタンを押し、「タイトル画面に戻る」ボタンを押すと確実にクラッシュしてしまいます。
クラッシュを恐れremoveAllChildrenをしない場合はreplaceSceneのあとで前の画面のパーティクルが消えずに残ってしまいます。
これはマズいので、なんとか解決策を考えました。

replaceSceneの時点で全てのパーティクルが画面から消えていればそもそもremoveAllChildrenする必要はないので、ポーズ中に「タイトル画面に戻る」ボタンを押された時点でフラグを立て、そのフラグが立っているときはそれ以上パーティクルの生成をしないようにしました。
replaceSceneのトランジションにある程度の時間を設定しておけば画面からパーティクルは消え、replaceScene後に画面に残骸が残ることはなくなりました。

これは、パーティクル生成クラスの初期化部分なのですが、ポーズ画面を管理するInfoLayerシングルトンインスタンスのterminatedというフラグを見て生成するかnilを返すか判断するコードを追加しました。

- (id)init
{
    if ([InfoLayer sharedInfo].terminated == NO) {
        return [self initWithTotalParticles:340];
    } else {
        return nil;
    }
}

+ (id)explosion
{
    return [[self alloc] init];
}

このexplosionコンビニエンスコンストラクターを使う方のクラスもnilが帰って来る可能性を考慮しnilかどうかの判定を入れます。

Explosion* particle = [Explosion explosion];
if (particle != nil) {
    particle.position = [self.parent convertToWorldSpace:self.position]; //ワールド座標
    particle.autoRemoveOnFinish = YES;
    [[ParticleBatch sharedParticleBatch] addChild:particle];
}

このゲームではパーティクルは爆発にしか使っていないので上の方法だけで解決しましたが、煙などパーティクルを出しっぱなしにしている場合はそれを止める処理が必要になりますね。