TGB/Source/Pathfinding

From TDN


Introduction


What follows is long, ugly, error prone, and guaranteed to drive you batty!
Its not true A* (star) in order to all it true A Star I'm told I must calculate the F value from G+H, but this implements much of the same kind of logic as true A*.

In the following examples, the red line shows what moveTo() on its own would probably try to do.
The Blue arrows show the path, and orientation of the moveToAstar() in action.
EyeCandy
Image:t2d-AI-ShowPath1.png
Image:t2d-AI-ShowPath2.png


This example requires some knowledge of TorqueScripting, and if you've worked through the example projects provided with TGB, most of this will make sense.. If not, I suggest you work through those examples first.
Here Goes Nothing

t2dAnimatedSprite In these examples , I have built a set of t2dAnimatedSprites with 8 way orientation, North,NorthEast,East,SouthEast,South,SouthWest,West,and NorthWest.
I named these sprites
northcowWalk
northwestcowWalk
eastcowWalk
southeastcowWalk
southcowWalk
southwestcowWalk
westcowWalk
and northwestcowWalk
I choose these names because I can easily set orientation with our %path.direction which you will see in our finished example.
I have a t2dAnimatedSprite as my main player character and named her scripting Name "cow", my scene starts out point east, so I assigned the "eastcowWalk" to her.

   new t2dAnimatedSprite(cow) {
      animationName = "eastcowWalk";
      position = "-31 2.37037";
      size = "12 12";
      cost = "1";
      mountID = "2";
   };

You'll notice the "cost" field has been added, this is going to be an important addition to all of your SceneObjects to properly weigh movement, if the cost is set properly, the cow walks around your objects not through them..
Now were going to need some helper functions to properly launch callbacks on certain things. I'll show you the entire function, then explain whats going on in each of them.
sceneWindow2D::onMouseDown

   function sceneWindow2D::onMouseUp(%this, %modifier, %worldPosition, %clicks)
   {
         %x = mfloor(getWord(%worldPosition,0));
         %y = mfloor(getWord(%worldPosition,1));
         moveToAstar(cow,findPath(cow,%x SPC %y,mfloor(cow.getWidth() /2),1000),10);   
   }


A typical t2dSceneWindow OnMouseUp event. When you release your mouse on your sceneWindow, we grab the world position x and the world postion y, and mfloor them, I found doing this helps the pathfinder out a hair by making the math a bit easier on the cpu. then we call moveToAstar() our function in our Astar Package you'll meet later on. But to give you an idea of what its doing here, i'll explain each portion

cow


This simply is our t2dAnimatedSprite we created above. Were telling our moveTo function who's going to use it.

findPath(cow,%x SPC %y,mfloor(cow.getWidth() /2)


Here were telling our findPath function, to use the object cow, and our moveTo vector is our mfloored world positions, the final part

mfloor(cow.getWidth()/2)


set the pathfinders width of nodes it will use to search, set too low, your pathfinder will create possibly hundreds or thousands of steps in the path to get someplace, set to high, you wont get natural movement.

1000

This sets the max Number of nodes were going to search...

and finally

10

the speed our our movement along the path , similar to %speed in the moveTo..
we now have a method to call our pathfinding routines.

In order to load the Astar stuff, you'll need to exec the package and activate it.

exec($currentProject @ "/gameScripts/aStar.cs");
activatePackage(Astar);

The Entire Ugly, Astar Package .....

//Astar techniques for finding paths.
//my implementation works off the width of the sprite in question.
//This also assumes North is Up

package Astar
{
   //Return Debug State
   
   function getaStarDebug()
   {
      return $aStarDebug;      
   }
 
   //set Debug State
   
   function setaStarDebug(%val)
   {
            $aStarDebug = %val;
            return getaStarDebug();
   }
   
   
   //given a sprite width, and a sceneGraph vector
   //we'll calculate neighbors for 
   //an 8 way directional the centers of each being that width away
   //N,NE,E,SE,S,SW,W,NW
   //and return a 16 element vector of their X/Y positions
   //I mostly use this for running scenarios from other script.
   //but Its here if you need it.
   
   function getNeighbors(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //Get our List of directionals
      %north     = getNorthNeighbor(%width,%vector);
      %northEast = getNorthEastNeighbor(%width,%vector);
      %east      = getEastNeighbor(%width,%vector);
      %southEast = getSouthEastNeighbor(%width,%vector);
      %south     = getSouthNeighbor(%width,%vector);
      %southWest = getSouthWestNeighbor(%width,%vector);
      %west      = getWestNeighbor(%width,%vector);
      %northWest = getNorthWestNeighbor(%width,%vector);
      
      //We now have a list of possible move points surrounding our vector.
      return %north SPC %northEast SPC %east SPC %southEast SPC %south SPC %southWest SPC %west SPC %northWest;
   }
  
   //Return North Neighbor  
   function getNorthNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //North
      %northX    = %x ;
      %northY    = %y - %width;
      %north     = %northX SPC %northY;
      return %north;
   }
   
   //return NorthEast Neighbor
   function getNorthEastNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //NorthEast
      %northEastX =  %x + %width;
      %northEastY =  %y - %width;
      %northEast  = %northEastX SPC %northEastY;
      return %northEast;
   }

   //return East Neighbor
   function getEastNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //East
      %eastX = %x + %width;
      %eastY = %y;
      %east = %eastX SPC %eastY;
      return %east;
   }   
 
   //return SouthEast Neighbor
   function getSouthEastNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //SouthEast
      %southEastX = %x + %width;
      %southEastY = %y + %width;
      %southEast = %southEastX SPC %southEastY;
      return %southEast;
   } 
 
   //return South Neighbor
   function getSouthNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //South
      %southX = %x;
      %southY = %y + %width;
      %south = %southX SPC %southY;
      return %south;
   } 

   //return SouthWest Neighbor
   function getSouthWestNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //SouthWest
      %southWestX = %x - %width;
      %southWestY = %y + %width;
      %southWest = %southWestX SPC %southWestY;
      return %southWest;
   } 

   //return West Neighbor
   function getWestNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //West
      %westX = %x - %width;
      %westY = %y;
      %west = %westX SPC %westY;
      return %west;
   }  
 
   //return NorthWest Neighbor
   function getNorthWestNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //NorthWest
      %northWestX = %x - %width;
      %northWestY = %y - %width;
      %northWest = %northWestX SPC %northWestY;
      return %northWest;
   }    
   
 //Cost Methods
   
   //Diagonal ShortCut Method
   function getDSMovementCost(%fromVector,%toVector)
   {
      %cost = 0;

      //Get %obj current X/Y positions.
      %objX=mfloor(getWord(%fromVector,0));
      %objY=mfloor(getWord(%fromVector,1));
   
      //Split out %vector Parts
      %targX=mfloor(getWord(%toVector,0));
      %targY=mfloor(getWord(%toVector,1));
      
      //Calculate absolutes
      %xDistance = mAbs((%objX-%targX));      
      %yDistance = mAbs((%objY-%targY));
      
      //Calculate the move cost
      if (%xDistance > %yDistance)
      {
         %cost = (14*%yDistance)+(10*(%xDistance-%yDistance));   
      } else {
         %cost = (14*%xDistance)+(10*(%yDistance-%xDistance));
      }
      return %cost;
      
   }

   //Manhatten Method
   function getMMMovementCost(%fromVector,%toVector)
   {    
      %cost = 0;
     
      //Get %obj current X/Y positions.
      %objX=mfloor(getWord(%fromVector,0));
      %objY=mfloor(getWord(%fromVector,1));
   
      //Split out %vector Parts
      %targX=mfloor(getWord(%toVector,0));
      %targY=mfloor(getWord(%toVector,1));
     
      %cost=10*(mAbs(%objX-%targX))+(mAbs(%objY-%tarY));
      
      return %cost;
   }

   //use DS and MM and get the average cost.
   //Depending upon the scenario, this might give you better movement..
   function getAverageCost(%fromVector,%toVector)
   {
      %cost = 0;
     
      %dsCost = getDSMovementCost(%fromVector,%toVector);
      %mmCost = getMMMovementCost(%fromVector,%toVector);
      
      %cost = (%dsCost + %mmCost) / 2;
      return %cost;
   }

   //Adds up costs of objects found at specific locations
   function getObjectCost(%sceneGraph,%vector,%width)
   {
      %cost = 0;
      %variant = %width;
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      %x1=%x+%variant;
      %y1=%y-%variant;
      %x2=%x-%variant;
      %y2=%y+%variant;
      %objList  = %sceneGraph.pickRect(%x1 SPC %y1,%x2 SPC %y2);
      %objCount = getWordCount(%objList);
      for(%i;%i<%objCount;%i++)
      {
         %obj = getWord(%objList,%i);
         if (isObject(%obj))
         {
               if (getaStarDebug())
               {
                  echo("Found Object with cost" SPC %obj.cost);
               }
                %cost = %cost + %obj.cost;        
         }
      }
      return %cost;
   }
   
   //Ouch sorry to make this so large, I can break it down further..
   //But I'm really not inclined too since this explains things 
   //better possibly ...
   function findPath(%obj,%toVector,%width,%maxNodes)
   {
      //Our local Path Object
      %path = new ScriptObject(Path)
      {
         name = "Path";
         isSearching = true;
         start = %obj.getPosition(); 
         finish = %toVector;
         found  = false;
         width  = %width;
         object = %obj;
         nodesSearched = 0;
         maxNodes = %maxNodes;
         actualNodes = 0;
         speed       = %obj.getWidth();
         frame       = 0;
         sceneGraph  = %obj.getSceneGraph();
      };
            
      //Node Class
      new ScriptObject(Node)
      {
         parent     = %path.start;
         vector     = "";
         direction  = "none";
         cost       = 0;
         neighbors  = "";
      };
      
      //Starting Node
      new ScriptObject(StartNode : Node)
      {
         superClass = "Node";
         vector     = %path.start;
         parent     = %path.start;
         direction  = "none";
         cost       = getDSMovementCost(%path.start,%toVector); 
         neighbors  = getNeighbors(%path.width,%path.start);
      };
      
      //Setup our parent as the starting node.
      %parent = StartNode;
      
      //Search nodes up to max nodes...
      for(%path.nodesSearched=0; %path.nodesSearched < %path.maxNodes; %path.nodesSearched++) 
      {
         //If we are within the %path.width from the finish vector, stop searching....
         if(t2dVectorCompare(%parent.vector,%toVector,%path.width))
         {
               %path.nodesSearched = %path.maxNodes;
               %path.isSearching = false;
               
         }
         
         //Get North Node from Parent
         %north = new ScriptObject("NodeN"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "north";
            vector     = getNorthNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going north.
         %north.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%north.vector,%path.width) + getDSMovementCost(%north.vector,%toVector);
         
         
         //get NorthEast Node From Parent.
         %northeast = new ScriptObject("NodeNE"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "northeast";
            vector     = getNorthEastNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going NorthEast
         %northeast.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%northeast.vector,%path.width) + getDSMovementCost(%northeast.vector,%toVector);        
                  
         //get East Node From Parent.
         %east = new ScriptObject("NodeE"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "east";
            vector     = getEastNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going East
         %east.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%east.vector,%path.width) + getDSMovementCost(%east.vector,%toVector);        
         
         
          //get SouthEast Node From Parent.
         %southeast = new ScriptObject("NodeSE"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "southeast";
            vector     = getSouthEastNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going SouthEast
         %southeast.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%southeast.vector,%path.width) + getDSMovementCost(%southeast.vector,%toVector);          
         
         
         //get South Node From Parent.
         %south = new ScriptObject("NodeS"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "south";
            vector     = getSouthNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going South
         %south.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%south.vector,%path.width) + getDSMovementCost(%south.vector,%toVector); 

         
         //get SouthWest Node From Parent.
         %southwest = new ScriptObject("NodeSW"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "southwest";
            vector     = getSouthWestNeighbor(%path.width,%parent.vector);
         };
         
         //Get cost of going SouthWest
         %southwest.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%southwest.vector,%path.width) + getDSMovementCost(%southwest.vector,%toVector); 
    
         
         //get West Node From Parent.
         %west = new ScriptObject("NodeW"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "west";
            vector     = getWestNeighbor(%path.width,%parent.vector);
         };
         //Get Cost of Going west.
         %west.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%west.vector,%path.width) + getDSMovementCost(%west.vector,%toVector);       
         
         //get NorthWest Node From Parent.
         %northwest = new ScriptObject("NodeNW"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "northwest";
            vector     = getNorthWestNeighbor(%path.width,%parent.vector);
         };

         //Get cost of Going NorthWest
         %northwest.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%northwest.vector,%path.width) + getDSMovementCost(%northwest.vector,%toVector); 
          
         //reset node check
         $nodeFound = false;
         
         //Weigh F Value North
         if (%north.cost < %northeast.cost &&
             %north.cost < %east.cost      &&
             %north.cost < %southeast.cost &&
             %north.cost < %south.cost     &&
             %north.cost < %southwest.cost &&
             %north.cost < %west.cost      &&
             %north.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("North Cheapest Cost at" SPC %north.cost);
            }
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %north;
            %path.nodes[%path.nodesSearched] = %north;
            $nodeFound = true;
            %path.actualNodes++;
         }
         
         //Weigh F Value Northeast
         if (%northeast.cost < %north.cost     &&
             %northeast.cost < %east.cost      &&
             %northeast.cost < %southeast.cost &&
             %northeast.cost < %south.cost     &&
             %northeast.cost < %southwest.cost &&
             %northeast.cost < %west.cost      &&
             %northeast.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("NorthEast Cheapest Cost at" SPC %northeast.cost);
            }
            %north.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %northeast;
            %path.nodes[%path.nodesSearched] = %northeast;
            $nodeFound = true;
            %path.actualNodes++;
         }         

         //Weigh F Value East
         if (%east.cost < %north.cost     &&
             %east.cost < %northeast.cost &&
             %east.cost < %southeast.cost &&
             %east.cost < %south.cost     &&
             %east.cost < %southwest.cost &&
             %east.cost < %west.cost      &&
             %east.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("East Cheapest Cost at" SPC %east.cost);
            }
            %north.delete();
            %northeast.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %east;
            %path.nodes[%path.nodesSearched] = %east;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value SouthEast
         if (%southeast.cost < %north.cost     &&
             %southeast.cost < %northeast.cost &&
             %southeast.cost < %east.cost      &&
             %southeast.cost < %south.cost     &&
             %southeast.cost < %southwest.cost &&
             %southeast.cost < %west.cost      &&
             %southeast.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("SouthEast Cheapest Cost at" SPC %southeast.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %southeast;
            %path.nodes[%path.nodesSearched] = %southeast;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value South
         if (%south.cost < %north.cost     &&
             %south.cost < %northeast.cost &&
             %south.cost < %east.cost      &&
             %south.cost < %southeast.cost &&
             %south.cost < %southwest.cost &&
             %south.cost < %west.cost      &&
             %south.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("South Cheapest Cost at" SPC %south.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %south;
            %path.nodes[%path.nodesSearched] = %south;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value SouthWest
         if (%southwest.cost < %north.cost     &&
             %southwest.cost < %northeast.cost &&
             %southwest.cost < %east.cost      &&
             %southwest.cost < %southeast.cost &&
             %southwest.cost < %south.cost     &&
             %southwest.cost < %west.cost      &&
             %southwest.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("SouthWest Cheapest Cost at" SPC %southwest.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %west.delete();
            %northwest.delete();
            %parent = %southwest;
            %path.nodes[%path.nodesSearched] = %southwest;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value West
         if (%west.cost < %north.cost     &&
             %west.cost < %northeast.cost &&
             %west.cost < %east.cost      &&
             %west.cost < %southeast.cost &&
             %west.cost < %south.cost     &&
             %west.cost < %southwest.cost &&
             %west.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("West Cheapest Cost at" SPC %west.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %northwest.delete();
            %parent = %west;
            %path.nodes[%path.nodesSearched] = %west;
            $nodeFound = true;
            %path.actualNodes++;
         }

         //Weigh F Value NorthWest
         if (%northwest.cost < %north.cost     &&
             %northwest.cost < %northeast.cost &&
             %northwest.cost < %east.cost      &&
             %northwest.cost < %southeast.cost &&
             %northwest.cost < %south.cost     &&
             %northwest.cost < %southwest.cost &&
             %northwest.cost < %west.cost)
         {
            if (getaStarDebug())
            {
               echo("NorthWest Cheapest Cost at" SPC %northwest.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %parent = %northwest;
            %path.nodes[%path.nodesSearched] = %northwest;
            $nodeFound = true;
            %path.actualNodes++;
         }
         
         //Something must have came up weighing the same... 
         //For my purposes if it was equal to a diagonal,
         //I'll pick the diagonal for more natural movement
         //and just check my N,E,S,W vs Diagonals
         
         if ($nodeFound == false)
         {
              switch ($north.cost)
              {
                  case $northeast.cost:
                  if (getaStarDebug())
                  {
                     echo("NorthEast Override Cost at" SPC %northeast.cost);
                  }
                  %north.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %northeast;
                  %path.nodes[%path.nodesSearched] = %northeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $northwest.cost:
                  if (getaStarDebug())
                  {
                     echo("NorthWest Override Cost at" SPC %northwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %parent = %northwest;
                  %path.nodes[%path.nodesSearched] = %northwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }
           
              switch ($south.cost)
              {
                  case $southeast.cost:
                  if (getaStarDebug())
                  {
                     echo("SouthEast Override Cost at" SPC %southeast.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southeast;
                  %path.nodes[%path.nodesSearched] = %southeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $southwest.cost:
                  if (getaStarDebug())
                  {
                     echo("SouthWest Override Cost at" SPC %southwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southwest;
                  %path.nodes[%path.nodesSearched] = %southwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }

              switch ($west.cost)
              {
                  case $southwest.cost:
                  if (getaStarDebug())
                  {
                    echo("SouthWest Override Cost at" SPC %southwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southwest;
                  %path.nodes[%path.nodesSearched] = %southwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $northwest.cost:
                  if (getaStarDebug())
                  {
                    echo("NorthWest Override Cost at" SPC %northwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %parent = %northwest;
                  %path.nodes[%path.nodesSearched] = %northwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }

              switch ($east.cost)
              {
                  case $southeast.cost:
                  if (getaStarDebug())
                  {
                    echo("SouthEast Override Cost at" SPC %southeast.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southeast;
                  %path.nodes[%path.nodesSearched] = %southeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $northeast.cost:
                  if (getaStarDebug())
                  {
                    echo("NorthEast Override Cost at" SPC %northeast.cost);
                  }
                  %north.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %northeast;
                  %path.nodes[%path.nodesSearched] = %northeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }
              
         }

      }
      if (getaStarDebug())
      {
         echo("Search Completed");
      }
      return %path;
   }
   
   //for the debug stuff.
   //make sure you have t2dStaticSprites 
   //Named
   //northImageMap,northeastImageMap, etc...
   function moveToAstar(%obj,%path,%speed)
   {
      //debug is turned on, draw the path on screen.
      if(getaStarDebug())
      {
         for(%step=0; %step < %path.actualNodes; %step++) 
         {
            %node = %path.nodes[%step];
               if(isObject(%node))
               {  
                  %sprite = drawSpriteAtVector(%node.direction@"ImageMap",%node.vector,1,%obj.getSceneGraph());
                  %sprite.setLifetime(20);
               }
         }
      }
      %node = %path.nodes[%path.frame];
      if (isObject(%node)&& isObject(%obj))
      {
         %obj.setOrientation(%node.direction);
         %obj.direction = %node.direction;
         %obj.moveTo(%node.vector,%speed,true,true);
      }
      $path = %path;
   }
};


I warned you :-)
Now lets Break this down some into chewable Chunks.
Debug State

   //Return Debug State
   
   function getaStarDebug()
   {
      return $aStarDebug;      
   }
 
   //set Debug State
   
   function setaStarDebug(%val)
   {
            $aStarDebug = %val;
            return getaStarDebug();
   }
   

This gives you ability after the package is activated to to turn on Astar Dump messages to the console, and turn on the neat blue arrows showing the path. You'll have to have the following image maps in place to get the arrows to show up..

northImageMap
northeastImageMap
eastImageMap
southeastImageMap
southImageMap
southwestImageMap
westImageMap
northwestImageMap

Whatever images you want are fine as long as you name them this because I assume you have them during debug.

getNeighbors()

   //given a sprite width, and a sceneGraph vector
   //we'll calculate neighbors for 
   //an 8 way directional the centers of each being that width away
   //N,NE,E,SE,S,SW,W,NW
   //and return a 16 element vector of their X/Y positions
   //I mostly use this for running scenarios from other script.
   //but Its here if you need it.
   
   function getNeighbors(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //Get our List of directionals
      %north     = getNorthNeighbor(%width,%vector);
      %northEast = getNorthEastNeighbor(%width,%vector);
      %east      = getEastNeighbor(%width,%vector);
      %southEast = getSouthEastNeighbor(%width,%vector);
      %south     = getSouthNeighbor(%width,%vector);
      %southWest = getSouthWestNeighbor(%width,%vector);
      %west      = getWestNeighbor(%width,%vector);
      %northWest = getNorthWestNeighbor(%width,%vector);
      
      //We now have a list of possible move points surrounding our vector.
      return %north SPC %northEast SPC %east SPC %southEast SPC %south SPC %southWest SPC %west SPC %northWest;
   }

All were really doing here is calling our Neighbor Functions from one place to get a 16x vector of neighbors surrounding a given vector.
Now lets take a look at our neighbor functions
I'm not going to reiterate every one of them, they all work the same way except for which direction they are checking in.

   //Return North Neighbor  
   function getNorthNeighbor(%width,%vector)
   {
      //Rip out our x and y 
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      
      //North
      %northX    = %x ;
      %northY    = %y - %width;
      %north     = %northX SPC %northY;
      return %north;
   }

here given a width, we'll search for a vector that many world units north and return that vector.

Cost Methods

   //Diagonal ShortCut Method
   function getDSMovementCost(%fromVector,%toVector)
   {
      %cost = 0;

      //Get %obj current X/Y positions.
      %objX=mfloor(getWord(%fromVector,0));
      %objY=mfloor(getWord(%fromVector,1));
   
      //Split out %vector Parts
      %targX=mfloor(getWord(%toVector,0));
      %targY=mfloor(getWord(%toVector,1));
      
      //Calculate absolutes
      %xDistance = mAbs((%objX-%targX));      
      %yDistance = mAbs((%objY-%targY));
      
      //Calculate the move cost
      if (%xDistance > %yDistance)
      {
         %cost = (14*%yDistance)+(10*(%xDistance-%yDistance));   
      } else {
         %cost = (14*%xDistance)+(10*(%yDistance-%xDistance));
      }
      return %cost;
      
   }

Here we weigh the cost of moving in a direction. This is a pretty standard Diagonal ShortCut method.. we are just doing some simple math, and adding 14 for diagonal movements, or 10 for straight N,W,E,S moves.


   //Manhatten Method
   function getMMMovementCost(%fromVector,%toVector)
   {    
      %cost = 0;
     
      //Get %obj current X/Y positions.
      %objX=mfloor(getWord(%fromVector,0));
      %objY=mfloor(getWord(%fromVector,1));
   
      //Split out %vector Parts
      %targX=mfloor(getWord(%toVector,0));
      %targY=mfloor(getWord(%toVector,1));
     
      %cost=10*(mAbs(%objX-%targX))+(mAbs(%objY-%tarY));
      
      return %cost;
   }

Same as above but using the shorter Manhatten Method..

   //use DS and MM and get the average cost.
   //Depending upon the scenario, this might give you better movement..
   function getAverageCost(%fromVector,%toVector)
   {
      %cost = 0;
     
      %dsCost = getDSMovementCost(%fromVector,%toVector);
      %mmCost = getMMMovementCost(%fromVector,%toVector);
      
      %cost = (%dsCost + %mmCost) / 2;
      return %cost;
   }

Use both methods, and average them for the cost...*Your mileage may vary
Additional Costing

   //Adds up costs of objects found at specific locations
   function getObjectCost(%sceneGraph,%vector,%width)
   {
      %cost = 0;
      %variant = %width;
      %x = getWord(%vector,0);
      %y = getWord(%vector,1);
      %x1=%x+%variant;
      %y1=%y-%variant;
      %x2=%x-%variant;
      %y2=%y+%variant;
      %objList  = %sceneGraph.pickRect(%x1 SPC %y1,%x2 SPC %y2);
      %objCount = getWordCount(%objList);
      for(%i;%i<%objCount;%i++)
      {
         %obj = getWord(%objList,%i);
         if (isObject(%obj))
         {
               if (getaStarDebug())
               {
                  echo("Found Object with cost" SPC %obj.cost);
               }
                %cost = %cost + %obj.cost;        
         }
      }
      return %cost;
   }

Here were grabbing a pickRect from the scenegraph, looking for objects, and if they have a costs enumerating them, and returning the total cost...

findPath -- 1 word "ug"

   //Ouch sorry to make this so large, I can break it down further..
   //But I'm really not inclined too since this explains things 
   //better possibly ...
   function findPath(%obj,%toVector,%width,%maxNodes)
   {
      //Our local Path Object
      %path = new ScriptObject(Path)
      {
         name = "Path";
         isSearching = true;
         start = %obj.getPosition(); 
         finish = %toVector;
         found  = false;
         width  = %width;
         object = %obj;
         nodesSearched = 0;
         maxNodes = %maxNodes;
         actualNodes = 0;
         speed       = %obj.getWidth();
         frame       = 0;
         sceneGraph  = %obj.getSceneGraph();
      };
            
      //Node Class
      new ScriptObject(Node)
      {
         parent     = %path.start;
         vector     = "";
         direction  = "none";
         cost       = 0;
         neighbors  = "";
      };
      
      //Starting Node
      new ScriptObject(StartNode : Node)
      {
         superClass = "Node";
         vector     = %path.start;
         parent     = %path.start;
         direction  = "none";
         cost       = getDSMovementCost(%path.start,%toVector); 
         neighbors  = getNeighbors(%path.width,%path.start);
      };
      
      //Setup our parent as the starting node.
      %parent = StartNode;
      
      //Search nodes up to max nodes...
      for(%path.nodesSearched=0; %path.nodesSearched < %path.maxNodes; %path.nodesSearched++) 
      {
         //If we are within the %path.width from the finish vector, stop searching....
         if(t2dVectorCompare(%parent.vector,%toVector,%path.width))
         {
               %path.nodesSearched = %path.maxNodes;
               %path.isSearching = false;
               
         }
         
         //Get North Node from Parent
         %north = new ScriptObject("NodeN"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "north";
            vector     = getNorthNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going north.
         %north.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%north.vector,%path.width) + getDSMovementCost(%north.vector,%toVector);
         
         
         //get NorthEast Node From Parent.
         %northeast = new ScriptObject("NodeNE"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "northeast";
            vector     = getNorthEastNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going NorthEast
         %northeast.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%northeast.vector,%path.width) + getDSMovementCost(%northeast.vector,%toVector);        
                  
         //get East Node From Parent.
         %east = new ScriptObject("NodeE"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "east";
            vector     = getEastNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going East
         %east.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%east.vector,%path.width) + getDSMovementCost(%east.vector,%toVector);        
         
         
          //get SouthEast Node From Parent.
         %southeast = new ScriptObject("NodeSE"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "southeast";
            vector     = getSouthEastNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going SouthEast
         %southeast.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%southeast.vector,%path.width) + getDSMovementCost(%southeast.vector,%toVector);          
         
         
         //get South Node From Parent.
         %south = new ScriptObject("NodeS"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "south";
            vector     = getSouthNeighbor(%path.width,%parent.vector);
         };
         
         //Get Cost of Going South
         %south.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%south.vector,%path.width) + getDSMovementCost(%south.vector,%toVector); 

         
         //get SouthWest Node From Parent.
         %southwest = new ScriptObject("NodeSW"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "southwest";
            vector     = getSouthWestNeighbor(%path.width,%parent.vector);
         };
         
         //Get cost of going SouthWest
         %southwest.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%southwest.vector,%path.width) + getDSMovementCost(%southwest.vector,%toVector); 
    
         
         //get West Node From Parent.
         %west = new ScriptObject("NodeW"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "west";
            vector     = getWestNeighbor(%path.width,%parent.vector);
         };
         //Get Cost of Going west.
         %west.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%west.vector,%path.width) + getDSMovementCost(%west.vector,%toVector);       
         
         //get NorthWest Node From Parent.
         %northwest = new ScriptObject("NodeNW"@%path.nodesSearched : Node)
         {
            superClass = "Node";
            parent     = %parent;
            direction  = "northwest";
            vector     = getNorthWestNeighbor(%path.width,%parent.vector);
         };

         //Get cost of Going NorthWest
         %northwest.cost   = %parent.cost + getObjectCost(%path.sceneGraph,%northwest.vector,%path.width) + getDSMovementCost(%northwest.vector,%toVector); 
          
         //reset node check
         $nodeFound = false;
         
         //Weigh F Value North
         if (%north.cost < %northeast.cost &&
             %north.cost < %east.cost      &&
             %north.cost < %southeast.cost &&
             %north.cost < %south.cost     &&
             %north.cost < %southwest.cost &&
             %north.cost < %west.cost      &&
             %north.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("North Cheapest Cost at" SPC %north.cost);
            }
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %north;
            %path.nodes[%path.nodesSearched] = %north;
            $nodeFound = true;
            %path.actualNodes++;
         }
         
         //Weigh F Value Northeast
         if (%northeast.cost < %north.cost     &&
             %northeast.cost < %east.cost      &&
             %northeast.cost < %southeast.cost &&
             %northeast.cost < %south.cost     &&
             %northeast.cost < %southwest.cost &&
             %northeast.cost < %west.cost      &&
             %northeast.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("NorthEast Cheapest Cost at" SPC %northeast.cost);
            }
            %north.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %northeast;
            %path.nodes[%path.nodesSearched] = %northeast;
            $nodeFound = true;
            %path.actualNodes++;
         }         

         //Weigh F Value East
         if (%east.cost < %north.cost     &&
             %east.cost < %northeast.cost &&
             %east.cost < %southeast.cost &&
             %east.cost < %south.cost     &&
             %east.cost < %southwest.cost &&
             %east.cost < %west.cost      &&
             %east.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("East Cheapest Cost at" SPC %east.cost);
            }
            %north.delete();
            %northeast.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %east;
            %path.nodes[%path.nodesSearched] = %east;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value SouthEast
         if (%southeast.cost < %north.cost     &&
             %southeast.cost < %northeast.cost &&
             %southeast.cost < %east.cost      &&
             %southeast.cost < %south.cost     &&
             %southeast.cost < %southwest.cost &&
             %southeast.cost < %west.cost      &&
             %southeast.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("SouthEast Cheapest Cost at" SPC %southeast.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %southeast;
            %path.nodes[%path.nodesSearched] = %southeast;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value South
         if (%south.cost < %north.cost     &&
             %south.cost < %northeast.cost &&
             %south.cost < %east.cost      &&
             %south.cost < %southeast.cost &&
             %south.cost < %southwest.cost &&
             %south.cost < %west.cost      &&
             %south.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("South Cheapest Cost at" SPC %south.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %southwest.delete();
            %west.delete();
            %northwest.delete();
            %parent = %south;
            %path.nodes[%path.nodesSearched] = %south;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value SouthWest
         if (%southwest.cost < %north.cost     &&
             %southwest.cost < %northeast.cost &&
             %southwest.cost < %east.cost      &&
             %southwest.cost < %southeast.cost &&
             %southwest.cost < %south.cost     &&
             %southwest.cost < %west.cost      &&
             %southwest.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("SouthWest Cheapest Cost at" SPC %southwest.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %west.delete();
            %northwest.delete();
            %parent = %southwest;
            %path.nodes[%path.nodesSearched] = %southwest;
            $nodeFound = true;
            %path.actualNodes++;
         } 

         //Weigh F Value West
         if (%west.cost < %north.cost     &&
             %west.cost < %northeast.cost &&
             %west.cost < %east.cost      &&
             %west.cost < %southeast.cost &&
             %west.cost < %south.cost     &&
             %west.cost < %southwest.cost &&
             %west.cost < %northwest.cost)
         {
            if (getaStarDebug())
            {
               echo("West Cheapest Cost at" SPC %west.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %northwest.delete();
            %parent = %west;
            %path.nodes[%path.nodesSearched] = %west;
            $nodeFound = true;
            %path.actualNodes++;
         }

         //Weigh F Value NorthWest
         if (%northwest.cost < %north.cost     &&
             %northwest.cost < %northeast.cost &&
             %northwest.cost < %east.cost      &&
             %northwest.cost < %southeast.cost &&
             %northwest.cost < %south.cost     &&
             %northwest.cost < %southwest.cost &&
             %northwest.cost < %west.cost)
         {
            if (getaStarDebug())
            {
               echo("NorthWest Cheapest Cost at" SPC %northwest.cost);
            }
            %north.delete();
            %northeast.delete();
            %east.delete();
            %southeast.delete();
            %south.delete();
            %southwest.delete();
            %west.delete();
            %parent = %northwest;
            %path.nodes[%path.nodesSearched] = %northwest;
            $nodeFound = true;
            %path.actualNodes++;
         }
         
         //Something must have came up weighing the same... 
         //For my purposes if it was equal to a diagonal,
         //I'll pick the diagonal for more natural movement
         //and just check my N,E,S,W vs Diagonals
         
         if ($nodeFound = false)
         {
              switch ($north.cost)
              {
                  case $northeast.cost:
                  if (getaStarDebug())
                  {
                     echo("NorthEast Override Cost at" SPC %northeast.cost);
                  }
                  %north.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %northeast;
                  %path.nodes[%path.nodesSearched] = %northeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $northwest.cost:
                  if (getaStarDebug())
                  {
                     echo("NorthWest Override Cost at" SPC %northwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %parent = %northwest;
                  %path.nodes[%path.nodesSearched] = %northwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }
           
              switch ($south.cost)
              {
                  case $southeast.cost:
                  if (getaStarDebug())
                  {
                     echo("SouthEast Override Cost at" SPC %southeast.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southeast;
                  %path.nodes[%path.nodesSearched] = %southeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $southwest.cost:
                  if (getaStarDebug())
                  {
                     echo("SouthWest Override Cost at" SPC %southwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southwest;
                  %path.nodes[%path.nodesSearched] = %southwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }

              switch ($west.cost)
              {
                  case $southwest.cost:
                  if (getaStarDebug())
                  {
                    echo("SouthWest Override Cost at" SPC %southwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southwest;
                  %path.nodes[%path.nodesSearched] = %southwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $northwest.cost:
                  if (getaStarDebug())
                  {
                    echo("NorthWest Override Cost at" SPC %northwest.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %parent = %northwest;
                  %path.nodes[%path.nodesSearched] = %northwest;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }

              switch ($east.cost)
              {
                  case $southeast.cost:
                  if (getaStarDebug())
                  {
                    echo("SouthEast Override Cost at" SPC %southeast.cost);
                  }
                  %north.delete();
                  %northeast.delete();
                  %east.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %southeast;
                  %path.nodes[%path.nodesSearched] = %southeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
                  case $northeast.cost:
                  if (getaStarDebug())
                  {
                    echo("NorthEast Override Cost at" SPC %northeast.cost);
                  }
                  %north.delete();
                  %east.delete();
                  %southeast.delete();
                  %south.delete();
                  %southwest.delete();
                  %west.delete();
                  %northwest.delete();
                  %parent = %northeast;
                  %path.nodes[%path.nodesSearched] = %northeast;
                  $nodeFound = true;
                  %path.actualNodes++;
                  break;
              }
              
         }

      }
      if (getaStarDebug())
      {
         echo("Search Completed");
      }
      return %path;
   }
  

Ok here we create the %path object thats going to hold our path, build up a node scriptObject as well, setup our StartNode from the objects getPosition(). then we start pathwalking, either until we get "really" close to the object or run out of nodes we allow with the MaxNodes variable.
The only interesting things to note here are if we dont have a node that stands out (or basically if two nodes work the same), were going to pick diagonals over N,S,E,W, I think it gives a more natural movement..
When completed it returns a proper %path ScriptObject to moveToAstar's required Path.
moveToAstar

   //for the debug stuff.
   //make sure you have t2dStaticSprites 
   //Named
   //northImageMap,northeastImageMap, etc...
   function moveToAstar(%obj,%path,%speed)
   {
      //debug is turned on, draw the path on screen.
      if(getaStarDebug())
      {
         for(%step=0; %step < %path.actualNodes; %step++) 
         {
            %node = %path.nodes[%step];
               if(isObject(%node))
               {  
                  %sprite = drawSpriteAtVector(%node.direction@"ImageMap",%node.vector,1,%obj.getSceneGraph());
                  %sprite.setLifetime(20);
               }
         }
      }
      %node = %path.nodes[%path.frame];
      if (isObject(%node)&& isObject(%obj))
      {
         %obj.setOrientation(%node.direction);
         %obj.direction = %node.direction;
         %obj.moveTo(%node.vector,%speed,true,true);
      }
      $path = %path;
   }

here you will notice a couple of things really the majority of this function deals with drawing out our path in debug mode..
but it does trigger the first path.node, calls an object function setOrientation , which I will show you below, to turn the sprite before it starts the directional walks. then it really just calls moveTo with callbacks turned on.
The rest of the magic works with normal sprite callbacks, and our special setOrientation function
setOrientation

function cow::setOrientation(%this,%direction)
{
     %this.setAnimation(%direction @"cowWalk"); 
}

Yep thats it, just set our animation, my sprites are looping for this test, but you might want to do more animation work here!
The last piece of the puzzle comes in the cow onPositionTarget callback

function cow::onPositionTarget(%this)
{
   if ($path.frame < $path.actualNodes + 1)
   {

      $path.frame++;
      %node = $path.nodes[$path.frame];
      if(isObject(%node))
      {
        %this.setOrientation(%node.direction);
         %this.moveTo(%node.vector,$path.speed,true,true,true,0);
         %node.delete();
      }
   }
}

here were walking the array of nodes from our Path ScriptObjects nodes array, and removing the %node on each iteration.

You'll notice a little SpriteBlotter function I use to draw the arrows with %sprite drawSpriteAtVector. this is just a little helper function I use.. But here it is..

   function drawSpriteAtVector(%imageMap,%vector,%width,%sceneGraph)
   {
      %sprite=new t2dStaticSprite() {};
         %sprite.imageMap = %imageMap;
         %sprite.position = %vector;
         %sprite.size = %width SPC %width;
         %sprite.visible = true;
         %sceneGraph.add(%sprite);
         return %sprite;
   }


Thats about it, I'm hoping others find and or use this , and submit changes , fixes, or bug reports for me to look into
Hope this was as much fun for you as it was for me :-)
- Rodney
I'll leave you with a few more examples.
Image:t2d-AI-ShowPath3.png
Image:t2d-AI-ShowPath4.png