TGB/Source/Pathfinding
From TDN
|
[edit] Introduction
t2dAnimatedSprite
In these examples , I have built a set of t2dAnimatedSprites with 8 way orientation, North,NorthEast,East,SouthEast,South,SouthWest,West,and NorthWest.
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..
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);
}
cow
findPath(cow,%x SPC %y,mfloor(cow.getWidth() /2)
mfloor(cow.getWidth()/2)
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..
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;
}
};
//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.
//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
//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.
//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..
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!
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.
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;
}
|







