C#::foreachしながらRemove
弾のオブジェクトが大量にあって、移動した結果画面から消えてなくなるという処理を考える。
段幕処理に限らず、リストのすべてを処理してその結果によってリストからなくなるというのはよくある話で。
素直に
//List<Bullet> bullets; foreach(Bullet b in this.bullets) { b.Act(); if(!b.Alive) this.bullets.Remove(b); }
と書いてみたいところですが、foreachの中でリストのメンバを入れたり出したりするのは御法度です。
ここはちょこっと頭をひねって
this.bullets.RemoveAll(delegate(Bullet b) { b.Act(); return !b.Alive; });
と書けばいいわけです。
RemoveAllはオブジェクトを渡すとboolを返すデリゲートを要求して、その戻り値がTrueとなる要素をリストから削除してくれますので、期待通りの動作をすることになります。
さらに、Act()の戻り値を変えても良いならそれをbool型にしてAct後のAliveを返すようにすると
this.bullets.RemoveAll(delegate(Bullet b){ return !b.Act(); });
あらすっきり。
これに仮にBulletクラスのstaticメンバとしてbulletsを登録してあったりして、Bulletのコンストラクタでそのリストに自動的に突っ込まれるように書いてやると、(Actで移動とあたり判定すませれば)メインループにはこれだけ書けば段幕処理って完了ですよね。C#だとdeleteもしなくていいもんね。
ところでこれ、一番素直に書く方法は、リストをもう一個作って残すモノだけそれにpushして最後に新しいリストで置換する方法かなー?