I want to write simple game with Cljfx library. I need the square I wrote on canvas is keep moving in one of four directions after key event happened. I decided to make some animation: draw and render canvas repeatedly. The state of Canvas is keep changing through this time. After drawning and rendering the thread sleeps sometime. But nothing is drawn during iterations. The thread just sleeps till the end of looping. And only after that canvas is refreshed. Can I do such a simple animation with Cljfx?
In project.clj
:dependencies [[org.clojure/clojure "1.10.0"]
[cljfx "1.7.22"]]
In core.clj
(ns examp
(:require [cljfx.api :as fx])
(:import [javafx.scene.canvas Canvas]
[javafx.scene.paint Color]
[javafx.scene.input KeyCode KeyEvent]))
(def ^:const WIDTH 300) ;Canvas width
(def ^:const HEIGHT 300) ;Canvas height
(declare root)
(declare renderer)
;Our mutable state
(def state*
(atom
{:x (/ WIDTH 2)
:y (/ HEIGHT 2)}))
;Defining canvas
(defn canvas [{:keys [width height x y]}]
{:fx/type :canvas
:width width
:height height
:draw (fn [^Canvas canvas]
(doto (.getGraphicsContext2D canvas)
(.setFill Color/BLACK)
(.fillRect 0 0 width height)
(.setFill Color/GREEN)
(.fillRect x y 10 10)))})
;Function for handling events
(defn event-handle [event]
(if (= :event/scene-event (:event/type event))
(cond
(= KeyCode/RIGHT (.getCode ^KeyEvent (:fx/event event)))
(dotimes [_ 3]
(swap! state* update-in [:x] #(+ % 10))
(renderer {:fx/type root :state @state*})
(Thread/sleep 300))
(= KeyCode/LEFT (.getCode ^KeyEvent (:fx/event event)))
(dotimes [_ 3]
(swap! state* update-in [:x] #(- % 10))
(renderer {:fx/type root :state @state*})
(Thread/sleep 300))
(= KeyCode/DOWN (.getCode ^KeyEvent (:fx/event event)))
(dotimes [_ 3]
(swap! state* update-in [:y] #(+ % 10))
(renderer {:fx/type root :state @state*})
(Thread/sleep 150))
(= KeyCode/UP (.getCode ^KeyEvent (:fx/event event)))
(dotimes [_ 3]
(swap! state* update-in [:y] #(- % 10))
(renderer {:fx/type root :state @state*})
(Thread/sleep 150)))))
;Main window
(defn root [{:keys [state]}]
{:fx/type :stage
:showing true
:scene {:fx/type :scene
:on-key-pressed {:event/type :event/scene-event}
:root {:fx/type :v-box
:children [{:fx/type canvas
:width WIDTH
:height HEIGHT
:x (:x state)
:y (:y state)}]}}})
;Define randerer
(def renderer
(fx/create-renderer
:opts {:fx.opt/map-event-handler event-handle}))
;Render miain window
(renderer {:fx/type root :state @state*})