Hi, I’m using RecastGraph and I’d like to extend a slightly more specific path type from ABPath.
I want to give more weight under certain conditions when searching for path.
This requires overriding the Open(function) of TriangleMeshNode.
So I copied the Open function from TriangleMeshNode to the new Path Type with hardcoding and added a line of code that I needed.
But when I installed the Astar with Unity package, it became impossible.
What approach should I take to solve this problem?
Whenever a new version is released, it would be too cumbersome and problematic to copy and install the package again.
Finally, I attach the New Path that I made.
Thank you.
public interface IAuthTraversalProvider
{
bool IsAuthed (GraphNode start, GraphNode end);
}
public class AuthedPath : XPath
{
public AuthedPath () { }
public IAuthTraversalProvider authTraversalProvider;
public new static AuthedPath Construct (Vector3 start, Vector3 end, OnPathDelegate callback = null)
{
var p = PathPool.GetPath<AuthedPath> ();
p.Setup (start, end, callback);
p.endingCondition = new ABPathEndingCondition (p);
return p;
}
protected override void CalculateStep (long targetTick) {
int counter = 0;
// Continue to search as long as we haven't encountered an error and we haven't found the target
while (CompleteState == PathCompleteState.NotCalculated) {
searchedNodes++;
// Close the current node, if the current node is the target node then the path is finished
if (endingCondition.TargetFound(currentR)) {
CompleteState = PathCompleteState.Complete;
break;
}
// Loop through all walkable neighbours of the node and add them to the open list.
Open(currentR.node as MeshNode, this, currentR, pathHandler);
// Any nodes left to search?
if (pathHandler.heap.isEmpty) {
FailWithError("Searched whole area but could not find target");
return;
}
// Select the node with the lowest F score and remove it from the open list
currentR = pathHandler.heap.Remove();
// Check for time every 500 nodes, roughly every 0.5 ms usually
if (counter > 500) {
// Have we exceded the maxFrameTime, if so we should wait one frame before continuing the search since we don't want the game to lag
if (System.DateTime.UtcNow.Ticks >= targetTick) {
//Return instead of yield'ing, a separate function handles the yield (CalculatePaths)
return;
}
counter = 0;
if (searchedNodes > 1000000) {
throw new System.Exception("Probable infinite loop. Over 1,000,000 nodes searched");
}
}
counter++;
}
if (CompleteState == PathCompleteState.Complete) {
ChangeEndNode(currentR.node);
Trace(currentR);
}
}
public void Open (MeshNode meshNode, Path path, PathNode pathNode, PathHandler handler)
{
if (meshNode.connections == null) return;
// Flag2 indicates if this node needs special treatment
// with regard to connection costs
bool flag2 = pathNode.flag2;
// Loop through all connections
for (int i = meshNode.connections.Length - 1; i >= 0; i--)
{
var conn = meshNode.connections[i];
var other = conn.node;
// Make sure we can traverse the neighbour
if (path.CanTraverse (conn.node))
{
PathNode pathOther = handler.GetPathNode (conn.node);
// Fast path out, worth it for triangle mesh nodes since they usually have degree 2 or 3
if (pathOther == pathNode.parent)
{
continue;
}
if (!authTraversalProvider.IsAuthed (meshNode, conn.node))
continue;
uint cost = conn.cost;
if (flag2 || pathOther.flag2)
{
// Get special connection cost from the path
// This is used by the start and end nodes
cost = path.GetConnectionSpecialCost (meshNode, conn.node, cost);
}
// Test if we have seen the other node before
if (pathOther.pathID != handler.PathID)
{
// We have not seen the other node before
// So the path from the start through this node to the other node
// must be the shortest one so far
// Might not be assigned
pathOther.node = conn.node;
pathOther.parent = pathNode;
pathOther.pathID = handler.PathID;
pathOther.cost = cost;
pathOther.H = path.CalculateHScore (other);
pathOther.UpdateG (path);
handler.heap.Add (pathOther);
}
else
{
// If not we can test if the path from this node to the other one is a better one than the one already used
if (pathNode.G + cost + path.GetTraversalCost (other) < pathOther.G)
{
pathOther.cost = cost;
pathOther.parent = pathNode;
other.UpdateRecursiveG (path, pathOther, handler);
}
}
}
}
}
/// <summary>
/// Changes the <see cref="endNode"/> to target and resets some temporary flags on the previous node.
/// Also sets <see cref="endPoint"/> to the position of target.
/// </summary>
void ChangeEndNode (GraphNode target)
{
// Reset temporary flags on the previous end node, otherwise they might be
// left in the graph and cause other paths to calculate paths incorrectly
if (endNode != null && endNode != startNode)
{
var pathNode = pathHandler.GetPathNode (endNode);
pathNode.flag1 = pathNode.flag2 = false;
}
endNode = target;
endPoint = (Vector3)target.position;
}
}
(Psuedo version)
public interface IAuthTraversalProvider
{
bool IsAuthed (GraphNode start, GraphNode end);
}
public class AuthedPath : XPath
{
public AuthedPath () { }
public IAuthTraversalProvider authTraversalProvider;
public new static AuthedPath Construct (Vector3 start, Vector3 end, OnPathDelegate callback = null)
{
~~~~~~~
}
protected override void CalculateStep (long targetTick) {
while (CompleteState == PathCompleteState.NotCalculated) {
searchedNodes++;
// Continue to search as long as we haven't encountered an error and we haven't found the target
// I want to override this method..!!
Open(currentR.node as MeshNode, this, currentR, pathHandler);
// Any nodes left to search?
// Select the node with the lowest F score and remove it from the open list
// Check for time every 500 nodes, roughly every 0.5 ms usually
}
if (CompleteState == PathCompleteState.Complete) {
ChangeEndNode(currentR.node);
Trace(currentR);
}
}
public void Open (MeshNode meshNode, Path path, PathNode pathNode, PathHandler handler)
{
// codes for TriangleMeshNode
// Loop through all connections
for (int i = meshNode.connections.Length - 1; i >= 0; i--)
{
var conn = meshNode.connections[i];
var other = conn.node;
// Make sure we can traverse the neighbour
if (path.CanTraverse (conn.node))
{
~~~~~~~~
// added condition for check!!
if (!authTraversalProvider.IsAuthed (meshNode, conn.node))
continue;
~~~~~~~~
}
}
}
}