head_hexagonはにらぼ☆てっくtale_hexagon
Archive » 5月 2016
ブログ画像

【Cocos2d-xアプリをUWPへ移植③】Windowsで実行時に落ちる問題を調べる

こんにちは、kiyokazkです。 前回の最後に発生した、実行は無事にできたけど、アイテムを取った瞬間に落ちる問題について、何が起こっているのかを調べました。 ポインタ変数の未初期化 これはcocos2dとか関係なく、初歩的なミス(?)で、ポインタ変数が未初期化なものがありました。
ミス(?)としたのは、元のプロジェクトがiOS用で、Objective-Cでは言語仕様として”未初期化変数はnilもしくは0になる”というのがあるため、それで問題がなかったからなんですが、クロスプラットフォームにする前提なのであればここはちゃんと(お作法的にも)NULLで初期化しているべきでした。
VisualStudioのデバッグビルドでは未初期化のメモリは0xcdcdcdcdになってるので比較的気づきやすいバグですね。久しぶりに0xcdcdcdcdを見ました。
これについては、ちゃんとポインタ変数をNULLで初期化することでOK。 Vectorの要素削除の挙動の違い これは若干の落とし穴でした。
Vector配列の要素をループ内で削除するときには要素数が変わるのでループを逆向きに回すのが定石ですが、Cocos2d-xのVectorの実装で、iOSとWindowsで若干の挙動の違いがあるようで、それに伴って問題が出ていました。 元々のコード: for(auto itr = m_enemies.rbegin(); itr != m_enemies.rend(); itr++) { EnemyObject *enemy = *itr; //死んでる? if(enemy->isDie()) { //配列から削除 m_enemies.eraseObject(enemy); } } 普通にm_enemiesをrbegin()で逆向きに回して、該当する要素を削除していました。 Windows実装だとeraseObject()後のVectorのループの挙動が少し変わっているようで(削除後にitrが指すものを続けてループで回せない)、以下のように書き換えました。 for (auto itr = m_enemies.rbegin(); itr != m_enemies.rend(); ) { EnemyObject *enemy = *itr; //死んでる? if (enemy->isDie()) { //配列から削除 m_enemies.eraseObject(enemy); itr = m_enemies.rbegin(); } else itr++; } 通常時は普通にitrのインクリメント、eraseObject()を行なった後はrbegin()を呼び直す、みたいな感じです。
これでループでの要素削除が意図通りに動作するようになりました。 これで一通りWindows環境に移植するという面ではひとまずできたので、次回からはいよいよWindowsストアアプリ、ユニバーサルアプリとしての対応について進めます。

Posted by kiyokazk on 2016/05/16 under Development