Advertisement
Guest User

Untitled

a guest
Mar 20th, 2018
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.82 KB | None | 0 0
  1. import pygame, math
  2. from precode2 import Vector2D, intersect_circles
  3. from random import randrange
  4. from config import *
  5.  
  6. class LonelyBoid(Exception):
  7. """my own exception"""
  8. pass
  9.  
  10. class GameObject():
  11. def __init__(self, pos_vec, speed, color, radius):
  12. self.pos_vec = pos_vec
  13. self.speed = speed
  14. self.color = color
  15. self.radius = radius
  16.  
  17. class Boids(GameObject):
  18. def __init__(self, pos_vec, speed, color, radius):
  19. GameObject.__init__(self, pos_vec, speed, color, radius)
  20.  
  21. def find_neighbour(self, boidlist, limit):
  22. """
  23. takes a list of objects as argument
  24. checks if the object is close enough to the "self"-boid be added to a list for all the close objects.
  25. returns this list.
  26. """
  27. in_area = []
  28.  
  29. try:
  30. for i in boidlist:
  31. if i is not self:
  32. if i.pos_vec.x - self.pos_vec.x > -limit and i.pos_vec.x -self.pos_vec.x < limit:
  33. if i.pos_vec.y - self.pos_vec.y > -limit and i.pos_vec.y -self.pos_vec.y < limit:
  34. in_area.append(i)
  35.  
  36. except:
  37. raise LonelyBoid("No more boids in list")
  38.  
  39. return in_area
  40.  
  41. #separates the boids
  42. def separate_boid(self, boidlist, magnitude):
  43. in_area = self.find_neighbour(boidlist, 30)
  44.  
  45. sum_x = 0
  46. sum_y = 0
  47.  
  48. if len(in_area)>0:
  49. for i in in_area:
  50. sum_x = self.pos_vec.x - i.pos_vec.x
  51. sum_y = self.pos_vec.y - i.pos_vec.y
  52.  
  53. try:
  54. normalize = -math.sqrt((sum_x*sum_x)+(sum_y*sum_y))
  55.  
  56. self.speed.x -= (sum_x/normalize) * MAX_SPEED / magnitude
  57. self.speed.y -= (sum_y/normalize) * MAX_SPEED / magnitude
  58. except:
  59. ZeroDivisionError
  60.  
  61. #aligns the average vector of the boids in an area
  62. def align_boid(self, boidlist, magnitude):
  63. in_area = self.find_neighbour(boidlist, 70)
  64.  
  65. sum_x = 0
  66. sum_y = 0
  67.  
  68. if len(in_area) >= 1:
  69. for i in in_area:
  70. sum_x += i.speed.x
  71. sum_y += i.speed.y
  72.  
  73. try:
  74. sum_x /= len(in_area)
  75. sum_y /= len(in_area)
  76.  
  77. normalize = math.sqrt((sum_x*sum_x)+(sum_y*sum_y))
  78.  
  79. normx = sum_x/normalize * MAX_SPEED
  80. normy = sum_y/normalize * MAX_SPEED
  81.  
  82. self.speed.x += normx / magnitude
  83. self.speed.y += normy / magnitude
  84.  
  85. except:
  86. ZeroDivisionError
  87.  
  88. #finds the center spot of a cluster of boids and tries to get the boids to flock to it
  89. def cohesion(self, boidlist, magnitude):
  90. in_area = self.find_neighbour(boidlist, 50)
  91.  
  92. sum_x = 0
  93. sum_y = 0
  94.  
  95. if len(in_area) >= 1:
  96. for i in in_area:
  97. if i.pos_vec.x == self.pos_vec.x and i.pos_vec.y == self.pos_vec.y:
  98. continue
  99. sum_x += self.pos_vec.x - i.pos_vec.x
  100. sum_y += self.pos_vec.y - i.pos_vec.y
  101.  
  102. try:
  103. sum_x /= len(in_area)
  104. sum_y /= len(in_area)
  105.  
  106. normalize = math.sqrt((sum_x*sum_x)+(sum_y*sum_y))
  107.  
  108. normx = sum_x/normalize * MAX_SPEED
  109. normy = sum_y/normalize * MAX_SPEED
  110.  
  111. self.speed.x -= normx / magnitude
  112. self.speed.y -= normy / magnitude
  113.  
  114. except:
  115. ZeroDivisionError
  116.  
  117. def intersect(self, obsticle, turnspeed):
  118. """
  119. if the boid is close enough to the obsticle to be appended to the in_area list,
  120. the boids speed will be incremented, depending on where the boid is relative to the obsticle
  121. """
  122. in_area = self.find_neighbour(obsticle, 70)
  123.  
  124. for i in in_area:
  125. if i.pos_vec.x - self.pos_vec.x > 0:
  126. i.speed.x += turnspeed
  127. else:
  128. i.speed.x -= turnspeed
  129. if i.pos_vec.y - self.pos_vec.y > 0:
  130. i.speed.y += turnspeed
  131. else:
  132. i.speed.y -= turnspeed
  133.  
  134. def edges_boid(self):
  135. """
  136. if the boids or hoiks is close to the edge of the screen,
  137. the x or y speed will be incremented depending on the location,
  138. if it is over the edge it will be teleported to the other side of the screen.
  139. """
  140. if self.pos_vec.x < EDGE_LIMIT:
  141. if self.speed.x < MAX_SPEED:
  142. self.speed.x += TURN_SPEED_EDGE
  143. if self.pos_vec.x < -10:
  144. self.pos_vec.x = SCREEN_WIDTH + 10
  145.  
  146. if self.pos_vec.x > SCREEN_WIDTH - EDGE_LIMIT:
  147. if self.speed.y > MIN_SPEED:
  148. self.speed.x -= TURN_SPEED_EDGE
  149. if self.pos_vec.x > SCREEN_WIDTH +10:
  150. self.pos_vec.x = -10
  151.  
  152. if self.pos_vec.y < EDGE_LIMIT:
  153. if self.speed.y < MAX_SPEED:
  154. self.speed.y += TURN_SPEED_EDGE
  155. if self.pos_vec.y < -10:
  156. self.pos_vec.y = SCREEN_HEIGHT + 10
  157.  
  158. if self.pos_vec.y > SCREEN_HEIGHT - EDGE_LIMIT:
  159. if self.speed.y > MIN_SPEED:
  160. self.speed.y -= TURN_SPEED_EDGE
  161. if self.pos_vec.y > SCREEN_HEIGHT + 10:
  162. self.pos_vec.y = -10
  163.  
  164.  
  165. def move_boid(self):
  166. """
  167. animates the boids and hoiks.
  168. """
  169. self.pos_vec.x += self.speed.x
  170. self.pos_vec.y += self.speed.y
  171.  
  172. def check_speed(self):
  173. """
  174. checks wheter the speed of the object is over or under the max speed,
  175. if it is lower than minimum speed it gets set to minumum speed
  176. if it is higher than max speed it gets set to max speed.
  177. this is to prevent the boids and hoiks flying to fast.
  178. """
  179. if self.speed.x > MAX_SPEED:
  180. self.speed.x = MAX_SPEED
  181. if self.speed.x < MIN_SPEED:
  182. self.speed.x = MIN_SPEED
  183.  
  184. if self.speed.y > MAX_SPEED:
  185. self.speed.y = MAX_SPEED
  186. if self.speed.y < MIN_SPEED:
  187. self.speed.y = MIN_SPEED
  188.  
  189. def draw_boid(self, screen):
  190. """draws a boid on the given screen"""
  191. pygame.draw.circle(screen, self.color, (int(self.pos_vec.x), int(self.pos_vec.y)), self.radius)
  192.  
  193. #from the precode
  194. def draw_vec_from_ball(self, screen, col):
  195. pygame.draw.line(screen, col, (self.pos_vec.x, self.pos_vec.y), (self.pos_vec.x + self.speed.x * LINE_LENGTH, self.pos_vec.y + self.speed.y * LINE_LENGTH), 3)
  196.  
  197.  
  198. class Hoiks(Boids):
  199. """
  200. inherites the class of boids, makes it possible to use polimorphism
  201. """
  202. def __init__(self, pos_vec, speed, color, radius):
  203. GameObject.__init__(self, pos_vec, speed, color, radius)
  204.  
  205. def seek_boid(self, boidlist, magnitude):
  206. """
  207. makes the hoik seek the closest boid. finds the vector of the closest boid,
  208. normalises it, and adds a normalised "target" vector devided by a given magnitude
  209. to the speed of the hoik
  210. """
  211. nearest = None
  212. shortest = None
  213.  
  214.  
  215. for i in boidlist:
  216. sum_x = self.pos_vec.x - i.pos_vec.x
  217. sum_y = self.pos_vec.y - i.pos_vec.y
  218. #the next 4 lines of code is borrowed from stack overflow from a similar problem.
  219. distance = (sum_x*sum_x+sum_y*sum_y)
  220.  
  221. if not shortest or distance < shortest:
  222. shortest = distance
  223. nearest = i
  224.  
  225. try:
  226. vectorx = nearest.pos_vec.x - self.pos_vec.x
  227. vectory = nearest.pos_vec.y - self.pos_vec.y
  228.  
  229. norm = math.sqrt((vectorx*vectorx)+(vectory*vectory))
  230.  
  231. self.speed.x += (vectorx/norm) * MAX_SPEED / magnitude
  232. self.speed.y += (vectory/norm) * MAX_SPEED / magnitude
  233. except:
  234. ZeroDivisionError
  235.  
  236. class Game():
  237. def __init__(self):
  238. """setup of the game class."""
  239. pygame.init()
  240. self.screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
  241. self.clock = pygame.time.Clock()
  242. pygame.display.set_caption("boids")
  243. self.done = False
  244.  
  245. self.boid_list = []
  246. self.hoik_list = []
  247. self.obsticle_list = []
  248. self.all_things_to_draw = []
  249.  
  250. #creating instances of boids
  251. for i in range(BOID_COUNT):
  252. self.boid = Boids(Vector2D(randrange(0,SCREEN_WIDTH), randrange(0,SCREEN_HEIGHT)), Vector2D(randrange(MIN_SPEED,MAX_SPEED),randrange(MIN_SPEED,MAX_SPEED)), BLACK, BOID_RADIUS)
  253. self.boid_list.append(self.boid)
  254.  
  255. #creating instances of hoiks
  256. for i in range (HOIK_COUNT):
  257. self.hoik = Hoiks(Vector2D(randrange(0,SCREEN_WIDTH), randrange(0,SCREEN_HEIGHT)), Vector2D(randrange(MIN_SPEED,MAX_SPEED),randrange(MIN_SPEED,MAX_SPEED)), RED, BOID_RADIUS)
  258. self.hoik_list.append(self.hoik)
  259.  
  260. #appending boidslist and hoikslist to a list of both list, allowing us to easily draw both lists
  261. self.all_things_to_draw.append(self.boid_list)
  262. self.all_things_to_draw.append(self.hoik_list)
  263.  
  264. def handle_events(self):
  265. """handles the quit event, and creates a new obsticle if u click the mouse."""
  266. events = pygame.event.get()
  267. for event in events:
  268. #event for quiting
  269. if event.type == pygame.QUIT:
  270. self.done = True
  271. #event for creating a new obsticle when clicking the mousebutton
  272. if event.type == pygame.MOUSEBUTTONDOWN:
  273. coordinate = pygame.mouse.get_pos()
  274. self.obsticle = Boids(Vector2D(coordinate[0], coordinate[1] ), Vector2D(0,0), RED, OBSTICLE_RADIUS)
  275. self.obsticle_list.append(self.obsticle)
  276.  
  277. def run(self):
  278. while not self.done:
  279. self.handle_events()
  280. self.time_passed = self.clock.tick(30)
  281. self.screen.fill((GREY))
  282.  
  283. #apply the 3 rules for the boid
  284. for i in self.boid_list:
  285. i.cohesion(self.boid_list, 1.7)
  286. i.separate_boid(self.boid_list, 1)
  287. i.align_boid(self.boid_list, 1.5)
  288.  
  289. #check for collision with the hoiks
  290. for u in self.hoik_list:
  291. if abs(i.pos_vec.x - u.pos_vec.x) < i.radius and abs(i.pos_vec.y - u.pos_vec.y) < i.radius:
  292. self.boid_list.remove(i)
  293.  
  294. #make the hoiks steer towards closest boid, make the boids run away from hoiks,
  295. #make sure hoiks dont colide and draw a vector from the hoiks to see who they are chasing
  296. for i in self.hoik_list:
  297. i.seek_boid(self.boid_list, SEEK_BOID_LIMIT)
  298. i.intersect(self.boid_list, TURN_SPEED_HOIKS)
  299. i.separate_boid(self.hoik_list, SEPARATE_HOIK_LIMIT)
  300.  
  301. #make the boids and hoiks steer away from obstacles.
  302. for i in self.obsticle_list:
  303. i.intersect(self.boid_list, TURN_SPEED_OBSTICLES)
  304. i.intersect(self.hoik_list, TURN_SPEED_OBSTICLES)
  305.  
  306. #using polimorphism to check the speed of the boids, and make sure they are not over the boundaries
  307. #Using polimorphism to move both hoiks and boids, and then drawing them.
  308. for i in self.all_things_to_draw:
  309. for u in i:
  310. u.check_speed()
  311. u.edges_boid()
  312. u.move_boid()
  313. u.draw_boid(self.screen)
  314. u.draw_vec_from_ball(self.screen, BLACK)
  315.  
  316. #drawing obsticles
  317. for i in self.obsticle_list:
  318. i.draw_boid(self.screen)
  319.  
  320. pygame.display.flip()
  321.  
  322. if __name__ == '__main__':
  323. my_game = Game()
  324. my_game.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement