Got positioner and collision-detector working

This commit is contained in:
Abhinav Sarkar 2013-09-25 15:28:33 +05:30
parent 07c53dcf2b
commit 00c46a5ee7
5 changed files with 243 additions and 19 deletions

View File

@ -7,7 +7,7 @@
:source-paths ["src/clj"]
:dependencies [[org.clojure/clojure "1.5.1"]
[domina "1.0.2-SNAPSHOT"]
[org.clojure/clojurescript "0.0-1878"]
[org.clojure/clojurescript "0.0-1844"]
[org.clojure/core.async "0.1.222.0-83d0c2-alpha"]]
:plugins [[lein-cljsbuild "0.3.3"]]

View File

@ -8,6 +8,9 @@
<![endif]-->
</head>
<body>
<div>FPS: <span id="fps"></span></div>
<div>Position: <span id="pos"></span></div>
<div style="position: absolute" id="ball">O</div>
<!-- pointing to cljsbuild generated js file -->
<script src="js/frpong.js"></script>
<script type="text/javascript">frpong.core.init()</script>

View File

@ -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)))

View File

@ -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"))))))

View File

@ -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))