ClojureのQuilでflappy bird。第4回

2023-05-02

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

前回は、落下の動きを作成しました。

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

イベントハンドラの作成

まず、イベントハンドラを作成します。引数は2つ、関数間でやり取りしているデータと、イベントの情報。

(defn key-pressed [status event]
  (println event)
  status)

作った関数を、defsketchに登録します。

(q/defsketch flappy-bird
  :title "flappy bird"
  :size [400 600]
  :setup setup
  :update update-state
  :draw draw-state
  :key-pressed key-pressed        ;;追加
  :features [:keep-on-top]
  :middleware [m/fun-mode])

評価してキーを押してみると、以下のようなマップでイベント情報を受け取っています。

{:key :a
 :key-code 65
 :raw-key a
 :modifiers #{}}

キー押下で加速度を追加する

加速度 → 速度 → 位置 と連鎖するので、キーが押された時に上向きの加速度を追加した値を返せば浮上します。(nature of code では更に、加わる力と物体の重さ → 加速度 となっているけど、そこは省略します)

このとき、下向きの重力と上向きの浮上力を加算する必要があるので、関数を作っておきます。

(t/testing "apply-force accelarationに加算する"
    (let [m0 (mv/mover 100. 110.)
          m1 (mv/apply-force m0 [-10. 20.])
          m2 (mv/apply-force m1 [3. -5.])]
      (t/is (= [-10. 20.] (:acceleration m1)))
      (t/is (= [-7. 15.] (:acceleration m2)))))
(defn apply-force [m f]
  (let [a (qv/add (:acceleration m) f)]
    (assoc m :acceleration a)))

それを使って、key-pressedでデータを更新して返します。

ジャンプ力と重力の値は、defで宣言しておきます。(引数のマップに入れるのもアリだと思いますが)

(def gravity [0. 0.2])             ;追加
(def jumping-power [0. -10.])      ;追加

;略

(defn key-pressed [{:keys [bird] :as all} {:keys [key]}]
  (if (= key :up)
      (let [new-bird (mv/apply-force bird jumping-power)]    ;; 浮上力を適用
        (assoc all :bird new-bird))
      all))

実行してみると、自機が吹っ飛んでいきました…。

加速度をクリアする

吹っ飛んでいった原因は、キー押下で追加された上向き加速度が残ったままになっていることでした。キーを離しても、update-stateが呼ばれるたびに上向きに加速してしまいます。

そこでmover/updateを実行すると:accelarationを[0 0]に戻すようにして、update-stateのたびに:accelarationに重力を適用します。

(defn update [m]
  (letfn [(ud [m to from]
            (clojure.core/update m to (partial qv/add (from m))))]
    (-> m
        (ud :velocity :acceleration)
        (ud :location :velocity)
        (assoc :acceleration [0. 0.]))))     ;追加
(defn setup []
  (q/frame-rate 30)
  {:bird (-> (mv/mover 100. 100.))})          ;accelarationを削除

(defn update-state [{:keys [bird]}]
  (let [gravity [0. 0.3]
        new-bird (-> bird
                     (mv/apply-force gravity)  ;追加
                     (mv/update))]
    {:bird new-bird}))

重力、ジャンプ力の調整は必要ですが、これでキーを押すと浮上するようになりました。

まとめ

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

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