マリオの完コピvol.23 処理負荷軽減

こちらのvol.19で言っていた負荷について
http://blog.game-kids.net/haruzakki/entry-747.html
オリジナルと同じようにマップを作って実行すると、やたら重くなった。

60だったFPSが30付近に。
なんじゃこりゃー。
ファミコンレベルなのに重くなるのか。
作り方がまずいのか?画像が多すぎる?
そして重くなってる箇所をつきとめる作業に。
これは各処理の部分をコメントアウトして確認する感じで。
すると各スプライトのupdateをするところで重くなっていた。
■該当のコード
auto children = mBgLayer->getChildren();
reverse(children.begin(), children.end());
for (auto obj : children) {
child->update();
}
スプライトといってもクリボーとノコノコしか処理をしているものはない。当たり判定が重いのか?
と思って当たり判定部分を切ったら少し軽くなった。
で、検証したところ
auto children = mBgLayer->getChildren();
reverse(children.begin(), children.end());
こうやって配列を逆順にするところが重かった。
正確に言うと
auto children = mBgLayer->getChildren();
この時点で配列のコピーが生成されているので、元の配列がでかいほど重くなる。
auto &children = mBgLayer->getChildren();
のように&を付けると参照になるので一瞬で処理が通るが、配列を逆順には出来ない。
配列を逆順にする理由は、ループ内で削除をしたいから。
詳しくは
http://qiita.com/AknEp/items/e54e18766ea00c86fca8
で、逆順にせず参照を使い、ループ外で削除するようにコードを変更したら軽くなった。
が、それでもクリボーを大量設置すると重い。
これは仕方ないのか?いや、30年前のファミコンレベルで重いとかありえない。
スーファミのファーストクイーンでも大量のスプライトが動いていたはずだ。
で、よくデバッグをしてみると、
auto &children = mBgLayer->getChildren();
このchildrenの数が全ての設置しているスプライトの数なので、やたら多い。レンガと地面、さらには雲や草原も含めているので500は軽く超える。
そのうち使用するのはクリボーとノコノコ程度なのでほとんどが空処理となる。
当たり判定でもほとんどが空処理になっている。
これが諸悪の根源だったようだ。
毎フレーム500×10(敵キャラ)くらいの空処理があるということ。
それで以下のようにupdateするスプライトだけをリストに入れて実行するようにした。
■リスト版
for (auto itr = mSprList.begin(); itr != mSprList.end(); itr++) {
MySprite* child = dynamic_cast<MySprite*>(*itr);
child->update();
}
こうすると劇的に軽くなった。
試しにクリボー大量設置してもこのように大丈夫。

リストに入れずにスプライトだけを扱ったレイヤーを別に作って、getChildrenで取得する事も検討したが、それだと背景の後ろにスプライトを表示する事が出来なくなるので、やめた。
今だとキノコがブロックの後ろから登場するとこだったり、後にマリオが土管に潜るところで背景の後ろに表示する必要が出てくる。
http://blog.game-kids.net/haruzakki/entry-747.html
オリジナルと同じようにマップを作って実行すると、やたら重くなった。

60だったFPSが30付近に。
なんじゃこりゃー。
ファミコンレベルなのに重くなるのか。
作り方がまずいのか?画像が多すぎる?
そして重くなってる箇所をつきとめる作業に。
これは各処理の部分をコメントアウトして確認する感じで。
すると各スプライトのupdateをするところで重くなっていた。
■該当のコード
auto children = mBgLayer->getChildren();
reverse(children.begin(), children.end());
for (auto obj : children) {
child->update();
}
スプライトといってもクリボーとノコノコしか処理をしているものはない。当たり判定が重いのか?
と思って当たり判定部分を切ったら少し軽くなった。
で、検証したところ
auto children = mBgLayer->getChildren();
reverse(children.begin(), children.end());
こうやって配列を逆順にするところが重かった。
正確に言うと
auto children = mBgLayer->getChildren();
この時点で配列のコピーが生成されているので、元の配列がでかいほど重くなる。
auto &children = mBgLayer->getChildren();
のように&を付けると参照になるので一瞬で処理が通るが、配列を逆順には出来ない。
配列を逆順にする理由は、ループ内で削除をしたいから。
詳しくは
http://qiita.com/AknEp/items/e54e18766ea00c86fca8
で、逆順にせず参照を使い、ループ外で削除するようにコードを変更したら軽くなった。
が、それでもクリボーを大量設置すると重い。
これは仕方ないのか?いや、30年前のファミコンレベルで重いとかありえない。
スーファミのファーストクイーンでも大量のスプライトが動いていたはずだ。
で、よくデバッグをしてみると、
auto &children = mBgLayer->getChildren();
このchildrenの数が全ての設置しているスプライトの数なので、やたら多い。レンガと地面、さらには雲や草原も含めているので500は軽く超える。
そのうち使用するのはクリボーとノコノコ程度なのでほとんどが空処理となる。
当たり判定でもほとんどが空処理になっている。
これが諸悪の根源だったようだ。
毎フレーム500×10(敵キャラ)くらいの空処理があるということ。
それで以下のようにupdateするスプライトだけをリストに入れて実行するようにした。
■リスト版
for (auto itr = mSprList.begin(); itr != mSprList.end(); itr++) {
MySprite* child = dynamic_cast<MySprite*>(*itr);
child->update();
}
こうすると劇的に軽くなった。
試しにクリボー大量設置してもこのように大丈夫。

リストに入れずにスプライトだけを扱ったレイヤーを別に作って、getChildrenで取得する事も検討したが、それだと背景の後ろにスプライトを表示する事が出来なくなるので、やめた。
今だとキノコがブロックの後ろから登場するとこだったり、後にマリオが土管に潜るところで背景の後ろに表示する必要が出てくる。