Simple A* algorithm example made in UPBGE/Blender and python.
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.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import bge
  2. scene = bge.logic.getCurrentScene()
  3. import math
  4. import mathutils
  5. lVector = []
  6. lOpen = []
  7. lClosed = []
  8. lShortest_Dist = []
  9. lPrevious_Vert = []
  10. lFrom_Start = []
  11. lHur = []
  12. lFval = []
  13. lDistances = []
  14. def build_lists(own):
  15. mesh = own.meshes
  16. size = own.meshes[0].getVertexArrayLength(0)
  17. kd = mathutils.kdtree.KDTree(size)
  18. lVector_tmp = []
  19. for mesh in own.meshes:
  20. for m_index in range(len(mesh.materials)):
  21. for v_index in range(mesh.getVertexArrayLength(m_index)):
  22. vertex = mesh.getVertex(m_index, v_index)
  23. lVector_tmp.append(vertex.XYZ)
  24. id = 0
  25. for x in lVector_tmp:
  26. if x not in lVector:
  27. lVector.append(x)
  28. lShortest_Dist.append(100000)
  29. lHur.append(100000)
  30. lFval.append(100000)
  31. lFrom_Start.append(100000)
  32. lPrevious_Vert.append(None)
  33. kd.insert(x, id)
  34. id += 1
  35. kd.balance()
  36. own['kd'] = kd
  37. def mouse2world():
  38. cam = bge.logic.getCurrentScene().active_camera
  39. vec = cam.getScreenVect(*bge.logic.mouse.position)
  40. camPos = cam.worldPosition
  41. projectedPos = [0,0,0]
  42. z = 60 # user-set depth
  43. projectedPos[0] = camPos[0] - vec[0] * z
  44. projectedPos[1] = camPos[1] - vec[1] * z
  45. projectedPos[2] = camPos[2] - vec[2] * z
  46. return projectedPos
  47. def clear_points():
  48. scene = bge.logic.getCurrentScene()
  49. for x in scene.objects:
  50. if 'point' in x:
  51. x.endObject()
  52. def mouse(cont):
  53. own = cont.owner
  54. keyboard = bge.logic.mouse
  55. JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
  56. if keyboard.events[bge.events.LEFTMOUSE] == JUST_ACTIVATED:
  57. mouse_pos = mouse2world()
  58. print('mouse clicked on', mouse_pos)
  59. end_pos = mouse_pos
  60. if 'end_pos' in own:
  61. own['start_pos'] = own['end_pos']
  62. own['start_index'] = own['end_index']
  63. own['end_pos'] = mouse_pos
  64. kd = own['kd']
  65. end_pos = mathutils.Vector((end_pos[0], end_pos[1], 0))
  66. co_find = end_pos
  67. co, index, dist = kd.find(co_find)
  68. own['end_pos'] = co
  69. own['end_index'] = index
  70. own['end_index'] = lVector.index(co)
  71. draw(own)
  72. def draw_path(own):
  73. start_index = own['start_index']
  74. end_index = own['end_index']
  75. breaker = 0
  76. current_pindex = end_index
  77. pos = scene.objects['addEmpty']
  78. starPath = []
  79. while current_pindex != start_index and breaker < 1600:
  80. try:
  81. current_pindex = lPrevious_Vert[current_pindex]
  82. if lVector[current_pindex] != own['start_pos']:
  83. pos.worldPosition = lVector[current_pindex]
  84. starPath.append(lVector[current_pindex])
  85. else:
  86. current_pindex = start_index
  87. except:
  88. current_pindex = start_index
  89. print('no current index')
  90. breaker += 1
  91. return starPath
  92. def draw_point(drawList, own, starPath):
  93. id = 0
  94. obj = scene.objects['addEmpty']
  95. for x in drawList:
  96. if x != own['start_pos'] and x != own['end_pos']:
  97. obj.worldPosition = x
  98. obj.worldPosition.z = .001
  99. point = scene.addObject('point', obj)
  100. point.color = [.5,.5,.05,0]
  101. point.scaling = [.5,.5,.5]
  102. point['id'] = id
  103. id += 1
  104. starPath = starPath[::-1]
  105. for x in starPath:
  106. obj.worldPosition = x
  107. obj.worldPosition.z = .002
  108. point = scene.addObject('point', obj)
  109. point.color = [0,1,1,0]
  110. point.scaling = [1,1,1]
  111. point['star'] = True
  112. point['id'] = id
  113. id += 1
  114. def draw(own):
  115. clear_points()
  116. get_start_end_verts(own)
  117. pos = scene.objects['addEmpty']
  118. pos.worldPosition = own['start_pos']
  119. start_pos = own['start_pos']
  120. point = scene.addObject('point', pos)
  121. point.color = [0,1,0,1]
  122. point.scaling = [2,2,2]
  123. point['ticker'] = 2.0
  124. if 'end_pos' in own:
  125. pos.worldPosition = own['end_pos']
  126. point = scene.addObject('point', pos)
  127. point.color = [1,0,0,1]
  128. point.scaling = [2,2,2]
  129. point['ticker'] = 2.0
  130. get_start_end_verts(own)
  131. dijk8(own)
  132. def get_neighbors(own, start):
  133. sv = lVector.index(start)
  134. kd = own['kd']
  135. neighbor_list = []
  136. neighbor_length_list = []
  137. for (co, index, dist4) in kd.find_n(start, 9):
  138. if co != start:
  139. neighbor_list.append(co)
  140. neighbor_length_list.append(dist4)
  141. min_dist = min(neighbor_length_list) * 1.5
  142. id = 0
  143. tnl = []
  144. for x in neighbor_list:
  145. if neighbor_length_list[id] > min_dist:
  146. neighbor_list.remove(x)
  147. else:
  148. tnl.append(x)
  149. id += 1
  150. neighbor_list = tnl
  151. return neighbor_list
  152. def dijk8(own):
  153. lOpen = []
  154. drawList = []
  155. for x in lVector:
  156. lShortest_Dist[lVector.index(x)] = 100000
  157. lPrevious_Vert[lVector.index(x)] = None
  158. lOpen.append(x)
  159. lFval[lVector.index(x)] = 1000000
  160. lHur = lDistances[own['end_index']]
  161. lShortest_Dist[own['start_index']] = 0
  162. lFval[own['start_index']] = lHur[own['start_index']]
  163. breaker = 0
  164. while lOpen != []:
  165. start = own['start_pos']
  166. tmp_dst = []
  167. id = 0
  168. for x in lFval:
  169. if lVector[id] in lOpen:
  170. tmp_dst.append(x)
  171. else:
  172. tmp_dst.append(50000000)
  173. id += 1
  174. parent_id = tmp_dst.index(min(tmp_dst))
  175. cur_vec = lVector[parent_id]
  176. cost = lShortest_Dist[parent_id]
  177. cur_Vid = parent_id
  178. cur_id = parent_id
  179. drawList.append(cur_vec)
  180. if cur_vec == own['end_pos']:
  181. print('path found')
  182. break
  183. neighbor_list = get_neighbors(own, cur_vec)
  184. from_start = lShortest_Dist[cur_Vid]
  185. for nb in neighbor_list:
  186. cv = lVector.index(nb)
  187. total_dist = ((cur_vec - nb).length) + from_start
  188. if lShortest_Dist[cv] > total_dist:
  189. lShortest_Dist[cv] = total_dist
  190. lPrevious_Vert[cv] = parent_id
  191. fval = lHur[cv] + lShortest_Dist[cv]
  192. if lFval[cv] > fval:
  193. lFval[cv] = fval
  194. lOpen.remove(cur_vec)
  195. if lOpen == []:
  196. print('list emptied')
  197. break
  198. breaker += 1
  199. if breaker > 4000:
  200. print('breaker tripped')
  201. break
  202. starPath = draw_path(own)
  203. draw_point(drawList, own, starPath)
  204. def get_start_end_verts(own):
  205. kd = own['kd']
  206. start = own['start_pos']
  207. end = own['end_pos']
  208. co, start_index, dist = kd.find(start)
  209. co, end_index, dist = kd.find(end)
  210. own['start_index'] = start_index
  211. own['end_index'] = end_index
  212. lShortest_Dist[start_index] = 0
  213. def pre_compute_dist(own):
  214. id = 0
  215. while id < len(lVector):
  216. end = lVector[id]
  217. lst = []
  218. for y in lVector:
  219. dist = ((end - y).length)
  220. lst.append(dist)
  221. lDistances.append(lst)
  222. id += 1
  223. def main(cont):
  224. own = cont.owner
  225. if 'inited' not in own:
  226. own['start_pos'] = mathutils.Vector((0.0, 0.0, 0.0))
  227. own['end_pos'] = mathutils.Vector((4.0, 8.0, 0.0))
  228. build_lists(own)
  229. pre_compute_dist(own)
  230. get_start_end_verts(own)
  231. own['inited'] = True
  232. draw(own)
  233. mouse(cont)