Simple Pathfind by pedrolbs8th Oct 2011 5:48
|
---|
Summary Simple pathfind function for AGK Description Code ` This code was downloaded from The Game Creators ` It is reproduced here with full permission ` http://www.thegamecreators.com main.agc ---------------------------------------------------- #include "ast.agc" #include "functions.agc" SetVirtualResolution(800,500) setPrintSize(18) Global mapx=22 Global mapy=11 //astar arrays and type------------------------------ //node type to populate cells Type TNode H as Integer //distance to end G as Integer //distance from start ParentX as Integer //coord x of parent cell ParentY as Integer //coord y of parent cell EndType //these two vectors define offset of search patterns //directions are respectively null,N,W,S,E,NE,SE,SW,NW Dim DsX[8] as Integer = [0,0,1,0,-1,1,1,-1,-1] Dim DsY[8] as Integer = [0,-1,0,1,0,-1,1,1,-1] //an array for the open list of cells Dim OpenList[1000,1] as Integer //an array for the closed list of cells Dim ClosedList[1000,1] as Integer //matrix of nodes to help calculate path Dim MapCalc[mapx,mapy] As TNode //---------------------------------------------------- //For the path drawing control------------------------ Dim PathSprites[1000] As Integer Global PathSpritesCounter //---------------------------------------------------- Dim collisionmap[mapx,mapy] Global DiscoveredPath$="" Global tilesize=32 Global img1,spr1,img2,spr2,img3,spr3,img4,spr4,img5,spr5 Global mx,my,mxC,myC,sxC,syC,exC,eyC,selBlock Global selDiag,startBlock,endBlock Global Error$ Global MouseInGrid Dim DiagText$[2] InitializeVariables() LoadMedia() InitializeMap(mapx,mapy) DrawGrid(mapx,mapy,tilesize) DrawButtons() do mx = getpointerx() my = getpointery() mapxb=mapx+2 mapyb=mapy+2 if mx >= tilesize and mx < tilesize * mapxb and my >= tilesize and my < tilesize * mapyb mxC = (mx / tilesize) - 1 myC = (my / tilesize) - 1 MouseInGrid=1 else mxC = -1 myC = -1 MouseInGrid=0 endif if GetVirtualButtonPressed( 10 ) selBlock = spr2 SetSpriteColorAlpha( spr2, 255 ) SetSpriteColorAlpha( spr4, 122 ) SetSpriteColorAlpha( spr5, 122 ) endif if GetVirtualButtonPressed( 11 ) selBlock = spr4 SetSpriteColorAlpha( spr4, 255 ) SetSpriteColorAlpha( spr2, 122 ) SetSpriteColorAlpha( spr5, 122 ) endif if GetVirtualButtonPressed( 12 ) selBlock = spr5 SetSpriteColorAlpha( spr5, 255 ) SetSpriteColorAlpha( spr2, 122 ) SetSpriteColorAlpha( spr4, 122 ) endif if GetVirtualButtonPressed( 1 ) If sxC = -1 or syC = -1 or exC = -1 or eyC = -1 Error$="Error : You need to define the start and the end cells before you find a path." Else DiscoveredPath$ = FindPath(sxC, syC, exC, eyC, selDiag, 1000) DrawPath(DiscoveredPath$) EndIf endif if GetVirtualButtonPressed( 2 ) //clear path ClearPath() endif if GetVirtualButtonPressed( 3 ) selDiag = selDiag + 1 If selDiag = 3 then selDiag = 0 endif if getpointerpressed() = 1 and MouseInGrid=1 If selBlock = 0 Error$="Error : Please select a block before you try to change the grid." ElseIf selBlock=spr2 //wall spr2 If collisionmap[mxC,myC] = 0 crazy1 = (mxC+1) * tilesize crazy2 = (myC+1) * tilesize clonedSprite = CloneSprite ( spr2 ) SetSpritePosition(clonedSprite, crazy1, crazy2) collisionmap[mxC,myC] = clonedSprite Else crazy1 = collisionmap[mxC,myC] deletesprite(crazy1) collisionmap[mxC,myC] = 0 EndIf ElseIf selBlock=spr4 //startpoint spr4 If startBlock > 0 then deletesprite(startBlock) crazy1 = (mxC+1) * tilesize crazy2 = (myC+1) * tilesize startBlock = CloneSprite ( spr4 ) setspriteposition(startBlock,crazy1,crazy2) sxC = mxC syC = myC ElseIf selBlock=spr5 //endpoint spr5 If endBlock > 0 then deletesprite(endBlock) crazy1 = (mxC+1) * tilesize crazy2 = (myC+1) * tilesize endBlock = CloneSprite ( spr5 ) setspriteposition(endBlock,crazy1,crazy2) exC = mxC eyC = myC EndIf endif DebugInfo() Sync() loop functions.agc--------------------------------------------------------- Function DrawPath(Path$) If PathSpritesCounter > 0 Then ClearPath() PathSpritesCounter = 0 PathX = -1 PathY = -1 PathAux$ = "" PathAlter = 0 For i = 1 to Len(Path$) If Mid(Path$,i,1) = "," Or i = Len(Path$) If PathAlter = 0 PathX = Val(PathAux$) PathAlter = 1 - PathAlter PathAux$ = "" Else If i = Len(Path$) Then PathAux$ = PathAux$ + Mid(Path$,i,1) PathY = Val(PathAux$) PathAlter = 1 - PathAlter PathAux$ = "" crazy1 = (PathX+1) * tilesize crazy2 = (PathY+1) * tilesize clonedSprite = CloneSprite ( spr3 ) SetSpritePosition(clonedSprite, crazy1, crazy2) PathSprites[PathSpritesCounter] = clonedSprite PathSpritesCounter = PathSpritesCounter + 1 EndIf Else PathAux$ = PathAux$ + Mid(Path$,i,1) EndIf Next i EndFunction Function ClearPath() If PathSpritesCounter = 0 Then exit For cp = 0 to PathSpritesCounter - 1 If PathSprites[cp] > -1 DeleteSprite(PathSprites[cp]) PathSprites[cp]=-1 EndIf Next EndFunction function DrawButtons() if GetVirtualButtonExists( 10 ) = 0 then AddVirtualButton( 10, 42, 470, 25 ) SetSpriteColorAlpha( spr2, 122 ) SetSpritePosition ( spr2, 60, 455) if GetVirtualButtonExists( 11 ) = 0 then AddVirtualButton( 11, 122, 470, 25 ) SetSpriteColorAlpha( spr4, 122 ) SetSpritePosition ( spr4, 140, 455) if GetVirtualButtonExists( 12 ) = 0 then AddVirtualButton( 12, 202, 470, 25 ) SetSpriteColorAlpha( spr5, 122 ) SetSpritePosition ( spr5, 220, 455) if GetVirtualButtonExists( 1 ) = 0 then AddVirtualButton( 1, 622, 470, 50 ) SetVirtualButtonText( 1, "Find Path" ) if GetVirtualButtonExists( 2 ) = 0 then AddVirtualButton( 2, 742, 470, 50 ) SetVirtualButtonText( 2, "Clear Path" ) if GetVirtualButtonExists( 3 ) = 0 then AddVirtualButton( 3, 352, 470, 25 ) endfunction function DebugInfo If GetTextExists( 10 ) = 0 then CreateText(10,"") SetTextSize( 10, 14 ) SetTextPosition( 10, 32, 1 ) SetTextColor( 10, 0, 255, 0, 255 ) SetTextString( 10, "Mouse x,y : " + str(mx) + "," + str(my)) If GetTextExists( 11 ) = 0 then CreateText(11,"") SetTextSize( 11, 14 ) SetTextPosition( 11, 232, 1 ) SetTextColor( 11, 0, 255, 0, 255 ) SetTextString( 11, "Mouse Cell x,y : " + str(mxC) + "," + str(myC)) If GetTextExists( 12 ) = 0 then CreateText(12,"") SetTextSize( 12, 12 ) SetTextPosition( 12, 32, 436 ) SetTextString( 12, "Path returned : " + DiscoveredPath$) If GetTextExists( 13 ) = 0 then CreateText(13,"") SetTextSize( 13, 14 ) SetTextPosition( 13, 32, 416 ) SetTextColor( 13, 255, 0, 0, 255 ) SetTextString( 13, Error$) If GetTextExists( 14 ) = 0 then CreateText(14,"") SetTextSize( 14, 14 ) SetTextPosition( 14, 452, 1 ) SetTextColor( 14, 0, 255, 0, 255 ) SetTextString( 14, "Diagonals : " + DiagText$[selDiag]) If GetTextExists( 15 ) = 0 then CreateText(15,"") SetTextSize( 15, 14 ) SetTextPosition( 15, 370, 463 ) SetTextString( 15, "Toggle diagonals") If GetTextExists( 16 ) = 0 then CreateText(16,"") SetTextSize( 16, 12 ) SetTextPosition( 16, 140, 487 ) SetTextString( 16, str(sxC)+","+str(syC)) If GetTextExists( 17 ) = 0 then CreateText(17,"") SetTextSize( 17, 12 ) SetTextPosition( 17, 220, 487 ) SetTextString( 17, str(exC)+","+str(eyC)) endfunction function DrawGrid(columns,rows,tsize) for x = -1 to columns for y = -1 to rows if x = -1 and y >= 0 iTextIndex = CreateText ( str(y) ) SetTextSize( iTextIndex, 16 ) SetTextAlignment( iTextIndex, 1 ) SetTextPosition( iTextIndex, tsize/2, (y + 1) * tsize + (tsize/4) ) elseif y = -1 and x >= 0 iTextIndex = CreateText ( str(x) ) SetTextSize( iTextIndex, 16 ) SetTextPosition( iTextIndex, (x + 1) * tsize + (tsize/4), tsize/2 ) elseif x >= 0 and y >= 0 clonedSprite = CloneSprite ( spr1 ) SetSpritePosition ( clonedSprite, (x + 1) * tsize, (y + 1) * tsize) endif next y next x endfunction function InitializeMap(columns,rows) for x = 0 to columns for y = 0 to rows If collisionmap[columns,rows]>0 auxsprite = collisionmap[columns,rows] DeleteSprite( auxsprite ) collisionmap[columns,rows]=0 EndIf next y next x endfunction function LoadMedia() img1 = LoadImage ("cell001.png") spr1 = CreateSprite ( img1 ) setspritedepth(spr1,10000) setspriteposition(spr1,-100,-100) img2 = LoadImage ("cell002.png") spr2 = CreateSprite ( img2 ) setspritedepth(spr2,9999) setspriteposition(spr2,-100,-100) img3 = LoadImage ("cell003.png") spr3 = CreateSprite ( img3 ) setspritedepth(spr3,9998) setspriteposition(spr3,-100,-100) img4 = LoadImage ("cellStart.png") spr4 = CreateSprite ( img4 ) setspritedepth(spr4,9997) setspriteposition(spr4,-100,-100) img5 = LoadImage ("cellEnd.png") spr5 = CreateSprite ( img5 ) setspritedepth(spr5,9996) setspriteposition(spr5,-100,-100) endfunction Function InitializeVariables() MouseInGrid=0 Error$="" selBlock=0 startBlock = 0 endBlock = 0 sxC=-1 syC=-1 exC=-1 eyC=-1 selDiag = 0 DiagText$[0] = "no" DiagText$[1] = "yes but no cutting corners" DiagText$[2] = "yes and can cut corners" For ps = 0 to 1000 PathSprites[ps]=-1 Next ps PathSpritesCounter = 0 EndFunction ast.agc--------------------------------------------------------------------------- Function FindPath(sX, sY, eX, eY, Diag, MaxSteps) // Parameters // sX - x coord of origin cell // sY - y coord of origin cell // eX - x coord of destination cell // eY - y coord of destination cell // Diag // 0 - No diagonals // 1 - Allow diagonals without cutting corners // 2 - Allow all diagonals // MaxSteps - max number of steps you allow the function to run // // This function is counting on the existence of 3 globals // mapx - integer - size x of the map // mapy - integer - size y of the map // collisionmap[mapx,mapy] - integers - matrix holding collision info //This var will define how many directions we will be searching from each parent cell Dirs=4 //if diagonals are allowed we update the amount of directions to search If Diag>0 then Dirs=8 //these two vars a and b will help search the open list for the next node a=0 b=0 //will help to check if there are any more path possibilities CountOpenCells=0 //these four vars will help find the way back //from end cell to start cell CamX=-1 CamY=-1 CamXaux = -1 CamYaux = -1 //this var will hold the path returned by the function FoundPath$="" //will help to check if we reached the end of the path search TerminationFlag = 0 //x coord of point being examined starts being the x of the starting point Px=sX //y coord of point being examined starts being the y of the starting point Py=sY //step counter StepCounter=0 //node holding our currently examined parent cell P as TNode //node holding the cells examined around the parent cell NewP as TNode //and here we say there is one element in the open list OpenCounter=1 //here we say there are zero elements in the closed list ClosedCounter=0 //this tells the function we are currently using element 0 of the open list OpenCurrent = 0 //dont search if start equals end If sX=eX and sY=eY then FoundPath$="already at target" //dont search if end is a wall If FoundPath$="" and collisionmap[eX,eY]>0 then FoundPath$="impossible path" If FoundPath$="" and collisionmap[sX,sY]>0 then FoundPath$="impossible path" //if we passed the first checks we are ready for the actual search If FoundPath$="" //this will initialize MapCalc to -1 in all four values of each node P.G=-1 P.H=-1 P.ParentX=-1 P.ParentY=-1 For i = 0 to mapx For j = 0 to mapy MapCalc[i,j] = P Next j Next i //here we define the starting cell as the first //element of the open list OpenList[0,0]=sX OpenList[0,1]=sY //these four lines define the node of the starting cell P.G=0 P.H=10*(Abs(Px-eX)+Abs(Py-eY)) P.ParentX = 666 P.ParentY = 666 //and this one puts the node in the starting coords MapCalc[sX,sY]=P //lets start the search Do //increment step counter StepCounter = StepCounter + 1 //iterator for direction offsets For i = 1 to Dirs //first we acquire the coords of the cell to be examined NewPx = Px + DsX[i] NewPy = Py + DsY[i] //we start assuming its walkable Walkable = 1 //then we will define it as not walkable if... //if the coordinates are off the grid If NewPx<0 or NewPx>mapx or NewPy<0 or NewPy>mapy then Walkable = 0 If Walkable = 1 //if there is a wall at this new cell If collisionmap[NewPx,NewPy]>0 then Walkable = 0 //if this is a diagonal direction but we cant cut corners and we would have to If NewPy + 1 <= mapy and NewPx - 1 >= 0 If Diag = 1 and i=5 and (collisionmap[NewPx,NewPy+1]>0 Or collisionmap[NewPx-1,NewPy]>0) then Walkable = 0 EndIf If NewPy - 1 >= 0 and NewPx - 1 >= 0 If Diag = 1 and i=6 and (collisionmap[NewPx,NewPy-1]>0 Or collisionmap[NewPx-1,NewPy]>0) then Walkable = 0 EndIf If NewPy - 1 >= 0 and NewPx + 1 <= mapx If Diag = 1 and i=7 and (collisionmap[NewPx,NewPy-1]>0 Or collisionmap[NewPx+1,NewPy]>0) then Walkable = 0 EndIf If NewPy + 1 <= mapy and NewPx + 1 <= mapx If Diag = 1 and i=8 and (collisionmap[NewPx,NewPy+1]>0 Or collisionmap[NewPx+1,NewPy]>0) then Walkable = 0 EndIf //if the cell is already in the closed list for j=0 to ClosedCounter -1 if ClosedList[j,0] = NewPx and ClosedList[j,1] = NewPy then Walkable = 0 next j EndIf //if none of the previous checks was positive then the cell is walkable for sure If Walkable = 1 //so we define the node values that will occupy it NewP.ParentX = Px NewP.ParentY = Py // the following penalizes a diagonal movement If i <= 4 NewP.G=P.G+10 Else NewP.G=P.G+14 EndIf NewP.H=10*(Abs(NewPx-eX)+Abs(NewPy-eY)) //lets check if the cell is already in the open list OpenExists = -1 for j=0 to OpenCounter -1 if OpenList[j,0] = NewPx and OpenList[j,1] = NewPy then OpenExists = j next j if OpenExists = -1 //if it is not then we give it the values of the new node //and we put the cell in the open list also incrementing the open list counter OpenList[OpenCounter,0] = NewPx OpenList[OpenCounter,1] = NewPy OpenCounter = OpenCounter + 1 MapCalc[NewPx,NewPy] = NewP //if by any chance we spotted the end cell lets raise a termination flag If NewPx=eX and NewPy=eY then TerminationFlag=1 else //if the cell is already in the open list we check to //see if this new way of reaching it is better tahn the one //previously found if MapCalc[NewPx,NewPy].G > NewP.G then MapCalc[NewPx,NewPy] = NewP endif //finished dealing with this walkable cell EndIf //lets go and check the next neighbour of our current cell Next i //at this point we checked every possible neighbour of the currently examined cell //if the termination flag was raised //we build the path string and exit the function If TerminationFlag=1 //we start at the end cell FoundPath$=str(eX)+","+str(eY) CamX=eX CamY=eY //we will repeat the following steps until we reach the starting node repeat FoundPath$=FoundPath$+"," CamXaux = CamX CamYaux = CamY //we make CamX and CamY point to the parent cell of the current cell CamX=MapCalc[CamXaux,CamYaux].ParentX CamY=MapCalc[CamXaux,CamYaux].ParentY //and we put those coords in the path string FoundPath$=FoundPath$+str(CamX)+","+str(CamY) until CamX=sX and CamY=sY //and we exit the do loop cycle to exit the function exit EndIf //if we went over the step limit we issue an error and leave the function If StepCounter>=MaxSteps FoundPath$="step limit exceeded" Exit EndIf //this invalidates the element of the open list we were examining OpenList[OpenCurrent,0] = -1 OpenList[OpenCurrent,1] = -1 //this adds that element to the closed list and increments the closed list counter ClosedList[ClosedCounter,0] = Px ClosedList[ClosedCounter,1] = Py ClosedCounter = ClosedCounter + 1 //here starts the process that will find the best //possible candidate to become the next current cell to be examined //initialize the comparison values to high values MinimoF = 999999 MinimoH = 999999 //initialize the counter of valid elements in the open list CountOpenCells=0 for i = 0 to OpenCounter - 1 //will only check the element if its valid If OpenList[i,0] > -1 //increments the counter of valid elements CountOpenCells=CountOpenCells+1 //retrieves the coords of the open list element a = OpenList[i,0] b = OpenList[i,1] //now we check the values of these coordinates AuxValue = MapCalc[a,b].G + MapCalc[a,b].H AuxValue2 = MapCalc[a,b].H //and we compare them to the best we found so far If AuxValue <= MinimoF and AuxValue2 < MinimoH //if they are better we prepare the cell to be examined next MinimoF = AuxValue MinimoH = AuxValue2 OpenCurrent = i Px = a Py = b P = MapCalc[a,b] endif endif next i //if there are no valid elements in the open list we have no path to //help us reach the end cell if CountOpenCells = 0 FoundPath$="no path to target" exit endif // now that we have a new cell to examine we go back to // start checking its neighbours Loop EndIf EndFunction FoundPath$ |