-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathboids3.rkt
160 lines (126 loc) · 4.54 KB
/
boids3.rkt
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#lang racket
#| Boids - bird like objects - https://en.wikipedia.org/wiki/Boids
Version 3: Boids like each other, but don't like the mouse.
Run (go) to start.
--
Copyright 2018, Eric Clack, [email protected]
This program is distributed under the terms of the GNU General
Public License
|#
(require 2htdp/universe 2htdp/image)
(require "util.rkt")
(require "2d.rkt")
(struct world (boids mousex mousey) #:transparent)
(struct boid (pos direction speed size) #:transparent)
(define BIG-BOID 20)
(define NUM-BOIDS 10)
(define TICK-RATE 1/30)
(define WIDTH 800)
(define HEIGHT 600)
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(define (new-boid)
(boid (pos (random WIDTH) (random HEIGHT))
(random 360)
(+ 1 (random 2))
BIG-BOID))
(define (move-pos a-pos a-direction a-speed)
(define r (degrees->radians a-direction))
(pos (+ (pos-x a-pos) (* a-speed (cos r)))
(+ (pos-y a-pos) (* a-speed (sin r)))))
(define (wrap-pos a-pos a-size)
(define x (pos-x a-pos))
(define y (pos-y a-pos))
(pos (cond
[(> x (+ WIDTH a-size)) (- 0 a-size)]
[(< x (- 0 a-size)) (+ WIDTH a-size)]
[else x])
(cond
[(> y (+ HEIGHT a-size)) (- 0 a-size)]
[(< y (- 0 a-size)) (+ HEIGHT a-size)]
[else y])))
(define (move-boid a)
;; Move a boid based on its speed, direction and size
(boid (wrap-pos
(move-pos (boid-pos a) (boid-direction a) (boid-speed a))
(boid-size a))
(boid-direction a)
(boid-speed a)
(boid-size a)))
(define (boid-distance-force d)
;; What force applied for distance d
(cond
[(< d 30) 1]
[(< d 50) .1]
[(< d 100) -.1]
[(< d 200) -.05]
[else 0]))
(define (mouse-distance-force d)
;; What force applied for distance d
(cond
[(< d 50) -.5]
[(< d 100) -.1]
[else 0]))
(define (apply-force a-boid angle mag)
;; Apply force with mag at angle to a-boid
(define new-d-s (add-direction-speeds
(boid-direction a-boid) (boid-speed a-boid)
angle mag))
(boid (boid-pos a-boid)
(first new-d-s)
(min 3 (second new-d-s)) ; max speed
(boid-size a-boid)))
(define (avoid-mouse all-boids mousex mousey)
;; Adjust boid speed and direction to avoid collisions
(define (-avoid-mouse a-boid)
;; The mouse position applies a force to this boid
;; based on distance and angle between each
(define angle (angle-between (boid-pos a-boid)
(pos mousex mousey)))
(define mag (mouse-distance-force (distance-between (boid-pos a-boid)
(pos mousex mousey))))
(apply-force a-boid angle mag))
(map -avoid-mouse all-boids))
(define (avoid-collisions all-boids)
(define (-avoid-collisions a-boid)
;; Get a list of angle/mag pairs between this boid and world
(define angles-mags
(map (λ (b)
(list (angle-between (boid-pos a-boid)
(boid-pos b))
(- (boid-distance-force (distance-between
(boid-pos a-boid)
(boid-pos b))))))
(remove a-boid all-boids)))
(define (cumulative-force angle-mag a-boid)
(apply-force a-boid (first angle-mag) (second angle-mag)))
(foldl cumulative-force a-boid angles-mags))
(map -avoid-collisions all-boids))
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(define (next-world w)
(world (map move-boid
(avoid-collisions
(avoid-mouse (world-boids w)
(world-mousex w)
(world-mousey w))))
(world-mousex w) (world-mousey w)))
(define (mouse-event w x y e)
(world (world-boids w) x y))
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Rendering
(define (img+scene pos img scene)
(place-image img (pos-x pos) (pos-y pos) scene))
(define (boids+scene boids scene)
(foldl (λ (a scene)
(img+scene (boid-pos a)
(circle (boid-size a) "solid" "gray")
scene))
scene boids))
(define (render-world w)
(boids+scene (world-boids w)
(empty-scene WIDTH HEIGHT "black")))
;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(define (go)
(big-bang (world (times-repeat NUM-BOIDS (new-boid)) 0 0)
(on-tick next-world TICK-RATE)
(on-mouse mouse-event)
(to-draw render-world)))