ClojureのQuilでflappy bird。第5回

2023-05-04

「Nature of Code -Processingではじめる自然現象のシミュレーション」という本を入手。1章完了まで進めたので、おさらいに、フラッピーバードを作成中。
Clojureを勉強中なので、こうした方がいいよとかあれば、ツッコミお願いします。

前回は、キーを押すと浮上する処理を作成しました。

今回は、障害物の表示を作成します。

障害物のスクロール

とりあえず、障害物も四角で表します。描画に使う関数は自機と共通にできるので、データの作成と表示をつくります。

摩擦や空気抵抗は再現していないので、生成時点のみ加速度を加れば、あとはその速度を維持したまま移動します。

(defn setup []
  (q/frame-rate 30)
  {:bird (mv/mover (/ (q/width) 4.) (/ (q/height) 2.))
   :pipe (-> (mv/mover (q/width)  (/ (q/height) 4.))     ;パイプを追加
              (mv/apply-force [-1 0]))})                 ;左向きの加速を適用

(defn update-state [{:keys [bird pipe] :as all}] 
  (let [update-bird #(-> %                              
                         (mv/apply-force gravity)
                         (mv/update))] 
    (-> all
        (update :bird update-bird)                       ;データを更新
        (update :pipe mv/update))))                      ;データを更新

(defn draw-state [{:keys [bird pipe]}]
  (q/background bgcolor) 
  (mv/display bird)
  (mv/display pipe))                                      ;表示

画面右から障害物が移動してくるようになりました。

大きさに違いをつくる

移動はできたので、自機と障害物の見分けがつくようにします。

moverで作るデータに、大きさを配列で持つ:sizeを追加し、display!関数でそれを元に描画します。

(t/testing "moverは、location,velocity,acceleration,sizeをもつマップを返す"
    (t/is (= {:location [100. 110.]
              :velocity [0. 0.]
              :acceleration [0. 0.]
              :size [30. 40.]}                  ;追加
             (mv/mover 100. 110. 30. 40.))))    ;変更
(defn mover [x y w h]
  {:location [x y]
   :velocity [0. 0.]
   :acceleration [0. 0.]
   :size [w h]})                              ;追加

;略

(defn display [{[x y] :location [w h] :size}]  ;変更 :sizeの値をw hに束縛
  (q/stroke 0)
  (q/fill 170)
  (q/rect x y w h))                            ;幅、高さを引数から指定
(defn setup []
  (q/frame-rate 30)
  {:bird (mv/mover (/ (q/width) 4.) (/ (q/height) 2.) 30 30)    ;サイズを追加
   :pipe (-> (mv/mover (q/width)  (/ (q/height) 4.) 50 100)     ;サイズを追加
              (mv/apply-force [-1 0]))})

自機と障害物の大きさに違いをつくれました。

障害物を複数表示

:pipeを配列にして、複数のmoverを処理するように変更します。


(defn setup []
  (q/frame-rate 30)
  {:bird (mv/mover (/ (q/width) 4.) (/ (q/height) 2.) 30. 30.)
   :pipes (for [n (range 5)]                                 ;5つのmover
            (-> (mv/mover (+ (q/width) (* 50. n))             ;xを50ずつずらして配置
                          (rand-int  (q/height))             ;yはランダム
                          50. 100.)
                (mv/apply-force [-1 0])))})                  ;移動スピード

(defn update-state [status]  
  (-> status
      (update :bird #(-> %
                         (mv/apply-force gravity)
                         (mv/update)))
      (update :pipes #(map mv/update %))))                    ;mapで全てのmoverを更新

(defn draw-state [{:keys [bird pipes]}]
  (q/background bgcolor) 
  (mv/display bird) 
  (doseq [p pipes] 
      (mv/display p)))                                        ;副作用があるのでdoseqで全てを描画

複数のブロックを表示できました。

まとめ

複数の障害物を表示できるようになりました。

次回は当たり判定を作成します。