Shuvit game master repo. http://shuvit.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

astar.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import bge, json, mathutils, math
  2. from timeit import default_timer as timer
  3. def chrono(function):
  4. def wrapper(*args, **kargs):
  5. before = timer()
  6. value = function(*args, **kargs)
  7. print(function.__qualname__, 'took', (timer() - before) * 100, 'to return', value)
  8. return value
  9. return wrapper
  10. def draw_all(self):
  11. for x in self.points:
  12. pm = bge.logic.getCurrentScene().addObject('path_marker')
  13. pm.worldPosition = x.loc
  14. pm.color = [1,1,0,1]
  15. pm.worldScale = [.25, .26, .25]
  16. class IterRegistry(type):
  17. def __iter__(cls):
  18. return iter(cls._registry)
  19. def load_points(points_file):
  20. mainDir = bge.logic.expandPath("//assets/")
  21. fileName = mainDir + points_file
  22. with open(fileName, 'r') as filehandle:
  23. return json.load(filehandle)
  24. def build_tree(points):
  25. kd = mathutils.kdtree.KDTree(len(points))
  26. id = 0
  27. for p in points:
  28. p = mathutils.Vector(p[0])
  29. kd.insert(p, id)
  30. id += 1
  31. kd.balance()
  32. return kd
  33. def get_distance(start, end):
  34. length = (end - start).magnitude
  35. return length
  36. class Point(object):
  37. __metaclass__ = IterRegistry
  38. _registry = []
  39. def __init__(self, list_point, parent, iter):
  40. self.l = list_point[0]
  41. self.id = iter
  42. self.parent = parent
  43. self.loc = mathutils.Vector(list_point[0])
  44. self.lneighbors = list_point[1]
  45. self.neighbors = []
  46. self._registry.append(self)
  47. self.g = 100000
  48. self.h = 100000
  49. self.f = 100000
  50. self.prev = None
  51. def get_neighbors(self):
  52. for p in self.lneighbors:
  53. for p_ in self.parent.points:
  54. if p_.loc == mathutils.Vector(p):
  55. self.neighbors.append(p_)
  56. self.neighbors = set(self.neighbors)
  57. def init_points(self):
  58. points = []
  59. iter = 0
  60. for x in self.points_list:
  61. name = 'p' + str(iter)
  62. y = Point(x, self, iter)
  63. points.append(y)
  64. iter += 1
  65. return points
  66. class Astar:
  67. def __init__(self, points_file, messenger):
  68. self.state = 'idle'
  69. self.points_list = load_points(points_file)
  70. self.points = init_points(self)
  71. self.start = []
  72. self.end = []
  73. self.kdtree = build_tree(self.points_list)
  74. self.life = 0
  75. self.open = []
  76. self.closed = []
  77. self.searched = []
  78. self.current = []
  79. self.fscores = []
  80. self.gscores = []
  81. self.lps = []
  82. self.messenger = messenger
  83. self.queue = []
  84. self.current_searcher = None
  85. for x in self.points: x.get_neighbors()
  86. def update(self):
  87. self.life += 1
  88. if self.state == 'searching':
  89. self.search()
  90. if self.life > 5000:
  91. self.state = 'idle'
  92. else:
  93. self.update_queue()
  94. def get_results(self):
  95. result_locs = []
  96. results = []
  97. cp = self.end
  98. breaker = 0
  99. while cp != self.start:
  100. result_locs.append(cp.id)
  101. results.append(cp.loc)
  102. if cp.prev == None:
  103. cp = self.current
  104. else:
  105. cp = cp.prev
  106. breaker += 1
  107. if breaker > 2000:
  108. break
  109. results.reverse()
  110. self.messenger.dispatch('path found', ['found path for object', self.current_searcher, results])
  111. def smallest_f(self):
  112. if len(self.open) > 1:
  113. l = []
  114. lfs = []
  115. for x in self.open:
  116. l.append(x)
  117. lfs.append(x.f)
  118. ind = lfs.index(min(lfs))
  119. return l[ind]
  120. else:
  121. return self.start
  122. #@chrono
  123. def search(self):
  124. tries = 0
  125. if self.open == []:
  126. self.state = 'inactive'
  127. while self.open != []:
  128. try:
  129. self.open.remove(self.current)
  130. except:
  131. pass
  132. current_node = self.smallest_f()
  133. self.current = current_node
  134. self.searched.append(current_node)
  135. self.closed.append(current_node) #add to closed
  136. if current_node == self.end:
  137. path = self.get_results()
  138. self.state = 'inactive'
  139. self.open = []
  140. break
  141. else:
  142. children = current_node.neighbors
  143. for child in children:
  144. self.searched.append(child)
  145. p = current_node
  146. g = get_distance(current_node.loc, child.loc) + current_node.g
  147. h = get_distance(child.loc, self.end.loc)
  148. f = g + h
  149. if child not in self.open and child not in self.closed:
  150. if g >= child.g:
  151. pass
  152. else:
  153. child.g = g
  154. child.h = h
  155. child.f = f
  156. child.prev = p
  157. self.open[:] = [x for x in self.open if x != child]
  158. self.closed[:] = [x for x in self.closed if x != child]
  159. self.open.append(child)
  160. tries += 1
  161. if tries >= 5:
  162. break
  163. def get_neighbor_id(self, id):
  164. iter = 0
  165. for p in self.points:
  166. if p[0] == id:
  167. num = iter
  168. else:
  169. pass
  170. iter += 1
  171. def set_gscore(self):
  172. self.gscores = []
  173. self.fscores = []
  174. self.lps = []
  175. for x in self.points:
  176. self.gscores.append(100000)
  177. self.fscores.append(100000)
  178. self.lps.append(None)
  179. x.f = 100000
  180. x.h = 100000
  181. x.g = 100000
  182. def set_fscore(self):
  183. self.fscores = []
  184. for x in self.points:
  185. self.fscores.append(100000)
  186. def queue_path(self, start_in, end_in, obj):
  187. self.queue.append([start_in, end_in, obj])
  188. def update_queue(self):
  189. if self.queue != []:
  190. self.get_path(self.queue[0][0], self.queue[0][1], self.queue[0][2])
  191. self.queue.remove(self.queue[0])
  192. def get_path(self, start_in, end_in, obj):
  193. stree = self.kdtree.find_n(start_in, 1)
  194. start_out = self.points[stree[0][1]]
  195. otree = self.kdtree.find_n(end_in, 1)
  196. end_out = self.points[otree[0][1]]
  197. self.life = 0
  198. self.current_searcher = obj
  199. self.start = start_out
  200. self.end = end_out
  201. self.state = 'searching'
  202. self.open.append(self.start)
  203. self.set_gscore()
  204. self.current = self.start
  205. self.open = []
  206. self.closed = []
  207. self.searched = []
  208. self.open.append(self.start)
  209. self.current = self.start
  210. self.current.g = 0
  211. self.current.f = 0
  212. self.current.h = get_distance(self.current.loc, self.end.loc)