# Pathfinding Crap
# BY:scabootssca
# scabootssca@yahoo.com
import Blender
import operator
### Generate The Node Tree
pathTree = Blender.Mesh.Get("path")
def dist(a,b):
return ((a[0]-b[0])**2+(a[1]-b[1])**2+(a[2]-b[2])**2)**.5
class point:
def __init__(self,co):
self.neighbors = {}
self.distance = 0
self.co = co
class path:
def __init__(self,points,distance,length):
self.points = points
self.distance = distance
self.length = length
def generateTree(pathTree):
points = {}
for v in pathTree.verts:
points[v.index] = point(v.co)
#print v.index,v.sel
for edge in pathTree.edges:
distance = dist(edge.v1.co,edge.v2.co)
points[edge.v1.index].neighbors[edge.v2.index] = distance
points[edge.v2.index].neighbors[edge.v1.index] = distance
return points
### Extra Stuff
def getClosestTo(pos,points):
closestPoint = 0
closestPos = dist(pos,points[closestPoint].co)
for pointTest in points:
if dist(pos,points[pointTest].co) < closestPos:
closestPoint = pointTest
closestPos = dist(pos,points[pointTest].co)
return closestPoint
def getPath(start,end,points):
p = [] # create a list P
# estimate The Distance
endPoint = points[end]
for pointTest in points.values():
pointTest.distance = dist(endPoint.co,pointTest.co)
# add the start node S, to P giving it one element
p.append(path([start],0,0))
print "-"*30
iter = 0
while True:
iter += 1
#if iter > 10000: print "itered out"; break
# Until first path of P ends with G, or P is empty
if not p: print "not p"; break
elif p[0].points[-1] == end: print "found end On Iter:%i"%iter; break
# extract the first path from P
test = p.pop(0)
# extend first path one step to all neighbors creating X new paths
news = []
for neighbor in points[test.points[-1]].neighbors:
new = path(test.points[:],test.distance,0)
new.points.append(neighbor)
new.distance += points[test.points[-1]].neighbors[neighbor]
new.length = new.distance+points[neighbor].distance
news.append(new)
# reject all paths with loops
tmp = news[:]
for pos,new in enumerate(news):
if len(new.points) != len(set(new.points)): #passes if there is a duplicate
tmp.remove(new)
news = tmp[:]
# for all paths that end at the same node, keep only the shortest one.
same = {}
for pos,new in enumerate(news):
try: same[new.points[-1]].append(new)
except KeyError: same[new.points[-1]] = [new]
for sameNum in same:
lists = same[sameNum]
lowest = lists[0]
for pathTest in lists:
if pathTest.length < lowest.length:
lowest = pathTest
same[sameNum] = lowest
# add each remaining new path to of P
for pathTest in same.values(): p.append(pathTest)
#for new in news: p.append(new)
#Sort all paths by total distance travelled, shortest first.
p.sort(key=operator.attrgetter("length"))#,reverse=1)
return p[0]
### Solve
cont = GameLogic.getCurrentController()
endOwn = cont.getOwner()
startMove = cont.getActuator("start")
startOwn = startMove.getOwner()
trackOwn = cont.getActuator("trackOwn").getOwner()
track = cont.getActuator("track")
if not hasattr(GameLogic,"points"):
GameLogic.points = generateTree(pathTree)
start = getClosestTo(startOwn.getPosition(),GameLogic.points)#0
end = getClosestTo(endOwn.getPosition(),GameLogic.points)#28
startOwn.r = dist(eval(startOwn.lastEndPos),endOwn.getPosition())
if dist(eval(startOwn.lastEndPos),endOwn.getPosition()) > .2:
startOwn.resolve = 1
if startOwn.resolve:# cont.getSensor("solveKey").isPositive():
startOwn.isSolving = 1
startOwn.resolve = 0
GameLogic.path = getPath(start,end,GameLogic.points)
startOwn.lastEndPos = str(endOwn.getPosition())
if startOwn.isSolving:
speed = .01
cur = GameLogic.points[GameLogic.path.points[0]].co
pos = startOwn.getPosition()
dist = dist(cur,pos)
if dist < speed:
del GameLogic.path.points[0]
if GameLogic.path.points:
trackOwn.setPosition(GameLogic.points[GameLogic.path.points[0]].co)
else:
startOwn.isSolving = 0
GameLogic.addActiveActuator(startMove,0)
else:
startMove.setDLoc(0,speed,0,1)
GameLogic.addActiveActuator(startMove,1)
GameLogic.addActiveActuator(track,1)