Add time travel
This commit is contained in:
@@ -43,12 +43,6 @@
|
||||
(load "core_listeners")
|
||||
(load "core_utils")
|
||||
|
||||
(defn ^:private reset-changed!
|
||||
[e-atom e-old e-new]
|
||||
(when (and (not= e-old e-new)
|
||||
(compare-and-set! e-atom e-old e-new))
|
||||
e-new))
|
||||
|
||||
(defn ^:private normalize
|
||||
[entities]
|
||||
(some->> entities
|
||||
@@ -58,9 +52,26 @@
|
||||
vec))
|
||||
|
||||
(defn ^:private wrapper
|
||||
[screen screen-fn]
|
||||
[screen-atom screen-fn]
|
||||
(screen-fn))
|
||||
|
||||
(defn ^:private reset-changed!
|
||||
[e-atom e-old e-new]
|
||||
(when (and (not= e-old e-new)
|
||||
(compare-and-set! e-atom e-old e-new))
|
||||
e-new))
|
||||
|
||||
(defn ^:private add-to-timeline!
|
||||
[screen-atom entities]
|
||||
(let [screen @screen-atom]
|
||||
(when (:record? screen)
|
||||
(swap! screen-atom
|
||||
update-in
|
||||
[:timeline]
|
||||
#(conj (or %1 []) %2)
|
||||
[(:total-time screen) entities])))
|
||||
entities)
|
||||
|
||||
(defn defscreen*
|
||||
[screen entities
|
||||
{:keys [on-show on-render on-hide on-pause on-resize on-resume on-timer]
|
||||
@@ -74,12 +85,12 @@
|
||||
(meta func))
|
||||
(wrapper screen)
|
||||
(reset-changed! entities old-entities)
|
||||
(update-screen! @screen)))))
|
||||
(update-screen! @screen)))
|
||||
@entities))
|
||||
execute-fn-on-gl! (fn [& args]
|
||||
(on-gl (apply execute-fn! args)))
|
||||
update-fn! (fn [func & args]
|
||||
(doto (apply swap! screen func args)
|
||||
update-screen!))]
|
||||
(apply swap! screen func args))]
|
||||
{:screen screen
|
||||
:entities entities
|
||||
:execute-fn! execute-fn!
|
||||
@@ -92,7 +103,6 @@
|
||||
(some-> @screen :world :object .dispose)
|
||||
; set the initial values in the screen map
|
||||
(update-fn! assoc
|
||||
:total-time 0
|
||||
:execute-fn! execute-fn!
|
||||
:execute-fn-on-gl! execute-fn-on-gl!
|
||||
:update-fn! update-fn!
|
||||
@@ -105,10 +115,12 @@
|
||||
(execute-fn! on-show)
|
||||
; update the physics contact listener if a :world was created
|
||||
(some->> (contact-listener @screen options execute-fn!)
|
||||
(update-fn! assoc :contact-listener)))
|
||||
(update-fn! assoc :contact-listener)
|
||||
update-screen!))
|
||||
:render (fn [d]
|
||||
(swap! screen #(assoc % :total-time (+ (:total-time %) d)))
|
||||
(execute-fn! on-render :delta-time d))
|
||||
(swap! screen update-in [:total-time] #(+ (or %1 0) %2) d)
|
||||
(->> (execute-fn! on-render :delta-time d)
|
||||
(add-to-timeline! screen)))
|
||||
:hide #(execute-fn! on-hide)
|
||||
:pause #(execute-fn! on-pause)
|
||||
:resize (fn [w h]
|
||||
@@ -135,7 +147,7 @@ via the screen map.
|
||||
:on-render
|
||||
(fn [screen entities]
|
||||
(println (:delta-time screen)) ; time (ms) elapsed since last frame
|
||||
(println (:total-time screen)) ; time (ms) elapsed since :on-show
|
||||
(println (:total-time screen)) ; time (ms) elapsed since first :on-show
|
||||
entities)
|
||||
; the screen was replaced
|
||||
:on-hide
|
||||
@@ -549,7 +561,8 @@ is the atom storing the screen map behind the scenes. Returns the updated
|
||||
|
||||
(update! screen :renderer (stage))"
|
||||
[screen & args]
|
||||
(apply (:update-fn! screen) assoc args))
|
||||
(doto (apply (:update-fn! screen) assoc args)
|
||||
update-screen!))
|
||||
|
||||
(defn screen!
|
||||
"Runs a function defined in another screen. You may optionally pass a series
|
||||
|
||||
@@ -78,6 +78,24 @@ specified path.
|
||||
~name)]
|
||||
(u/call! p# ~k ~@options)))
|
||||
|
||||
(defn rewind!
|
||||
"Returns the most recent entities vector saved in the timeline after removing
|
||||
the last `steps` from it. The timeline is recorded by calling
|
||||
`(update! screen :record? true)`.
|
||||
|
||||
If there are 100 items saved in the timeline and `(rewind! screen 1)` is called,
|
||||
it will remove the last one and return the entities vector from the 99th item.
|
||||
If `steps` is invalid, nil is returned.
|
||||
|
||||
If you want to do something more complex with the timeline than a simple rewind,
|
||||
you can directly access it via `(:timeline screen)`. Each item inside it is a
|
||||
vector containing a timestamp (seconds since the screen was first shown) and an
|
||||
entities vector."
|
||||
[{:keys [timeline update-fn!] :as screen} steps]
|
||||
(when-let [[total-time entities] (get timeline (- (count timeline) steps 1))]
|
||||
(update-fn! update-in [:timeline] subvec 0 (- (count timeline) steps 1))
|
||||
entities))
|
||||
|
||||
; static fields
|
||||
|
||||
(defmacro scaling
|
||||
|
||||
Reference in New Issue
Block a user