Implement more flexible state management

This commit is contained in:
Jeremy Dormitzer 2019-11-08 23:34:45 -05:00
parent 81964a0d73
commit 850ef80139
3 changed files with 47 additions and 15 deletions

View File

@ -1,5 +1,6 @@
{:deps {org.clojure/clojure {:mvn/version "1.9.0"} {:deps {org.clojure/clojure {:mvn/version "1.9.0"}
org.clojure/clojurescript {:mvn/version "1.10.520"}} org.clojure/clojurescript {:mvn/version "1.10.520"}
binaryage/oops {:mvn/version "0.7.0"}}
:paths ["src" "resources"] :paths ["src" "resources"]
:aliases {:fig {:extra-deps :aliases {:fig {:extra-deps
{com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"} {com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}

View File

@ -1,6 +1,8 @@
(ns ^:figwheel-hooks three-playground.core (ns ^:figwheel-hooks three-playground.core
(:require (:require
[goog.dom :as gdom] [goog.dom :as gdom]
[goog.object :as obj]
[oops.core :refer [oset!+]]
[three])) [three]))
(defn get-app-element [] (defn get-app-element []
@ -24,31 +26,53 @@
(.setSize renderer (.-innerWidth js/window) (.-innerHeight js/window)) (.setSize renderer (.-innerWidth js/window) (.-innerHeight js/window))
(.add scene cube) (.add scene cube)
(atom {:running true (atom {:running true
:cube {:rotation {:x 0 :y 0}}
:renderer renderer :renderer renderer
:scene scene :entity-state {:cube {:rotation {:x 0 :y 0}}
:camera {:position {:z 5}} :camera {:position {:z 5}}}
:entities {:cube cube :entities {:scene scene
:cube cube
:camera camera}}))) :camera camera}})))
(defonce app-state (init-state)) (defonce app-state (init-state))
(defn update-state [state] (defn update-state [state]
(-> state (-> state
(assoc-in [:cube :rotation :x] (assoc-in [:entity-state :cube :rotation :x]
(+ (get-in state [:cube :rotation :x]) (+ (get-in state [:entity-state :cube :rotation :x])
0.01)) 0.03))
(assoc-in [:cube :rotation :y] (assoc-in [:entity-state :cube :rotation :y]
(+ (get-in state [:cube :rotation :y]) (+ (get-in state [:entity-state :cube :rotation :y])
0.01)))) 0.01))))
(defn map->paths [m]
(if (map? m)
(vec
(mapcat (fn [[k v]]
(let [sub (map->paths v)
nested (map #(into [k] %) (filter (comp not empty?) sub))]
(if (seq nested)
nested
[[k]])))
m))
[]))
(defn update-entities! [state]
(doseq [[id entity] (:entities state)]
(let [target-state (get-in state [:entity-state id])]
(when target-state
(doseq [path (map->paths target-state)]
(let [str-path (map name path)
current (apply aget entity str-path)
new (get-in target-state path)]
(when-not (= current new)
(oset!+ entity str-path new))))))))
(defn render [state] (defn render [state]
(let [{:keys [renderer scene]} state (let [renderer (:renderer state)
scene (get-in state [:entities :scene])
camera (get-in state [:entities :camera]) camera (get-in state [:entities :camera])
cube (get-in state [:entities :cube])] cube (get-in state [:entities :cube])]
(set! (-> camera (.-position) (.-z)) (get-in state [:camera :position :z])) (update-entities! state)
(set! (-> cube (.-rotation) (.-x)) (get-in state [:cube :rotation :x]))
(set! (-> cube (.-rotation) (.-y)) (get-in state [:cube :rotation :y]))
(.render renderer scene camera))) (.render renderer scene camera)))
(defn the-loop [] (defn the-loop []

View File

@ -1 +1,8 @@
(ns three-playground.core-test) (ns three-playground.core-test
(:require [cljs.test :refer-macros [deftest testing is]]
[three-playground.core :as core]))
(deftest test-map->paths
(testing "Basic case"
(is (= (core/map->paths {:foo {:bar 1 :baz 2} :qux 3})
[[:foo :bar] [:foo :baz] [:qux]]))))