ゴミ箱.net

汚物は消毒

ゲーム製作日記5 衝突判定の続き

久々に更新するかw

前回では、領域を表す抽象クラスを作ってそこから円とか長方形とかの種類ごとに派生クラスを実装することを考えていたんだったな。
その場合に、異なる種類の領域どうしの当たり判定をどう実装するかを考えねばならなくなる。
どこかで具体的な処理をハードコーディングする必要は避けられないとはいえ、それを誰に持たせるか?円と長方形の衝突判定なら円がそれを受け持つのか?長方形か?もしくは独立した判定メソッドを作るのか?

解法1
すべての種類の領域のクラスに、他の種類の領域との衝突判定メソッドを種類ごとに実装する。
これは悪手も悪手、これをやるようだったら両手の指を切り落として二度とプログラムを組むなといわれるレベル。
まず実装が二度手間になってしまう。円のクラスが長方形との衝突判定、長方形のクラスが円との衝突判定を実装していたら無駄である。内部の実装を共通化することは可能とはいえ、どのみちメソッドを2つ用意しなければならない。
そして何より、これでは領域の種類を増やすことが難しい。種類を増やすごとに既存の領域の実装に手を入れねばならなくなる。もし第三者のライブラリだったらお手上げである。

解法2
領域のクラスにすべて順序づけをしておき、下位のクラスには上位のクラスとの衝突判定メソッドを実装する責任を持たせる。
上位のクラスが下位のクラスとの衝突判定をしたい場合は、下位のクラスが持つメソッドを呼び出せばよくなるので、実装の二度手間は省ける。
ただし、順序を一意に管理するのが面倒なのと、下位のクラスが必ず上位のクラスとの衝突判定メソッドを持たねばならないのでいちいち実装するのが面倒になる欠点がある。

解法3
それぞれの種類のクラスに、「相手の種類を知っていたら衝突判定する」メソッドを用意しておく。そして、自分が知らない種類の領域との衝突判定は相手側の「相手の種類を知っていたら衝突判定する」メソッドを呼び出すようにする。

以下のようなクラスを作成し、これを継承してCollidesIfKnownを実装する。
このメソッドでは、パラメータotherが自分が「知っている」種類であれば衝突判定を実施し、そうでない場合は例外を投げるようにする。(実際は三値論理を実現できればよく、特に例外にする必要はないが。)

class RegionBase : IRegion {
bool Collides(IRegion other) {
try {
return CollidesIfKnown(other);
} catch (UnknownRegionTypeException exception) {
return ((RegionBase)other).CollidesIfKnown(this);
}
}

abstract bool CollidesIfKnown(IRegion other) throws UnknownRegionTypeException;
}

この方法だと、解法2のような順序に縛られることはなくなる。
ただし、2種類のクラスのうちどちらかのCollidesIfKnownできちんと判定ができる必要はある。どちらのクラスでも実装をし忘れたらアウトだ。

解法4
そもそも領域のクラスには衝突判定の具体的な処理は実装しない。
衝突判定メソッドを実装した第三者的なクラス(衝突判定マネージャ?)を用意しておき、衝突判定マネージャにあらかじめ領域の種類と、対応するメソッドを登録しておく。
メソッドが集中管理できるので分かりやすく、また実装漏れも起こしにくいだろう。独自の種類を追加した場合はメソッドも自作して衝突判定マネージャに登録すればいい。
ただ領域のクラスと衝突判定のメソッドが切り離されてしまい分かりにくくなるデメリットはある。それに衝突判定メソッドを衝突判定マネージャに登録して管理しなければならないのも多少手間だ。


今回は解法3をとることにした。これがいちばん手間的な意味でマシな方法だろう。
スポンサーサイト

PageTop

コメント


管理者にだけ表示を許可する