【enchant.js】Hello Physical World vol.8【box2d】

気がつけばもう2月も1週が過ぎました。
お久しぶりです。
最低でも月に1度の更新を目標としている本ブログですが、1月はvita版アマガミの発売を記念してひとりアマガミ・アペンドに挑戦していた上に、月末月初に病気と相成りまして結局更新ができませんでした。
そんなこんなで先行き不穏当な出だしでありますが、今年もよろしくお願いします。

さて。
前回(Vol.7)の最後で衝突時に実行されるcontact関数を扱おうとお約束しました。予告通り、今回はcontact関数の解説です。

contact関数はPhySprite及びbox2dの世界を司るPhysicsWorldそれぞれに用意されています。
まずはPhySpriteの関数であるcontactに焦点を当てましょう。
PhySpriteのcontact関数はコールバック関数を引数とします。さらにこのコールバック関数では、ぶつかったPhySpriteを引数とすることができます。
くどくど説明するより実際にコードを書いて実行してもらった方が理解が早いと思いますので、まず前回のコードを引っ張り出してきてgame.rootScene.onenterframeの中に以下のコードを追加し実行してみて下さい。

ball2.contact(function (sprite) {
    sprite.destroy();
});

どうでしょう。野球ボールの下にあった地面がいきなり消えてそのままボールは下に落ちていきましたね。
野球ボール、すなわちball2にfloor2が接触したため、ball2のcontact関数が実行されたのです。floor2は引数spriteとしてcontact関数に渡され、関数内に記述されたdestory関数を実行され、ゲーム上から削除されました。

それでは、ball2が何かにぶつかる度に画像が変わるようにしてみましょう。

ball2.contact(function (sprite) {
    this.frame++;
});

……変わりませんね。
実はcontactの実行空間は、ball2の配下じゃないんですね。なので、ball2にアクセスするには以下のようにしてやる必要があります。

ball2.contact(function (sprite) {
    ball2.frame++;
});

次はPhysicsWorldのcontact関数を見てみましょう。
PhysicsWorldのcontact関数の場合に引数とするコールバック関数では、2つのPhySpriteを引数とすることが出来ます。game.rootScene.onenterframeの中に以下のコードを追加すると、ぶつかったもの同士が消えます。

world.contact(function(sprite1, sprite2) {
    sprite1.destroy();
    sprite2.destroy();
});

最後に、本文中でさらりと出しているdestroy関数について解説します。
destroy関数は、実行するとenchant.js上からPhySpriteを削除する関数です。Spriteを削除するのはScene.removeChildを使うのでは? と思った方もいらっしゃると思います。
実はbox2dとenchant.jsはそれぞれ異なる世界を持っていて、Spriteを使用するにはそれぞれの世界に追加してやる必要があります。
box2dについてはPhySpriteを生成した時点で自動的に追加されます。enchant.jsにはいつも通りScene.addChildで追加します。
削除する時はdestroy関数を使うことでbox2d及びenchant.jsからSpriteを削除することが出来ます。
もしScene.removeChildを使用したらどうなるか。画面上からはSpriteは削除されますが、box2d上には残っていますので「何もないところにぶつかる」という事象が起こります。気をつけてくださいね。