同じHitイベントが1フレームに2回発生する原因と対処法
「実は昨日の実験の最中に、ティックの発生タイミングとは別の問題に気付いてしまった。記事にしたかどうかは忘れたんだけど、妹が作ってたアクションゲームの試作で、1フレーム2回Hitイベントが起きるっていうバグがあったよね?」
妹「あったよ。パンチした時に、手のコリジョンから2回Hitが出てくるの。たまに1個の時もあって、敵との位置関係で違うみたいだったけど」
「その原因が少しわかってきたんだよ」
「昨日取ってたログの一部なんだけど、地面にあたった時、2回Hitが発生してるんだよ。"フィジックス中"の前と後で」
妹「地面に当たったら……その後は跳ね返って上に行くんだから、2回も地面に当たる必要ないよね」
「そう、1回でいい」
「この"SimulationGeneratesHitEvents"を、最初は地面とボールと両方に設定してたんだよ。Hitイベントが起きないと困るなと思って。でもこれを両方ともチェック外すと、"フィジックス中"の手前の分だけ残った」
妹「あれ要らなかったの!?」
「でもその状態だと、勢いがなくなって地面に落ちて止まった後は、Hitが発生しなくなる。厳密に言えば毎フレーム重力で下に落ちようとして、地面にあたって押し戻されてるはずだから、Hitしてるとも言えるんだけど、それは"SimulationGeneratesHitEvents"がないとノーカウントになるみたい」
妹「見た目から言えば動いてないし、もう止まってるから、Hitもしてないってことかなあ……」
- "SimulationGeneratesHitEvents"のチェックを外す(両方、もしくは片方、都合のいい方法で)
- HitイベントではHitしたアクターの記録だけして、実際の処理はその後のTickイベントでやる(ティックグループは"フィジックス後"にする)
「こういう対策をすれば2回Hit問題には対処できそう」
妹「Hitしたアクターの記録というのは?」
「HitしたタイミングでActor型の配列に追加して、もう配列に同じアクターがある場合は無視する。で、後のTickでForeachとか使って処理して、終わったら配列をClearする。これで毎フレーム1回分の処理が出来る。TSET型が実装されたら、配列じゃなくてそっち使ってもいいかも」
妹「全部にそういうの仕込むの大変そう」
「そのへんはComponent化するとかでなんとか」