Browse Source

Got positioner and collision-detector working

Abhinav Sarkar 9 years ago
parent
commit
00c46a5ee7
5 changed files with 243 additions and 19 deletions
  1. 1
    1
      project.clj
  2. 3
    0
      resources/public/index.html
  3. 4
    4
      src/clj/frpong/core.clj
  4. 55
    14
      src/cljs/frpong/core.cljs
  5. 180
    0
      src/cljs/frpong/helpers.cljs

+ 1
- 1
project.clj View File

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

+ 3
- 0
resources/public/index.html View File

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

+ 4
- 4
src/clj/frpong/core.clj View File

@@ -1,6 +1,6 @@
1 1
 (ns frpong.core)
2 2
 
3
-(defn foo
4
-  "I don't do a whole lot."
5
-  [x]
6
-  (println x "Hello, World!"))
3
+(defmacro go-loop [& body]
4
+  `(cljs.core.async.macros/go
5
+     (while true
6
+       ~@body)))

+ 55
- 14
src/cljs/frpong/core.cljs View File

@@ -1,20 +1,61 @@
1 1
 (ns frpong.core
2
-  (:require [cljs.core.async :as async
3
-             :refer [<! >! chan put!]]
4
-            [domina :as dom]
2
+  (:require [frpong.helpers :as h]
3
+            [cljs.core.async :as async
4
+             :refer [<! >! chan put! close! sliding-buffer dropping-buffer timeout]]
5
+            [domina :as dom :refer [log]]
5 6
             [domina.events :as ev])
6
-  (:require-macros [cljs.core.async.macros :as m :refer [go]]))
7
+  (:require-macros [cljs.core.async.macros :as m :refer [go]]
8
+                   [frpong.core :refer (go-loop)]))
7 9
 
10
+(defn positioner [tick-chan vel-chan pos-chan-in pos-chan-out]
11
+  (go-loop
12
+    (let [tick (<! tick-chan)
13
+          [vel-x vel-y] (<! vel-chan)
14
+          [x y] (<! pos-chan-in)
15
+          pos-next [(+ x (* vel-x tick)) (+ y (* vel-y tick))]]
16
+      (>! pos-chan-out pos-next))))
8 17
 
9
-(defn event-chan [event-type]
10
-  (let [c (chan)]
11
-    (ev/listen! js/document event-type
12
-      (fn [e] (put! c e)))
13
-    c))
18
+(defn collision-detector [width height tick-chan pos-chan vel-chan-in vel-chan-out]
19
+  (go-loop
20
+    (let [tick (<! tick-chan)
21
+          [vel-x vel-y] (<! vel-chan-in)
22
+          [x y] (<! pos-chan)
23
+          [xn yn] [(+ x (* vel-x tick)) (+ y (* vel-y tick))]]
24
+      (>! vel-chan-out
25
+        (cond
26
+          (< xn 0) [(- vel-x) vel-y]
27
+          (< yn 0) [vel-x (- vel-y)]
28
+          (> xn width) [(- vel-x) vel-y]
29
+          (> yn height) [vel-x (- vel-y)]
30
+          :else [vel-x vel-y])))))
14 31
 
15 32
 (defn ^:export init []
16
-  (let [mm-chan (event-chan :mousemove)]
17
-    (go
18
-      (while true
19
-        (let [e (<! mm-chan)]
20
-          (.log js/console (str (:clientX e) " , " (:clientY e))))))))
33
+  (let [frame-chan (h/frame-chan)
34
+        [frame-chan1 frame-chan2] (h/dup-chan frame-chan)
35
+        
36
+        fps-chan (h/map-chan #(/ 1000 %) (h/diff-chan frame-chan2))
37
+        
38
+        width 100
39
+        height 100
40
+        init-pos [0 50]
41
+        init-vel [0.05 0.05]
42
+        
43
+        [tick-chan-pos tick-chan-collsion] (h/dup-chan (h/diff-chan frame-chan1))
44
+        
45
+        pos-chan (chan)
46
+        [pos-chan-pos pos-chan-render pos-chan-collision] (h/multiplex pos-chan 3)
47
+
48
+        vel-chan (chan)
49
+        [vel-chan-pos vel-chan-collision] (h/dup-chan vel-chan)]
50
+    (positioner tick-chan-pos vel-chan-pos pos-chan-pos pos-chan)
51
+    (collision-detector width height tick-chan-collsion pos-chan-collision vel-chan-collision vel-chan)
52
+    
53
+    (go (>! pos-chan init-pos))
54
+    (go (>! vel-chan init-vel))
55
+    
56
+    (go-loop
57
+      (let [[x y] (map int (<! pos-chan-render))]
58
+        (dom/set-text! (dom/by-id "fps") (<! fps-chan))
59
+        (dom/set-text! (dom/by-id "pos") [x y])
60
+        (dom/set-style! (dom/by-id "ball") "left" (str (+ 50 x) "px"))
61
+        (dom/set-style! (dom/by-id "ball") "top" (str (+ 50 y) "px"))))))

+ 180
- 0
src/cljs/frpong/helpers.cljs View File

@@ -0,0 +1,180 @@
1
+(ns frpong.helpers
2
+  (:require [cljs.core.async :as async
3
+             :refer [<! >! chan put! close! sliding-buffer dropping-buffer timeout]]
4
+            [domina :as dom :refer [log]]
5
+            [domina.events :as ev])
6
+  (:require-macros [cljs.core.async.macros :as m :refer [go]]
7
+                   [frpong.core :refer (go-loop)]))
8
+
9
+(defn now []
10
+  (.valueOf (js/Date.)))
11
+
12
+(defn put-all! [cs x]
13
+  (doseq [c cs]
14
+    (put! c x)))
15
+
16
+(defn cconj [v c1]
17
+  (let [c2 (chan)]
18
+    (go
19
+      (>! c2 v)
20
+      (while true
21
+        (>! c2 (<! c1))))
22
+    c2))
23
+
24
+(defn multiplex [in cs-or-n]
25
+  (let [cs (if (number? cs-or-n)
26
+             (repeatedly cs-or-n chan)
27
+             cs-or-n)]
28
+    (go (loop []
29
+          (let [x (<! in)]
30
+            (if-not (nil? x)
31
+              (do
32
+                (put-all! cs x)
33
+                (recur))
34
+              :done))))
35
+    cs))
36
+
37
+(defn copy-chan
38
+  ([c]
39
+    (first (multiplex c 1)))
40
+  ([out c]
41
+    (first (multiplex c [out]))))
42
+
43
+(defn dup-chan [c]
44
+  (multiplex c 2))
45
+
46
+(defn map-chan
47
+  ([f source] (map-chan (chan) f source))
48
+  ([c f source]
49
+    (go-loop
50
+      (>! c (f (<! source))))
51
+    c))
52
+
53
+(defn filter-chan
54
+  ([f source] (filter-chan (chan) f source))
55
+  ([c f source]
56
+    (go-loop
57
+      (let [v (<! source)]
58
+        (when (f v)
59
+          (>! c v))))
60
+    c))
61
+
62
+(defn interval-chan
63
+  ([msecs]
64
+    (interval-chan msecs :leading))
65
+  ([msecs type]
66
+    (interval-chan (chan (dropping-buffer 1)) msecs type))
67
+  ([c msecs type]
68
+    (condp = type
69
+      :leading (go-loop
70
+                 (>! c (now))
71
+                 (<! (timeout msecs)))
72
+      :falling (go-loop
73
+                 (<! (timeout msecs))
74
+                 (>! c (now))))
75
+    c))
76
+
77
+(defn throttle
78
+  ([source control]
79
+    (throttle (chan) source control))
80
+  ([c source control]
81
+    (go
82
+      (loop [state ::init last nil cs [source]]
83
+        (let [[_ sync] cs]
84
+          (let [[v sc] (alts! cs)]
85
+            (condp = sc
86
+              source (condp = state
87
+                       ::init (do (>! c v)
88
+                                (recur ::throttling last
89
+                                  (conj cs control)))
90
+                       ::throttling (recur state v cs))
91
+              sync (if last 
92
+                     (do (>! c last)
93
+                       (recur state nil
94
+                         (conj (pop cs) control)))
95
+                     (recur ::init last (pop cs))))))))
96
+    c))
97
+
98
+(defn debounce
99
+  ([source msecs]
100
+    (debounce (chan) source msecs))
101
+  ([c source msecs]
102
+    (go
103
+      (loop [state ::init cs [source]]
104
+        (let [[_ threshold] cs]
105
+          (let [[v sc] (alts! cs)]
106
+            (condp = sc
107
+              source (condp = state
108
+                       ::init
109
+                         (do (>! c v)
110
+                           (recur ::debouncing
111
+                             (conj cs (timeout msecs))))
112
+                       ::debouncing
113
+                         (recur state
114
+                           (conj (pop cs) (timeout msecs))))
115
+              threshold (recur ::init (pop cs)))))))
116
+    c))
117
+
118
+(defn after-last
119
+  ([source msecs]
120
+    (after-last (chan) source msecs))
121
+  ([c source msecs]
122
+    (go
123
+      (loop [cs [source]]
124
+        (let [[_ toc] cs]
125
+          (let [[v sc] (alts! cs :priority true)]
126
+            (recur
127
+              (condp = sc
128
+                source (conj (if toc (pop cs) cs)
129
+                         (timeout msecs))
130
+                toc (do (>! c (now)) (pop cs))))))))
131
+    c))
132
+
133
+(defn fan-in
134
+  ([ins] (fan-in (chan) ins))
135
+  ([c ins]
136
+    (go (while true
137
+          (let [[x] (alts! ins)]
138
+            (>! c x))))
139
+    c))
140
+
141
+(defn distinct-chan
142
+  ([source] (distinct-chan (chan) source))
143
+  ([c source]
144
+    (go
145
+      (loop [last ::init]
146
+        (let [v (<! source)]
147
+          (when-not (= last v)
148
+            (>! c v))
149
+          (recur v))))
150
+    c))
151
+
152
+(defn event-chan [event-type]
153
+  (let [c (chan)]
154
+    (ev/listen! js/document event-type #(put! c %))
155
+    c))
156
+
157
+(defn frame-chan []
158
+  (let [c (chan (sliding-buffer 1000))
159
+        step (fn step [ts]  (do (put! c ts) (.requestAnimationFrame js/window step)))]
160
+    (.requestAnimationFrame js/window step)
161
+    c))
162
+
163
+(defn counting-chan [source]
164
+  (let [c (chan)]
165
+    (go
166
+      (loop [count 0]
167
+        (<! source)
168
+        (>! c count)
169
+        (recur (inc count))))
170
+    c))
171
+
172
+(defn diff-chan [source]
173
+  (let [c (chan)]
174
+    (go
175
+      (let [start (<! source)]
176
+        (loop [start start]
177
+          (let [ts (<! source)]
178
+            (>! c (- ts start))
179
+            (recur ts)))))
180
+    c))

Loading…
Cancel
Save