-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathboid.py
113 lines (92 loc) · 3.7 KB
/
boid.py
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
from p5 import Vector, stroke, circle
import numpy as np
class Boid():
def __init__(self, x, y, width, height):
self.position = Vector(x, y)
vec = (np.random.rand(2) - 0.5)*10
self.velocity = Vector(*vec)
vec = (np.random.rand(2) - 0.5)/2
self.acceleration = Vector(*vec)
self.max_force = 0.3
self.max_speed = 5
self.perception = 100
self.width = width
self.height = height
def update(self):
self.position += self.velocity
self.velocity += self.acceleration
#limit
if np.linalg.norm(self.velocity) > self.max_speed:
self.velocity = self.velocity / np.linalg.norm(self.velocity) * self.max_speed
self.acceleration = Vector(*np.zeros(2))
def show(self):
stroke(255)
circle((self.position.x, self.position.y), radius=10)
def apply_behaviour(self, boids):
alignment = self.align(boids)
cohesion = self.cohesion(boids)
separation = self.separation(boids)
self.acceleration += alignment
self.acceleration += cohesion
self.acceleration += separation
def edges(self):
if self.position.x > self.width:
self.position.x = 0
elif self.position.x < 0:
self.position.x = self.width
if self.position.y > self.height:
self.position.y = 0
elif self.position.y < 0:
self.position.y = self.height
def align(self, boids):
steering = Vector(*np.zeros(2))
total = 0
avg_vector = Vector(*np.zeros(2))
for boid in boids:
if np.linalg.norm(boid.position - self.position) < self.perception:
avg_vector += boid.velocity
total += 1
if total > 0:
avg_vector /= total
avg_vector = Vector(*avg_vector)
avg_vector = (avg_vector / np.linalg.norm(avg_vector)) * self.max_speed
steering = avg_vector - self.velocity
return steering
def cohesion(self, boids):
steering = Vector(*np.zeros(2))
total = 0
center_of_mass = Vector(*np.zeros(2))
for boid in boids:
if np.linalg.norm(boid.position - self.position) < self.perception:
center_of_mass += boid.position
total += 1
if total > 0:
center_of_mass /= total
center_of_mass = Vector(*center_of_mass)
vec_to_com = center_of_mass - self.position
if np.linalg.norm(vec_to_com) > 0:
vec_to_com = (vec_to_com / np.linalg.norm(vec_to_com)) * self.max_speed
steering = vec_to_com - self.velocity
if np.linalg.norm(steering)> self.max_force:
steering = (steering /np.linalg.norm(steering)) * self.max_force
return steering
def separation(self, boids):
steering = Vector(*np.zeros(2))
total = 0
avg_vector = Vector(*np.zeros(2))
for boid in boids:
distance = np.linalg.norm(boid.position - self.position)
if self.position != boid.position and distance < self.perception:
diff = self.position - boid.position
diff /= distance
avg_vector += diff
total += 1
if total > 0:
avg_vector /= total
avg_vector = Vector(*avg_vector)
if np.linalg.norm(steering) > 0:
avg_vector = (avg_vector / np.linalg.norm(steering)) * self.max_speed
steering = avg_vector - self.velocity
if np.linalg.norm(steering) > self.max_force:
steering = (steering /np.linalg.norm(steering)) * self.max_force
return steering