Pathfinding using waypoints help

Blitz3D Forums/Blitz3D Programming/Pathfinding using waypoints help

Ross C(Posted 2006) [#1]
Hey, i have been trying to get my head round pathfinding for a while. I mostly grasp the grid idea, but struggle in finding the shortest path. I can find a path and navigate around obstacles, hugging the terrain, but obviously this isn't the shortest path. Anyyyyyyyyway...

I figured i'd set up nodes or waypoints in my editor, to try and reduce the time taken to calculate a path. But, i'm a bit stuck on how to go about finding the shortest path...

www.rosscrooks.pwp.blueyonder.co.uk/waypoints.PNG

Take that picture for example, can someone outline the process for finding the shortest path. Just a quick text description would be lovely :o) I thought choosing the nodes, based on how close they were to the destination, but as that path may lead to a far longer route, i don't think i can use that.


Chroma(Posted 2006) [#2]
You could calculate the distance in between each set of nodes and then compare them, choose the one with the shortest distance.


(tu) sinu(Posted 2006) [#3]
read up on djekstra (sp?) i coded my pathfinding using it.


Ross C(Posted 2006) [#4]
Does it use nodes? Or a grid? I'll see if i can find anything. Was just wondering a rough process of steps to take to achieve this.

Chroma. The problem with calculating the distances, is you would need to loop through all the possible different combinations, marking nodes, so you can't go back on yourself. Depending on the number of nodes and connecting nodes, it could take a while to calculate.


Matty(Posted 2006) [#5]
Hi Ross - I use waypoints in my game and have a simple program I run outside of the actual game to pre calculate the pathfinding solution so that in the game the units only need to specify their starting and target positions and they are given the 'next node' to move to on their way to their target.

However the same system could be used in real time. (with some modifications)

Here is a cutdown version of what I use, hopefully it is helpful. The IsInLOS function will need to be changed if you are doing a 3d world, as it is currently for a 2d environment.




puki(Posted 2006) [#6]
There are a few examples in the old Blitzcoder Showcase: http://www.blitzcoder.com/cgi-bin/showcase/showcase_frontpage.pl

I think the solution is really going to depend on the actual game and the requirements of the pathfinding.

If it were a FPS-type (corridors) game then, personally, I'd precalc as much as possible.


Bouncer(Posted 2006) [#7]
Just google for A* algorithm. All grid methods can alo be used for node graphs with slight modification. But A* is clearly the best in most situations (some other algos work better in special cases).

Read this as a base:
http://www.policyalmanac.org/games/aStarTutorial.htm

and continue with this:
http://www.policyalmanac.org/games/twoTiered.htm

and when actually coding the thing... better do it with binary heaps, so read this:
http://www.policyalmanac.org/games/binaryHeaps.htm

And to make this all easier for you... here's my pretty fast heap functions:

;HEAP FUNCTIONS
Global HEAPSIZE=0
Global HMAXSIZE=100			;this is your heaps size
Dim HEAPITEM%(HMAXSIZE)
Dim HEAPKEY#(HMAXSIZE)

Function HEAP_INSERT(n,key#)
HEAPSIZE=HEAPSIZE+1
HEAPITEM(HEAPSIZE) = n

m = HEAPSIZE
HEAPKEY(HEAPITEM(m))=key

  While m <> 1 ;While item hasn't bubbled to the top (m=1)

     ;Check if child is <= parent. If so, swap them.
     If HEAPKEY(HEAPITEM(m)) <= HEAPKEY(HEAPITEM(m/2)) Then
        temp = HEAPITEM(m/2)
        HEAPITEM(m/2) = HEAPITEM(m)
        HEAPITEM(m) = temp
        m = m/2 
     Else

        Exit ;exit the while/wend loop
     End If
  Wend
End Function

Function HEAP_REMOVELOWEST()
;If HEAP_EMPTY()=0
L = HEAPITEM(1)

;GET THE LAST ITEM AND PUT IT IN THE FIRST POSITION
;(FIRST GET*S DELETED)
HEAPITEM(1) = HEAPITEM(HEAPSIZE)
HEAPSIZE = HEAPSIZE - 1

v = 1
;Repeat the following until the item sinks to its proper spot in the binary heap.
Repeat
  u = v
  If 2*u+1 <= HEAPSIZE;if both children exist
    ;Select the lowest of the two children.
    If HEAPKEY(HEAPITEM(u)) >= HEAPKEY(HEAPITEM(2*u)) Then v = 2*u 
    If HEAPKEY(HEAPITEM(v)) >= HEAPKEY(HEAPITEM(2*u+1)) Then v = 2*u+1

  Else If 2*u <= HEAPSIZE ;if only child #1 exists
    ;Check if the F cost is greater than the child
    If HEAPKEY(HEAPITEM(u)) >= HEAPKEY(HEAPITEM(2*u))Then v = 2*u
  End If

  If u <> v Then ; If parent's F > one or both of its children, swap them
    temp = HEAPITEM(u)
    HEAPITEM(u) = HEAPITEM(v)
    HEAPITEM(v) = temp
  Else
    Exit ;if item <= both children, exit repeat/forever loop
  End If
Forever

Return L
;End If
End Function

Function UPDATE_HEAPITEM(item,newkey#,HEAPPOS=0)
If HEAPPOS=0
For i=1 To HEAPSIZE
If HEAPITEM(i) = item Then m=i:Exit
Next
Else 
m=HEAPPOS
End If

HEAPKEY(HEAPITEM(m)) = newkey

  While m <> 1 ;While item hasn't bubbled to the top (m=1)
     ;Check if child is <= parent. If so, swap them.
     If HEAPKEY(HEAPITEM(m)) <= HEAPKEY(HEAPITEM(m/2)) Then
        temp = HEAPITEM(m/2)
        HEAPITEM(m/2) = HEAPITEM(m)
        HEAPITEM(m) = temp
        m = m/2 
     Else
        Exit ;exit the while/wend loop
     End If
  Wend
End Function

Function HEAP_EMPTY()
If HEAPSIZE>0 Return 0 Else Return 1
End Function
Function CLEAR_HEAP()
Dim HEAPITEM%(HMAXSIZE)
Dim HEAPKEY#(HMAXSIZE)
HEAPSIZE=0
End Function




Bouncer(Posted 2006) [#8]
ALso here's an example A* loop using the above heap code for you to study. It's ripped out of my game so it doesn't work as is... but it's pretty well commented.

Function P_ASTAR(node1%,GOAL%,o%=0)
Local CLOSED%[P_MAXNODES]
Local PARENT%[P_MAXNODES]
Local G#[P_MAXNODES]					;GENERATED COST
Local H#[P_MAXNODES]					;ESTIMATED COST (to target)
goal_found=0

If o=0 Then P_GOAL_NODE(o) = 0


If NODE1 <> GOAL
CLEAR_HEAP()
HEAP_INSERT(node1,0)


;P_ELAPSEDTIME=MilliSecs()
Repeat
;GET THE MOST LOWEST COST NODE FROM THE HEAP
current = HEAP_REMOVELOWEST()

;PUT IT TO THE CLOSED LIST
CLOSED[current] = 1

	;CHECK ALL THE NODES CONNECTED TO CURRENT NODE
	For i=1 To P_NODE_CONNECTIONS(current)
	nn = P_NODE_CON(current,i)

	;IF NOT ON THE CLOSED LIST PROCEED
	If CLOSED[nn]=0
	
	;SEARCH THE OPEN LIST -> PUT THE HEAP POS IN found ELSE found = 0
	found=0
	For ii=1 To HEAPSIZE
	If HEAPITEM(ii) = nn Then found=ii:Exit
	Next

	;NOT ON OPENLIST ---> CALCULATE COST AND PUT IT IN!
	If found=0
	PARENT[nn] = current
	H[nn] = P_MANHATTAN_DISTANCE(nn,GOAL)					;ESTIMATE THE DISTANCE TO GOAL
	G[nn] = P_NODE_ARCLENGTH(current,i) + G[current]		;G = distance to this node + G of the parent node
	F# = G[nn] + H[nn]																	;CALCULATE FINAL COST

	;PUT TO OPENLIST
	HEAP_INSERT(nn,F)
	End If

	;IS ON THE OPEN LIST --- > CHECK IF THIS IS BETTER PATH TO  IT
	If found>0
	NG# = P_NODE_ARCLENGTH(current,i) + G[current]

		;IF THIS PATH*S G SCORE = LOWER THAN OLD G --> UPDATE
		If NG<G[nn]
		PARENT[nn] = current
		G[nn] = NG																				;REPLACE THE OLD G WITH THE CURRENT G
		F# = G[nn] + H[nn]																	;CALCULATE FINAL COST
		UPDATE_HEAPITEM(nn,F,found)											;UPDATE THIS NODE
		End If
		
	End If

	End If
	Next

If current=GOAL Then goal_found=1
Until  HEAP_EMPTY()=1 Or goal_found=1 
End If

	P_PATHNODES(o)=0
	P_PATHCOST(o)=0
	
	If P_GOAL_NODE(o)>0
	P_PATHNODES(o) = P_PATHNODES(o) + 1
	P_PATHNODE(o,P_PATHNODES(o)) = P_GOAL_NODE(o)
	End If

;TRACE THE PATH!
If goal_found=1
current=GOAL
P_PATHCOST(o) = G[current]

	Repeat
	P_PATHNODES(o) = P_PATHNODES(o)+1
	P_PATHNODE(o,P_PATHNODES(o)) = current
	current = PARENT[current]
	Until current=node1
	P_PATHNODES(o) = P_PATHNODES(o)+1
	P_PATHNODE(o,P_PATHNODES(o)) = current

End If



;P_ELAPSEDTIME=MilliSecs()-P_ELAPSEDTIME

Return P_PATHNODES(o)
End Function



Ross C(Posted 2006) [#9]
Thanks alot guys, i'll have a good look through this lot. My needs are fairly simple. Just a basic 2d solution would suit my 3d world. :o) Thanks again!


b32(Posted 2006) [#10]
Looking at the picture, I would think you just need to add all distances ?

Hope this would make any sense than:
You can determine "direct" distances. That would be distances between two points that are connected.
And "indirect" distances. Distances between two points that are connected via another point.

First, calculate all direct distances.
Then, calculate all indirect distances by adding the direct distances to each other.

example:

Phase 1
Point 0->1=100 units
Point 1->2=125 units
Point 2->3= 75 units

Phase 2
Point 0->2=225 units
Point 0->3=300 units
etc.


Danny(Posted 2006) [#11]
Check these recent Gamasutra Feature, pretty good stuff on advanced pathfinding...

http://www.gamasutra.com/features/20060626/strom_01.shtml
and
http://www.stromcode.com/wiki/index.php?title=Main_Page/Articles/Genetic_Programming:_Evolving_an_Intelligent_Pathfinding_Algorithm