グレインの備忘録

プログラミング関係とかをつらつらと。

OOP初心者がブロック崩しを作ってみる その2

※この記事は「OOP初心者がブロック崩しを作ってみる その1」の続きです

衝突判定を考える

さて、衝突判定のやり方を考えよう。

衝突はボールとReflectorの間で起こる。とりあえず以下のようにクラス分けしてみる。

f:id:grainrigi:20170902161501p:plain

ReflectorCollectionにReflectorを全て格納しておいて、Ball側から参照、衝突判定を行う。

move関数はBallに速度に従っての移動を指示する関数で、移動するたびに衝突判定を行う。

BallとReflectorのgetRect関数はそれぞれの専有する範囲を返す。(衝突判定に使用)

衝突判定を外に出す

これでも悪くはないが、Ballが「移動する物体」と「衝突する物体」の2つの役割を持っているので、分割したい。

ということで、衝突判定は外に出し、Ballは速度に従って移動することに専念することにする。

f:id:grainrigi:20170902163639p:plain

CollisionManagerが衝突判定を担当する。

流れとしては、

  1. Ballのmove関数が呼ばれる
  2. Ballが速度に従って移動
  3. BallがexecuteCollisionを呼ぶ
  4. CollisionManagerが全Reflectorと衝突判定
  5. CollisionManagerがgiveImpulseを呼び、ボールに力積を与える

という感じ。

Observerパターンを適用する

結合度の面から言えば、BallとCollisionManagerがお互いの関数を直接呼び出しているのであまり良くない。

そもそも、CollisionManagerはボールの移動をトリガーとして衝突判定を行うのである。

したがって、CollisionManagerがボールの移動を監視すれば良い。

つまり、Observerパターンを適用する。

f:id:grainrigi:20170902171012p:plain

move関数で移動した後、observerに移動を通知する。

これで多少はすっきりした。

Reflectorが衝突を知るには

ブロックのように衝突の有無を情報として必要とするReflectorが存在するので、それを通知する必要がある。

それもCollisionManagerが担当するのが妥当であろう。

以上のことを加味してまとめたクラス図はこうなった。

f:id:grainrigi:20170902171952p:plain

衝突判定に関しては概ねこのような感じでいいだろう。

次回予告

次回「OOP初心者がブロック崩しを作ってみる その3」は、この大まかな設計を基に実際にコードを書いてみることにする。