Skip to content

Instantly share code, notes, and snippets.

@selfsame
Last active August 29, 2015 14:18
Show Gist options
  • Select an option

  • Save selfsame/08cb0c63b814fb204305 to your computer and use it in GitHub Desktop.

Select an option

Save selfsame/08cb0c63b814fb204305 to your computer and use it in GitHub Desktop.
tween.core
(ns tween.core
(:require arcadia.core clojure.string)
(:import [UnityEngine Color Vector3 GameObject Color]))
;TODO
;[ ] deftween fn for +'ing target and value for relative target
;[ ] link! protocol for adding callbacks
;[ ] callback should handle sequences
;[ ] delay functionality (in link! ?)
;[ ] tweens should call finish with remainder float, if a callback is a tween add remainder to start time
;[x] when recycling tween comp or destroying, make sure uid is dissoc'd from REGISTRY
(defn -V+ [^Vector3 a ^Vector3 b] (Vector3/op_Addition a b))
(def ^:private UID (atom 0))
(def REGISTRY (atom {}))
(def PROP-GETS (atom {}))
(defn finish [uid c]
(when-let [f (get @REGISTRY uid)]
(swap! REGISTRY dissoc uid)
(f c)))
(deftype Tween [^System.MonoType component opts callbacks]
clojure.lang.IObj
(ToString [this] (str "" component "|" (:duration opts)))
(meta [this] (meta opts))
clojure.lang.ILookup
(valAt [_ k] (if (= k :callback) @callbacks (get opts k)))
(valAt [_ k nf] (if (= k :callback) @callbacks (get opts k nf)))
clojure.lang.Associative
(assoc [this k v]
(if (= k :callback)
(do (reset! callbacks v) this)
(Tween. component (assoc opts k v) (atom @callbacks))))
clojure.lang.IPersistentCollection
(equiv [self o]
(if (instance? Tween o)
(and (= component (.component o))
(= opts (.opts o)))
false))
clojure.lang.IFn
(invoke [this go]
(let [pre-c (.GetComponent go component)
c (or pre-c (.AddComponent go component))
uid (int (swap! UID inc))]
(set! (.active c) true)
(set! (.value c) (.target c))
(when pre-c
(swap! REGISTRY dissoc (.uid c))
(set! (.value c) (.target c)))
(when @callbacks
(swap! REGISTRY conj {uid @callbacks}))
(set! (.uid c) uid)
(set! (.start c) (float (UnityEngine.Time/time)))
(set! (.duration c) (float (:duration opts)))
(when-let [getter (get @PROP-GETS (last (clojure.string/split (str component) #"\.")))]
(set! (.value c) (getter go)))
(if (:+ opts)
(set! (.target c) (-V+ (.value c) (:target opts)))
(set! (.target c) (:target opts)))
go)) )
(defn make [c target & more]
(let [args (conj {:target target :duration 1.0 :+ false :callback nil}
(into {} (mapv
#(cond
(= :+ %) {:+ true}
(number? %) {:duration %}
(instance? clojure.lang.IFn %) {:callback %})
more)))]
(Tween. c (dissoc args :callback) (atom (:callback args)))))
(defmacro deftween [sym props getter valuer & setter]
(let [compsym (symbol (str sym "_tween"))
res-props (concat '[^boolean active ^float delay ^float start ^float duration ^boolean relative ^float ratio ^int uid] props)
[_ [this] get-more] getter
[_ [this-v] value-more] valuer
set-more (if (first setter) (first (drop 2 (first setter))) (list 'set! get-more value-more))]
`(~'do
(~'swap! ~'tween.core/PROP-GETS ~'conj {(~'str (~'quote ~compsym)) (~'fn [~this] ~get-more)})
(~'arcadia.core/defcomponent ~compsym ~res-props
(~'Awake [~this]
('~use '~'hard.core)
(~'set! (~'.duration ~this) (float 5.0))
(~'set! (~'.start ~this) (~'UnityEngine.Time/time))
(~'set! (~'.value ~this) ~get-more)
(~'set! (~'.target ~this) ~get-more))
(~'Update [~this-v]
(~'if (~'.active ~this-v)
(~'if (~'> (~'- (~'UnityEngine.Time/time) (~'.start ~this-v)) (~'.duration ~this-v))
(~'do
(~'set! (~'.ratio ~this-v) ~'(float 1.0))
~set-more
(~'set! (~'.active ~this-v) ~'false)
(~'tween.core/finish (~'.uid ~this-v) (~'.gameObject ~this-v))
(~'set! (~'.delay ~this-v) (~'float (~'- (~'.delay ~this-v) (~'- (~'- (~'UnityEngine.Time/time) (~'.start ~this-v)) (~'.duration ~this-v))))))
(~'do
(~'set! (~'.ratio ~this-v) (~'float (~'/ (~'- (~'UnityEngine.Time/time) (~'.start ~this-v)) (~'.duration ~this-v))))
~set-more)
)))
~'(OnDestroy [this]
(swap! tween.core/REGISTRY dissoc (.uid this))))
(~'defn ~sym [~'& ~'more] (~'apply ~'tween.core/make (~'cons ~compsym ~'more)))
)))
(deftween position [^Vector3 value ^Vector3 target]
(-get [this] (.position (.transform this)))
(-value [this] (Vector3/Lerp value target (.ratio this))))
(deftween scale [^Vector3 value ^Vector3 target]
(-get [this] (.localScale (.transform this)))
(-value [this] (Vector3/Lerp (.value this) (.target this) (.ratio this))))
(deftween euler [^Vector3 value ^Vector3 target]
(-get [this] (.eulerAngles (.transform this)))
(-value [this] (Vector3/Lerp (.value this) (.target this) (.ratio this))))
(deftween material-color [^Color value ^Color target]
(-get [this] (.color (.material (.GetComponent this UnityEngine.Renderer))))
(-value [this] (Color/Lerp (.value this) (.target this) (.ratio this))))
(deftween text-color [^Color value ^Color target]
(-get [this] (.color (.GetComponent this "TextMesh")))
(-value [this] (Color/Lerp (.value this) (.target this) (.ratio this))))
(deftween light-color [^Color value ^Color target]
(-get [this] (.color (.GetComponent this "Light")))
(-value [this] (Color/Lerp (.value this) (.target this) (.ratio this))))
(deftween light-range [^float value ^float target]
(-get [this] (.range (.GetComponent this "Light")))
(-value [this] (float (+ value (* (- target value) (.ratio this))))))
(deftween material-texture-offset [^Vector2 value ^Vector2 target]
(-get [this] (.GetTextureOffset (.material (.GetComponent this UnityEngine.Renderer) "_MainTex")))
(-value [this] )
(-set [this] (.SetTextureOffset (.material (.GetComponent this UnityEngine.Renderer))
"_MainTex"
(Vector2/Lerp (.value this) (.target this) (.ratio this)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment