-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.cljs
140 lines (120 loc) · 3.94 KB
/
main.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
(ns cljs-boids.main)
(def FPS 30)
(def SCREEN_SIZE 500)
(def NUM_BOIDS 500)
(def BOID_SIZE 5)
(def MAX_SPEED 7)
(def canvas (.getElementById js/document "world"))
(def ctx (.getContext canvas "2d"))
(def boids (array))
(defn make-boids []
(loop [i 0]
(when (< i NUM_BOIDS)
(aset boids i (js-obj "x" (* (js/Math.random) SCREEN_SIZE)
"y" (* (js/Math.random) SCREEN_SIZE)
"vx" 0
"vy" 0))
(recur (inc i)))))
(defn get-distance [b1 b2]
(let [x (- (aget b1 "x") (aget b2 "x"))
y (- (aget b1 "y") (aget b2 "y"))]
(Math/sqrt (+ (* x x) (* y y)))))
(defn += [boid property value]
(aset boid property
(+ (aget boid property) value)))
(defn -= [boid property value]
(aset boid property
(- (aget boid property) value)))
(defn *= [boid property value]
(aset boid property
(* (aget boid property) value)))
(defn x-boid [index] (aget boids index "x"))
(defn y-boid [index] (aget boids index "y"))
(defn vx-boid [index] (aget boids index "vx"))
(defn vy-boid [index] (aget boids index "vy"))
(defn rule1 [index]
(let [num-boids (.-length boids)]
(loop [x 0 y 0 i 0]
(if (< i num-boids)
(recur (+ x (x-boid i)) (+ y (y-boid i)) (inc i))
(let [cx (/ (- x (x-boid index)) (- num-boids 1))
cy (/ (- y (y-boid index)) (- num-boids 1))
b (aget boids index)]
(+= b "vx" (/ (- cx (aget b "x")) 100))
(+= b "vy" (/ (- cy (aget b "y")) 100)))))))
(defn rule2 [index]
(let [num-boids (.-length boids)]
(loop [i 0]
(if (< i num-boids)
(if (== i index) (recur (inc i))
(let [b (aget boids index)
d (get-distance (aget boids i) b)]
(when (< d 5)
(-= b "vx" (- (x-boid i) (aget b "x")))
(-= b "vy" (- (y-boid i) (aget b "y"))))
(recur (inc i))))))))
(defn rule3 [index]
(let [num-boids (.-length boids)]
(loop [vx 0 vy 0 i 0]
(if (< i num-boids)
(recur (+ vx (vx-boid i)) (+ vy (vy-boid i)) (inc i))
(let [cvx (/ (- vx (vx-boid index)) (- num-boids 1))
cvy (/ (- vy (vy-boid index)) (- num-boids 1))
b (aget boids index)]
(+= b "vx" (/ (- cvx (aget b "vx")) 8))
(+= b "vy" (/ (- cvy (aget b "vy")) 8)))))))
(defn restrict [index]
(let [b (aget boids index)
speed (Math/sqrt (+ (* (aget b "vx") (aget b "vx"))
(* (aget b "vy") (aget b "vy"))))]
(if (>= speed MAX_SPEED)
(let [r (/ MAX_SPEED speed)]
(*= b "vx" r)
(*= b "vy" r)))
(if (or (and (< (aget b "x") 0) (< (aget b "vx") 0))
(and (> (aget b "x") SCREEN_SIZE) (> (aget b "vx") 0)))
(*= b "vx" -1))
(if (or (and (< (aget b "y") 0) (< (aget b "vy") 0))
(and (> (aget b "y") SCREEN_SIZE) (> (aget b "vy") 0)))
(*= b "vy" -1))))
(defn draw []
(.clearRect ctx 0 0 SCREEN_SIZE SCREEN_SIZE)
(loop [i 0]
(when (< i (.-length boids))
(.fillRect ctx
(- (x-boid i) (/ BOID_SIZE 2))
(- (y-boid i) (/ BOID_SIZE 2))
BOID_SIZE
BOID_SIZE)
(recur (inc i)))))
(defn move []
(loop [i 0]
(when (< i (.-length boids))
(rule1 i)
(rule2 i)
(rule3 i)
(restrict i)
(let [b (aget boids i)]
(+= b "x" (aget b "vx"))
(+= b "y" (aget b "vy")))
(recur (inc i)))))
(defn simulate []
(draw)
(move))
(defn calc-time [func name]
(.time js/console name)
(loop [i 0]
(when (< i NUM_BOIDS)
(func i)
(recur (inc i))))
(.timeEnd js/console name))
(defn init []
(set! (.-width canvas) SCREEN_SIZE)
(set! (.-height canvas) SCREEN_SIZE)
(set! (.-fillStyle ctx) "rgba(33, 33, 33, 0.8)")
(make-boids)
(calc-time rule1 "rule1")
(calc-time rule2 "rule2")
(calc-time rule3 "rule3")
(calc-time restrict "restrict"))
(set! (.-onload js/window) init)