-
Notifications
You must be signed in to change notification settings - Fork 0
/
pilot.py
129 lines (104 loc) · 4.3 KB
/
pilot.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# This module will represent the pilot controlling an enemy ship using a
# modified implementation of Craig Reynold's flocking algorithim
import math
from vector2d import Vector2D
class Pilot():
def __init__(self):
self.max_acceleration = 0.1
self.sightRange = 150
# TODO: Scales request by 1/d
def calc_avoid(self, boids, position):
"""Returns the avoid accerlation"""
avoidAccel = Vector2D(0, 0)
range = 40
weight = 1/15
# Add up all the separation vectors
for boid in boids:
if math.dist(position, boid.rect.center) < range:
xdiff = position[0]-boid.rect.center[0]
ydiff = position[1]-boid.rect.center[1]
diff = Vector2D(xdiff, ydiff)
diff.scale(1/(diff.calc_magnitude()))
avoidAccel.add(diff)
avoidAccel.scale(weight)
return avoidAccel
#
def calc_align(self, boids, velocity):
"""Returns the acceleration vector to align velocity direction with the
average velocity direction of nearby boids."""
velocities = Vector2D(0, 0)
weight = 1/36
# No change if there are no other boids around.
if not(len(boids)):
return Vector2D(0, 0)
# Accumulates velocities
for boid in boids:
velocities.add_values(boid.velocity.x, boid.velocity.y)
# Averages velocities
if len(boids) > 1:
velocities.scale(1/(len(boids)-1))
xdiff = velocities.x - velocity.x
ydiff = velocities.y - velocity.y
alignAccel = Vector2D(xdiff, ydiff)
alignAccel.scale(weight)
return alignAccel
def calc_approach(self, boids, position):
"""Returns the approach accerlation"""
approachAccel = Vector2D(0, 0)
weight = 1/100
# Add up all the separation vectors
for boid in boids:
xdiff = boid.rect.center[0]-position[0]
ydiff = boid.rect.center[1]-position[1]
approachAccel.add_values(xdiff, ydiff)
# Makes accleration based on average position
if len(boids) > 0:
approachAccel.scale(1/len(boids))
approachAccel.scale(weight)
return approachAccel
def calc_player(self, position, playerPos):
# Ignore (-1, -1) for menu animations
if(playerPos == (-1, -1)):
return(Vector2D(0, 0))
weight = 1/100
"""Returns the acceleration towards the player."""
xdiff = playerPos[0]-position[0]
ydiff = playerPos[1]-position[1]
playerAccel = Vector2D(xdiff, ydiff)
playerAccel.scale(weight)
return playerAccel
def get_acceleration(self, position, velocity, boids, playerPos):
"""Returns a single acceleration vector in response to nearby boids."""
# Find the neighboring boids
neighbors = self.find_neighbors(boids, position, self.sightRange)
# Acceleration acccumulator
# Add acceleration requests in order of importance
accelRequests = [
self.calc_avoid(neighbors, position),
self.calc_player(position, playerPos),
self.calc_align(neighbors, velocity),
self.calc_approach(neighbors, position)]
# Add up requests untill max acceleration is reached
acceptedRequests = Vector2D(0, 0)
for request in accelRequests:
# Add if room
if acceptedRequests.calc_magnitude() < self.max_acceleration:
acceptedRequests.add(request)
# Trim tail if over
if acceptedRequests.calc_magnitude() > self.max_acceleration:
tail = acceptedRequests.calc_magnitude()-self.max_acceleration
request.normalize()
request.scale(-tail)
acceptedRequests.add(request)
return acceptedRequests
def find_neighbors(self, boids, position, distance):
"""Finds all the boids in a given list within the given distance of the
indicated position."""
# List to hold nearby boids
nearbyBoids = []
# Keep boids within distance
for boid in boids:
d = math.dist(position, boid.rect.center)
if((d < distance) and (d > 0)):
nearbyBoids.append(boid)
return nearbyBoids