衝突判定

enchant.jsには衝突判定の関数が用意されているが、残念ながら透明色が考慮されていない。
例えば公式Materialの「イトカワ」と32x32で抜き出した「はやぶさ」の衝突判定を行うと、見た目上ぶつかっていないのに関数がtrueを返してくる場合がある。
パッと思い付く解決策は2つ。
ひとつ目は画像が重なっている範囲で透明職でない部分があるか判断する方法。
ふたつ目は別途衝突判定用のEntityを用意してやることだ。

ひとつ目だが、残念ながら実装することができない。SurfaceにはgetPixselというピクセル単位の情報を取得する関数があるのだが、何故かロードした画像に対しては無効なのだ。

ではふたつ目は実装することができるのか。これはそんな難しいことではない。
イトカワ」の形に沿うように円形や矩形を描画したEntityを配置し、それらと衝突判定を実行するのだ。気を付ける点は判定用のEntityがユーザに見えないようにすること。これはaddChildの順番を考慮するかopacityを0にすればいい。多分だが、そもそもaddChildしなければいいだけだと思う。

実は第3の道がある。
これはふたつ目の案に似ているのだが、根本が大きく異なる。
HTML5CanvasにはisPointInPathという関数があり、任意の座標があるPathの中にあるかどうかを返してくれる。これを利用すれば、かなり複雑なグラフィックであっても詳細な衝突判定が可能になる。Pathを書くのが地獄だが。
注意点は、PathはベースのEntityに連動して動いてはくれないというところだ。これを忘れるとぶつかっても何も起こらなかったり、ぶつかっていないのに衝突処理が実行されるということになる。

「ミッション!」ではこの第3の道を選択したのだが、「イトカワ」の形状から察するに、今思うとふたつ目の案の方がスマートだったかも知れない。

enchant.jsの衝突判定といえば、もうひとつ注意したい点がある。

enchant.jsには画像を拡大させるscaleという関数が用意されている。この関数を使えば当然画像は拡大されるが、衝突判定の領域が拡大されるわけではない。これを忘れると、ぶつかっているのに反応なし、あるいはぶつかっていないのに反応あり、なんてことになる。
rotate関数で画像を回転させた場合も同じだ。