-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBoids.py
More file actions
163 lines (145 loc) · 5.81 KB
/
Boids.py
File metadata and controls
163 lines (145 loc) · 5.81 KB
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
161
162
163
import arcade
#from math import atan, sin, cos, sqrt
from math import sqrt
from Mouse import Mouse
from ViewWindow import ViewWindow
class Boid():
def __init__(self,
flock_count: int,
pos_x: float,
pos_y: float,
x_vel: int,
y_vel: int,
colour: list,
boid_width: int,
boid_height: int,
range_min: int,
range_fov: int,
speed_max: int,
view_window: ViewWindow) -> None:
"""
Boid constructor
:param flock_count: number of boids in flock
:param pos_x: x position of boid
:param pos_y: y position of boid
:param x_vel: x velocity of boid
:param y_vel: y velocity of boid
:param colour: colour of boid
:param boid_width: width of boid
:param boid_height: height of boid
:param range_min: minimum range of boid
:param range_fov: minimum range of boid
:param speed_max: maximum speed of boid
:param view_window: view window dataclass
"""
self.debug: bool = False
# Set initial boid properties
self.x: float = pos_x
self.y: float = pos_y
self.vel_x: float = x_vel
self.vel_y: float = y_vel
self.colour: list = colour
self.theta: float = 0
self.width: int = boid_width
self.height: int = boid_height
self.range_min: int = range_min
self.range_fov: int = range_fov
self.speed_min: int = 1
self.speed_max: int = speed_max
self.flock_count: int = flock_count
# Define window parameters
self.window_height: int = view_window.height
self.window_width: int = view_window.width
self.buffer: int = view_window.buffer
self.buffer_turn: int = int(view_window.buffer / 2)
self.mouse: Mouse = Mouse()
# def move(self, boids_x: list, boids_y: list, boids_vel_x: list, boids_vel_y: list) -> None:
def move(self, boid_flock: list, mouse: Mouse) -> None:
"""
Move the boid
"""
self.mouse = mouse
seperation_dx: float = 0
separation_dy: float = 0
alignment_xvel: float = 0
alignment_yvel: float = 0
cohesion_xavg: float = 0
cohesion_yavg: float = 0
neighbour_count: int = 0
mouse_velx: float = 0
mouse_vely: float = 0
# Get the flock position and velocity data
for boid in boid_flock:
boid_range = sqrt((self.x - abs(boid.x)) ** 2 + (self.y - abs(boid.y)) ** 2)
# Separation when too close
if boid_range <= self.range_min:
seperation_dx += self.x - boid.x
separation_dy += self.y - boid.y
# Alignment and Cohesion when in range
if boid_range <= self.range_fov:
alignment_xvel += boid.vel_x
alignment_yvel += boid.vel_y
cohesion_xavg += boid.x
cohesion_yavg += boid.y
neighbour_count += 1
seperation_factor = 0.1
alignment_factor = 0.05
cohesion_factor = 0.01
mouse_factor = 0.005
seperation_x = seperation_dx * seperation_factor
seperation_y = separation_dy * seperation_factor
alignment_x = ((alignment_xvel / neighbour_count) - self.vel_x) * alignment_factor
alignment_y = ((alignment_yvel / neighbour_count) - self.vel_y) * alignment_factor
cohesion_x = ((cohesion_xavg / neighbour_count) - self.x) * cohesion_factor
cohesion_y = ((cohesion_yavg / neighbour_count) - self.y) * cohesion_factor
if self.mouse.active:
dx = self.mouse.x - self.x
dy = self.mouse.y - self.y
distance = sqrt(dx ** 2 + dy ** 2)
if self.mouse.chase:
mouse_velx = dx * mouse_factor
mouse_vely = dy * mouse_factor
else:
mouse_velx = (-dx / distance) * mouse_factor * 10
mouse_vely = (-dy / distance) * mouse_factor * 10
# Update velocity with boid properties
self.vel_x += seperation_x + alignment_x + cohesion_x + mouse_velx
self.vel_y += seperation_y + alignment_y + cohesion_y + mouse_vely
# Set speed limits
self.speed_limit()
# Avoid the wall
self.avoid_wall()
# Update position with new velocity
self.update_position()
def speed_limit(self):
speed = sqrt(self.vel_x * self.vel_x + self.vel_y * self.vel_y)
if speed == 0:
self.vel_x = self.speed_min
self.vel_y = self.speed_min
elif speed > self.speed_max:
self.vel_x = (self.vel_x / speed) * self.speed_max
self.vel_y = (self.vel_y / speed) * self.speed_max
elif speed < self.speed_min:
self.vel_x = (self.vel_x / speed) * self.speed_min
self.vel_y = (self.vel_y / speed) * self.speed_min
def avoid_wall(self):
if self.x < (0 + self.buffer):
self.vel_x = self.vel_x + self.buffer_turn
if self.x > (self.window_width - self.buffer):
self.vel_x = self.vel_x - self.buffer_turn
if self.y < (0 + self.buffer):
self.vel_y = self.vel_y + self.buffer_turn
if self.y > (self.window_height - self.buffer):
self.vel_y = self.vel_y - self.buffer_turn
def update_position(self):
self.x += self.vel_x
self.y += self.vel_y
def debug_vals(self) -> None:
print(f"Boid x: {self.x} y: {self.y} x_vel:{self.vel_x} y_vel:{self.vel_y}")
"""
def generate_theta(self) -> None:
if self.vel_x == 0:
self.theta = atan(self.vel_y)
else:
self.theta = atan(self.vel_y / self.vel_x)
"""