diff --git a/src/cljs/topdown2d/core.cljs b/src/cljs/topdown2d/core.cljs index 4128a07..fba6d22 100644 --- a/src/cljs/topdown2d/core.cljs +++ b/src/cljs/topdown2d/core.cljs @@ -1,50 +1,40 @@ (ns topdown2d.core (:require - [topdown2d.demoscene :as demoscene] - [topdown2d.input :as input])) + [topdown2d.demoscene :as demoscene] + [topdown2d.input :as input])) (enable-console-print!) -(def gamestate { - :canvas (.getElementById js/document "gamecanvas") - :ctx (.getContext (.getElementById js/document "gamecanvas") "2d") - :target-fps 40 - :timing { - ; msecs of previous frame - :prev 0 - ; msecs of current frame - :now 0 - ; fps resulting of prev and now - :fps 0 - ; difference between prev and now in seconds - :elapsed 0 - } - ; width and height of the canvas - :dimensions { - :w 600 - :h 400 - } - :input { - :dir :? - } - ; currently active scene - :scene :demo - :scenes { - :demo { - :update demoscene/update-scene - :draw demoscene/draw-scene - :init demoscene/init - :data {} - } - } -}) +(def gamestate + {:canvas (.getElementById js/document "gamecanvas") + :ctx (.getContext (.getElementById js/document "gamecanvas") "2d") + :target-fps 40 + :timing {;; msecs of previous frame + :prev 0 + ;; msecs of current frame + :now 0 + ;; fps resulting of prev and now + :fps 0 + ;; difference between prev and now in seconds + :elapsed 0} + ;; width and height of the canvas + :dimensions {:w 600 + :h 400} + :input {:dir :?} + ;; currently active scene + :scene :demo + :scenes {:demo {:update demoscene/update-scene + :draw demoscene/draw-scene + :init demoscene/init + :data {}}}}) (defn set-timing "sets the current time at the given key" [state timingkey] - (assoc-in state - [:timing timingkey] - (.now js/performance))) + (assoc-in + state + [:timing timingkey] + (.now js/performance))) (defn set-fps "calculates the current fps using the elapsed time" @@ -56,11 +46,10 @@ (defn set-elapsed-seconds "calculates and writes the elapsed seconds since the last frame" [gamestate] - (assoc-in gamestate - [:timing :elapsed] - (/ - (- - (get-in gamestate [:timing :now]) + (assoc-in + gamestate + [:timing :elapsed] + (/ (-(get-in gamestate [:timing :now]) (get-in gamestate [:timing :prev])) 1000))) @@ -77,12 +66,12 @@ "updates timing information and the current scene" [gamestate] (-> gamestate - (assoc-in [:input :dir] (input/dir)) - (set-timing :now) - (set-elapsed-seconds) - (set-fps) - (update-scene) - (set-timing :prev))) + (assoc-in [:input :dir] (input/dir)) + (set-timing :now) + (set-elapsed-seconds) + (set-fps) + (update-scene) + (set-timing :prev))) (defn draw-fps "draws the current fps" @@ -90,22 +79,22 @@ (let [ctx (:ctx gamestate)] (aset ctx "fillStyle" "white") (.fillRect - ctx - 0 0 13 13) + ctx + 0 0 13 13) (aset ctx "fillStyle" "black") (aset ctx "font" "10px monospace") (.fillText - (:ctx gamestate) - (int (get-in gamestate [:timing :fps])) - 0 10))) + (:ctx gamestate) + (int (get-in gamestate [:timing :fps])) + 0 10))) (defn draw-step "clears the canvas, draws fps and invokes the scene draw function" [gamestate] (.clearRect (:ctx gamestate) - 0 0 - (get-in gamestate [:dimensions :w]) - (get-in gamestate [:dimensions :h])) + 0 0 + (get-in gamestate [:dimensions :w]) + (get-in gamestate [:dimensions :h])) (let [scenekey (:scene gamestate) scene (scenekey (:scenes gamestate)) drawfunc (:draw scene)] @@ -119,32 +108,34 @@ [gamestate] (let [newstate (update-step gamestate)] (draw-step newstate) - ; calculate the duration of update-step and draw-step - ; substract that from the wait time to reach target-fps - ; more accurately + ;; calculate the duration of update-step and draw-step + ;; substract that from the wait time to reach target-fps + ;; more accurately (let [now (get-in newstate [:timing :now]) duration (- (.now js/performance) now)] (.setTimeout js/window - (fn [] - (.requestAnimationFrame js/window - #(mainloop newstate))) - (/ - (- 1000 duration) - (:target-fps gamestate)))))) + (fn [] + (.requestAnimationFrame + js/window + #(mainloop newstate))) + (/ + (- 1000 duration) + (:target-fps gamestate)))))) (defn init-scenes "initiates the scene data maps using their respective init functions" [] (assoc - gamestate - :scenes - (reduce - (fn [scenes [scenekey scenedata]] - (let [initfunc (:init scenedata) - newdata (initfunc gamestate scenedata)] - (assoc scenes - scenekey newdata))) - {} - (:scenes gamestate)))) + gamestate + :scenes + (reduce + (fn [scenes [scenekey scenedata]] + (let [initfunc (:init scenedata) + newdata (initfunc gamestate scenedata)] + (assoc + scenes + scenekey newdata))) + {} + (:scenes gamestate)))) (mainloop (init-scenes)) diff --git a/src/cljs/topdown2d/demoscene.cljs b/src/cljs/topdown2d/demoscene.cljs index 778758a..2671e07 100644 --- a/src/cljs/topdown2d/demoscene.cljs +++ b/src/cljs/topdown2d/demoscene.cljs @@ -1,47 +1,38 @@ (ns topdown2d.demoscene (:require - [topdown2d.collision :as collision] - [topdown2d.input :as input] - [topdown2d.sprites :as sprites])) + [topdown2d.collision :as collision] + [topdown2d.input :as input] + [topdown2d.sprites :as sprites])) (defn init [gamestate scenedata] - (assoc scenedata - :data { - :player { - :x (- (/ (get-in gamestate [:dimensions :w]) 2) 32) - :y (- (/ (get-in gamestate [:dimensions :h]) 2) 32) - :w 64 :h 64 - :d :s - :sprite { - :image (.getElementById js/document "demo-player") - :size 64 - :rows { - :w 1 :e 3 - :n 0 :s 2 - :? 2 - } - :cycle { - :pos 0 - :from 1 :count 8 - :last-cycle 0 - ; seconds per cycle - :spc 0.08 - } - } - } - :viewport { - :image (.getElementById js/document "demo-background") - :keep-in { - :x 0 :y 0 - :w 2239 :h 2235 - } - :x 1 :y 1 - :d :? - :pps 350 - :w (get-in gamestate [:dimensions :w]) - :h (get-in gamestate [:dimensions :h]) - } - })) + (assoc + scenedata + :data + {:player {:x (- (/ (get-in gamestate [:dimensions :w]) 2) 32) + :y (- (/ (get-in gamestate [:dimensions :h]) 2) 32) + :w 64 :h 64 + :d :s + :sprite + {:image (.getElementById js/document "demo-player") + :size 64 + :rows {:w 1 :e 3 + :n 0 :s 2 + :? 2} + :cycle {:pos 0 + :from 1 + :count 8 + :last-cycle 0 + ;; seconds per cycle + :spc 0.08}}} + :viewport {:image (.getElementById js/document "demo-background") + :keep-in {:x 0 :y 0 + :w 2239 :h 2235} + :x 1 :y 1 + :d :? + :pps 350 + :w (get-in gamestate [:dimensions :w]) + :h (get-in gamestate [:dimensions :h]) + }})) (defn update-player [gamestate player dir] (let [old-dir (:d player) @@ -49,33 +40,33 @@ (as-> player p (assoc p :d new-dir) (if (= :? dir) - (sprites/reset-cycle player) - (sprites/proc-cycle gamestate p))))) + (sprites/reset player) + (sprites/proc gamestate p))))) (defn update-viewport [gamestate viewport dir] (collision/move-inside - (assoc viewport :d dir) - (:keep-in viewport) - (collision/pps->px gamestate viewport))) + (assoc viewport :d dir) + (:keep-in viewport) + (collision/pps->px gamestate viewport))) (defn update-scene [gamestate scenedata] (let [player (get-in scenedata [:data :player]) viewport (get-in scenedata [:data :viewport]) dir (get-in gamestate [:input :dir])] (-> scenedata - (assoc-in [:data :player] - (update-player gamestate player dir)) - (assoc-in [:data :viewport] - (update-viewport gamestate viewport dir))))) + (assoc-in [:data :player] + (update-player gamestate player dir)) + (assoc-in [:data :viewport] + (update-viewport gamestate viewport dir))))) (defn draw-scene [gamestate scenedata] (let [viewport (get-in scenedata [:data :viewport]) {:keys [x y w h background]} viewport] (.drawImage - (:ctx gamestate) - (:image viewport) - x y w h - 0 0 w h)) + (:ctx gamestate) + (:image viewport) + x y w h + 0 0 w h)) (sprites/draw - (:ctx gamestate) - (get-in scenedata [:data :player]))) + (:ctx gamestate) + (get-in scenedata [:data :player]))) diff --git a/src/cljs/topdown2d/input.cljs b/src/cljs/topdown2d/input.cljs index 1b8b2ce..d22f009 100644 --- a/src/cljs/topdown2d/input.cljs +++ b/src/cljs/topdown2d/input.cljs @@ -5,18 +5,20 @@ (defn keydown? [code] (get @keysdown (name code) false)) -(.addEventListener js/document - "keydown" - (fn [event] - (swap! keysdown #(assoc % (.-code event) true)) - false)) +(.addEventListener + js/document + "keydown" + (fn [event] + (swap! keysdown #(assoc % (.-code event) true)) + false)) -(.addEventListener js/document - "keyup" - (fn [event] - (swap! keysdown - #(assoc % (.-code event) false)) - false)) +(.addEventListener + js/document + "keyup" + (fn [event] + (swap! keysdown + #(assoc % (.-code event) false)) + false)) (defn dir [] (cond diff --git a/src/cljs/topdown2d/sprites.cljs b/src/cljs/topdown2d/sprites.cljs index 8cc8a72..35d2139 100644 --- a/src/cljs/topdown2d/sprites.cljs +++ b/src/cljs/topdown2d/sprites.cljs @@ -1,35 +1,42 @@ (ns topdown2d.sprites) -(defn proc-cycle [gamestate obj] +(defn- reset-cycle [obj] + (let [cycle (get-in obj [:sprite :cycle]) + {:keys [pos from] maxpos :count} cycle + reset-position? (> (inc pos) maxpos)] + (-> obj + ;; set position + (assoc-in + [:sprite :cycle :pos] + (if reset-position? + from + (inc pos))) + ;; timestamp of last cycle is 0 + (assoc-in + [:sprite :cycle :last-cycle] + 0)))) + +(defn proc [gamestate obj] (let [sprite (:sprite obj) sprite-cycle (:cycle sprite) - from (:from sprite-cycle) - maxpos (:count sprite-cycle) - {:keys [pos spc last-cycle]} sprite-cycle - restart? (> (inc pos) maxpos) + {:keys [spc last-cycle]} sprite-cycle elapsed (get-in gamestate [:timing :elapsed])] - ; new sprite frame? + ;; new sprite frame? (if (> (+ last-cycle elapsed) spc) - ; start cycle from new? - ; reset last-cycle - (-> obj - (assoc-in - [:sprite :cycle :pos] - (if restart? from (inc pos))) - (assoc-in - [:sprite :cycle :last-cycle] - 0)) - (update-in obj - [:sprite :cycle :last-cycle] - #(+ % elapsed))))) + (reset-cycle obj) + ;; no new sprite, increase last-cycle + (update-in + obj + [:sprite :cycle :last-cycle] + #(+ % elapsed))))) -(defn reset-cycle [obj] +(defn reset [obj] (assoc-in - obj - [:sprite :cycle :pos] - 0)) + obj + [:sprite :cycle :pos] + 0)) -(defn pos-in-sprite [sprite d] +(defn- pos-in-sprite [sprite d] (let [{:keys [size rows]} sprite pos (get-in sprite [:cycle :pos]) row (d rows)] @@ -41,7 +48,8 @@ sprite-size (:size sprite) sprite-cycle (:cycle sprite) pos (pos-in-sprite sprite d)] - (.drawImage ctx - image - (:x pos) (:y pos) sprite-size sprite-size - x y sprite-size sprite-size))) + (.drawImage + ctx + image + (:x pos) (:y pos) sprite-size sprite-size + x y sprite-size sprite-size)))