ClojureのQuilでflappy bird。第6回

「Nature of Code -Processingではじめる自然現象のシミュレーション」という本を入手。1章完了まで進めたので、おさらいに、フラッピーバードを作成中。
Clojureを勉強中なので、こうした方がいいよとかあれば、ツッコミお願いします。
前回は、障害物の表示を作成しました。
今回は、衝突判定を作成します。
当たり判定を作る
1つの点が四角形とぶつかっている(四角の中にある)かどうかは、
点のx座標が四角の幅の中にある、かつ、点のY座標が四角の高さの中にある
(and (<= x1 x x2) (<= y1 y y2))
で判断できます。
それの応用で、四角形と四角形がぶつかっているかの判断は、下の式で判断できるようです。
;;mover_test.clj
(t/testing "collision?"
(let [m1 (mv/mover 20. 30. 40. 50.)
m2 (mv/mover 100. 110. 20. 30.)
m3 (mv/mover 10. 10. 30. 30.)
m4 (mv/mover 10. 10. 100. 100.)
m5 (mv/mover 25. 35. 35. 45.)
]
(t/testing "範囲外はfalse"
(t/is (not (mv/collision? m1 m2))))
(t/testing "範囲内はtrue"
(t/is (mv/collision? m1 m3)) ;i一部が重なる
(t/is (mv/collision? m1 m4)) ;m4 ⊃ m1
(t/is (mv/collision? m1 m5)) ;m1 ⊃ m5
)))
;;mover.clj
(defn collision? [a b]
(let [[ax1 ay1] (:location a)
[ax2 ay2] (map + [ax1 ay1] (:size a)) ;;四角形左上の座標に幅高さを足して右下の座標を求める
[bx1 by1] (:location b)
[bx2 by2] (map + [bx1 by1] (:size b))]
(and (<= (max ax1 bx1) (min ax2 bx2)) ;;当たり判定
(<= (max ay1 by1) (min ay2 by2)))))
テストを通ったので、組み込んでいきます。
当たりを判定する
まずは、update-stateにぶつかり判定を入れてみます。
(defn update-state [status]
(let [new-status (-> status
(update :bird #(-> %
(mv/apply-force gravity)
(mv/update)))
(update :pipes #(map mv/update %)))]
(when (->> new-status ;;更新した位置で
:pipes ;;土管と
(map #(mv/collision? (:bird new-status) %)) ;;自機が↓ぶつかっていたら
(some true?)) ;;ひとつでも
(println "hit!")) ;;"hit"の文字を出力
new-status))
動作確認すると、hitの文字が出力されました。
ゲームオーバーをつくる
自機が土管にぶつかったら、ゲームオーバーにして描画や操作の受付を停止します。
ゲームオーバーを判断するために、関数間で渡しているマップに:game-over? false を追加します。
update-statusでは、game-over?が、trueなら受け取ったマップをそのまま返す、falseなら通常の処理
draw-stateでは、game-over?が、trueならgame overの文字を表示、falseなら通常の処理するように変更します。
(defn setup []
(q/frame-rate 30)
{:bird (mv/mover (/ (q/width) 4.) (/ (q/height) 2.) 30. 30.)
;;略
:game-over? false}) ;追加
(defn update-state [{:keys [game-over?] :as status}]
(if game-over?
status ;;game overならマップをそのまま帰す
(let [new-status (-> status
;;略
)
hit? (->> new-status ;;当たり判定
:pipes
(map #(mv/collision? (:bird new-status) %))
(some true?))]
(assoc new-status :game-over? hit?)))) ;;判定結果でマップを更新
(defn draw-state [{:keys [bird pipes game-over?]}]
(if game-over?
(do ;;game overなら
(q/text-size 32)
(q/fill 0)
(q/text "game-over!" (-> (q/width) (/ 2) (- 80)) (/ (q/height) 2))) ;;gameover表示
(do
;;略 ;;通常の処理
))))
これで、自機が障害物に当たるとゲームオーバーするようになりました。

まとめ
今回は、当たり判定とゲームオーバーの処理を追加しました。
次は、以下を作成します。
- 障害物(土管)を上下ペアで現れるように
- 得点の表示
- 障害物を通過したら点数が入る
- 落下、上昇、スクロールなどのスピード調整
ディスカッション
コメント一覧
まだ、コメントがありません