parent
07c53dcf2b
commit
00c46a5ee7
@ -1,6 +1,6 @@ |
||||
(ns frpong.core) |
||||
|
||||
(defn foo |
||||
"I don't do a whole lot." |
||||
[x] |
||||
(println x "Hello, World!")) |
||||
(defmacro go-loop [& body] |
||||
`(cljs.core.async.macros/go |
||||
(while true |
||||
~@body))) |
||||
|
@ -1,20 +1,61 @@ |
||||
(ns frpong.core |
||||
(:require [cljs.core.async :as async |
||||
:refer [<! >! chan put!]] |
||||
[domina :as dom] |
||||
(:require [frpong.helpers :as h] |
||||
[cljs.core.async :as async |
||||
:refer [<! >! chan put! close! sliding-buffer dropping-buffer timeout]] |
||||
[domina :as dom :refer [log]] |
||||
[domina.events :as ev]) |
||||
(:require-macros [cljs.core.async.macros :as m :refer [go]])) |
||||
(:require-macros [cljs.core.async.macros :as m :refer [go]] |
||||
[frpong.core :refer (go-loop)])) |
||||
|
||||
(defn positioner [tick-chan vel-chan pos-chan-in pos-chan-out] |
||||
(go-loop |
||||
(let [tick (<! tick-chan) |
||||
[vel-x vel-y] (<! vel-chan) |
||||
[x y] (<! pos-chan-in) |
||||
pos-next [(+ x (* vel-x tick)) (+ y (* vel-y tick))]] |
||||
(>! pos-chan-out pos-next)))) |
||||
|
||||
(defn event-chan [event-type] |
||||
(let [c (chan)] |
||||
(ev/listen! js/document event-type |
||||
(fn [e] (put! c e))) |
||||
c)) |
||||
(defn collision-detector [width height tick-chan pos-chan vel-chan-in vel-chan-out] |
||||
(go-loop |
||||
(let [tick (<! tick-chan) |
||||
[vel-x vel-y] (<! vel-chan-in) |
||||
[x y] (<! pos-chan) |
||||
[xn yn] [(+ x (* vel-x tick)) (+ y (* vel-y tick))]] |
||||
(>! vel-chan-out |
||||
(cond |
||||
(< xn 0) [(- vel-x) vel-y] |
||||
(< yn 0) [vel-x (- vel-y)] |
||||
(> xn width) [(- vel-x) vel-y] |
||||
(> yn height) [vel-x (- vel-y)] |
||||
:else [vel-x vel-y]))))) |
||||
|
||||
(defn ^:export init [] |
||||
(let [mm-chan (event-chan :mousemove)] |
||||
(go |
||||
(while true |
||||
(let [e (<! mm-chan)] |
||||
(.log js/console (str (:clientX e) " , " (:clientY e)))))))) |
||||
(let [frame-chan (h/frame-chan) |
||||
[frame-chan1 frame-chan2] (h/dup-chan frame-chan) |
||||
|
||||
fps-chan (h/map-chan #(/ 1000 %) (h/diff-chan frame-chan2)) |
||||
|
||||
width 100 |
||||
height 100 |
||||
init-pos [0 50] |
||||
init-vel [0.05 0.05] |
||||
|
||||
[tick-chan-pos tick-chan-collsion] (h/dup-chan (h/diff-chan frame-chan1)) |
||||
|
||||
pos-chan (chan) |
||||
[pos-chan-pos pos-chan-render pos-chan-collision] (h/multiplex pos-chan 3) |
||||
|
||||
vel-chan (chan) |
||||
[vel-chan-pos vel-chan-collision] (h/dup-chan vel-chan)] |
||||
(positioner tick-chan-pos vel-chan-pos pos-chan-pos pos-chan) |
||||
(collision-detector width height tick-chan-collsion pos-chan-collision vel-chan-collision vel-chan) |
||||
|
||||
(go (>! pos-chan init-pos)) |
||||
(go (>! vel-chan init-vel)) |
||||
|
||||
(go-loop |
||||
(let [[x y] (map int (<! pos-chan-render))] |
||||
(dom/set-text! (dom/by-id "fps") (<! fps-chan)) |
||||
(dom/set-text! (dom/by-id "pos") [x y]) |
||||
(dom/set-style! (dom/by-id "ball") "left" (str (+ 50 x) "px")) |
||||
(dom/set-style! (dom/by-id "ball") "top" (str (+ 50 y) "px")))))) |
||||
|
@ -0,0 +1,180 @@ |
||||
(ns frpong.helpers |
||||
(:require [cljs.core.async :as async |
||||
:refer [<! >! chan put! close! sliding-buffer dropping-buffer timeout]] |
||||
[domina :as dom :refer [log]] |
||||
[domina.events :as ev]) |
||||
(:require-macros [cljs.core.async.macros :as m :refer [go]] |
||||
[frpong.core :refer (go-loop)])) |
||||
|
||||
(defn now [] |
||||
(.valueOf (js/Date.))) |
||||
|
||||
(defn put-all! [cs x] |
||||
(doseq [c cs] |
||||
(put! c x))) |
||||
|
||||
(defn cconj [v c1] |
||||
(let [c2 (chan)] |
||||
(go |
||||
(>! c2 v) |
||||
(while true |
||||
(>! c2 (<! c1)))) |
||||
c2)) |
||||
|
||||
(defn multiplex [in cs-or-n] |
||||
(let [cs (if (number? cs-or-n) |
||||
(repeatedly cs-or-n chan) |
||||
cs-or-n)] |
||||
(go (loop [] |
||||
(let [x (<! in)] |
||||
(if-not (nil? x) |
||||
(do |
||||
(put-all! cs x) |
||||
(recur)) |
||||
:done)))) |
||||
cs)) |
||||
|
||||
(defn copy-chan |
||||
([c] |
||||
(first (multiplex c 1))) |
||||
([out c] |
||||
(first (multiplex c [out])))) |
||||
|
||||
(defn dup-chan [c] |
||||
(multiplex c 2)) |
||||
|
||||
(defn map-chan |
||||
([f source] (map-chan (chan) f source)) |
||||
([c f source] |
||||
(go-loop |
||||
(>! c (f (<! source)))) |
||||
c)) |
||||
|
||||
(defn filter-chan |
||||
([f source] (filter-chan (chan) f source)) |
||||
([c f source] |
||||
(go-loop |
||||
(let [v (<! source)] |
||||
(when (f v) |
||||
(>! c v)))) |
||||
c)) |
||||
|
||||
(defn interval-chan |
||||
([msecs] |
||||
(interval-chan msecs :leading)) |
||||
([msecs type] |
||||
(interval-chan (chan (dropping-buffer 1)) msecs type)) |
||||
([c msecs type] |
||||
(condp = type |
||||
:leading (go-loop |
||||
(>! c (now)) |
||||
(<! (timeout msecs))) |
||||
:falling (go-loop |
||||
(<! (timeout msecs)) |
||||
(>! c (now)))) |
||||
c)) |
||||
|
||||
(defn throttle |
||||
([source control] |
||||
(throttle (chan) source control)) |
||||
([c source control] |
||||
(go |
||||
(loop [state ::init last nil cs [source]] |
||||
(let [[_ sync] cs] |
||||
(let [[v sc] (alts! cs)] |
||||
(condp = sc |
||||
source (condp = state |
||||
::init (do (>! c v) |
||||
(recur ::throttling last |
||||
(conj cs control))) |
||||
::throttling (recur state v cs)) |
||||
sync (if last |
||||
(do (>! c last) |
||||
(recur state nil |
||||
(conj (pop cs) control))) |
||||
(recur ::init last (pop cs)))))))) |
||||
c)) |
||||
|
||||
(defn debounce |
||||
([source msecs] |
||||
(debounce (chan) source msecs)) |
||||
([c source msecs] |
||||
(go |
||||
(loop [state ::init cs [source]] |
||||
(let [[_ threshold] cs] |
||||
(let [[v sc] (alts! cs)] |
||||
(condp = sc |
||||
source (condp = state |
||||
::init |
||||
(do (>! c v) |
||||
(recur ::debouncing |
||||
(conj cs (timeout msecs)))) |
||||
::debouncing |
||||
(recur state |
||||
(conj (pop cs) (timeout msecs)))) |
||||
threshold (recur ::init (pop cs))))))) |
||||
c)) |
||||
|
||||
(defn after-last |
||||
([source msecs] |
||||
(after-last (chan) source msecs)) |
||||
([c source msecs] |
||||
(go |
||||
(loop [cs [source]] |
||||
(let [[_ toc] cs] |
||||
(let [[v sc] (alts! cs :priority true)] |
||||
(recur |
||||
(condp = sc |
||||
source (conj (if toc (pop cs) cs) |
||||
(timeout msecs)) |
||||
toc (do (>! c (now)) (pop cs)))))))) |
||||
c)) |
||||
|
||||
(defn fan-in |
||||
([ins] (fan-in (chan) ins)) |
||||
([c ins] |
||||
(go (while true |
||||
(let [[x] (alts! ins)] |
||||
(>! c x)))) |
||||
c)) |
||||
|
||||
(defn distinct-chan |
||||
([source] (distinct-chan (chan) source)) |
||||
([c source] |
||||
(go |
||||
(loop [last ::init] |
||||
(let [v (<! source)] |
||||
(when-not (= last v) |
||||
(>! c v)) |
||||
(recur v)))) |
||||
c)) |
||||
|
||||
(defn event-chan [event-type] |
||||
(let [c (chan)] |
||||
(ev/listen! js/document event-type #(put! c %)) |
||||
c)) |
||||
|
||||
(defn frame-chan [] |
||||
(let [c (chan (sliding-buffer 1000)) |
||||
step (fn step [ts] (do (put! c ts) (.requestAnimationFrame js/window step)))] |
||||
(.requestAnimationFrame js/window step) |
||||
c)) |
||||
|
||||
(defn counting-chan [source] |
||||
(let [c (chan)] |
||||
(go |
||||
(loop [count 0] |
||||
(<! source) |
||||
(>! c count) |
||||
(recur (inc count)))) |
||||
c)) |
||||
|
||||
(defn diff-chan [source] |
||||
(let [c (chan)] |
||||
(go |
||||
(let [start (<! source)] |
||||
(loop [start start] |
||||
(let [ts (<! source)] |
||||
(>! c (- ts start)) |
||||
(recur ts))))) |
||||
c)) |
Loading…
Reference in new issue