
【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ストアアプリ、ユニバーサルアプリとしての対応について進めます。