Due to some limitations right now, making this behave just like you want it to requires some somewhat ugly tweaks.
The cost of a path is defined as:
sum(traversalProvider.GetTraversalCost(node) for node in path) +
sum(connection cost between each adjacent node in path)
There are two things that need tweaking:
I don’t think you want to consider the movement cost for the start node, right? In the example code below, I have compensated for that by returning 0 for the start node.
The connection cost between nodes can currently not be modified by the ITraversalProvider. This is something I’m working on improving. However, we can compensate for it by subtracting the default connection cost when we run the ITraversalProvider.GetTraversalCost method. This is pretty ugly, but it works for your use case.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public class MovementPointTest : MonoBehaviour {
public int movementPoints = 2;
class MyCustomTraversalProvider : ITraversalProvider {
public uint defaultCostToMoveBetweenTwoNodes;
public bool CanTraverse(Path path, GraphNode node) {
return DefaultITraversalProvider.CanTraverse(path, node);
}
public uint GetTraversalCost(Path path, GraphNode node) {
if (node == (path as ConstantPath).startNode) return 0;
uint c = 0;
if (node.Tag == 0) {
c = 1000;
} else if (node.Tag == 1) {
c = 2000;
} else if (node.Tag == 2) {
c = 4000;
}
return (uint)(c - defaultCostToMoveBetweenTwoNodes);
}
}
void Update() {
var defaultCostToMoveBetweenTwoNodes = AstarPath.active.data.gridGraph.neighbourCosts[0];
var maxGScore = 1000 * movementPoints;
// +1 to make the path find all nodes up to *and including* the max g score
maxGScore += 1;
ConstantPath path = ConstantPath.Construct(transform.position, maxGScore, null);
path.traversalProvider = new MyCustomTraversalProvider() { defaultCostToMoveBetweenTwoNodes = defaultCostToMoveBetweenTwoNodes };
AstarPath.StartPath(path);
path.BlockUntilCalculated();
var allNodes = path.allNodes;
foreach (var node in allNodes) {
Pathfinding.Drawing.Draw.SolidBox((Vector3)node.position, Vector3.one * 0.5f, Color.red);
}
}
}
It will indeed. But you you want to post-process the path using the Seeker’s modifiers you can use the seeker.PostProcess(path) method.
See Seeker - A* Pathfinding Project
You can put the block manager’s traversal provider as a field inside your own custom traversal provider. And then just forward the CanTraverse call to it.
Hi, thank to your support, I have created CustomTraversalProvider to suite my need as below
public class CustomTraversalProvider : ITraversalProvider {
private uint _defaultCostToMoveBetweenTwoNodes = AstarPath.active.data.gridGraph.neighbourCosts[0];
private ITraversalProvider _blockManagerTraversalProvider;
public CustomTraversalProvider(ITraversalProvider blockManagerTraversalProvider) {
_blockManagerTraversalProvider = blockManagerTraversalProvider;
}
public bool CanTraverse(Path path, GraphNode node) {
return _blockManagerTraversalProvider.CanTraverse(path, node);
}
public uint GetTraversalCost(Path path, GraphNode node) {
if (path is ConstantPath && node == (path as ConstantPath).startNode) return 0;
if (path is ABPath && node == (path as ABPath).startNode) return 0;
uint cost = 0;
if (node.Tag == 0) {
cost = 1000;
} else if (node.Tag == 1) {
cost = 2000;
}
return cost - _defaultCostToMoveBetweenTwoNodes;
}
}
It works perfectly for now, but I have encountered another problem relate to BlockManager.
Following document, I have attached 2 components into my Unit which are SingleNodeBlocker and UnitController, both of them have field public BlockManager BlockManager; which will be assign by Drag and Drop in Editor.
But when making my unit into a Prefab, the BlockManager can’t be assigned anymore, I can modify my UnitController to solve this but what about SingleNodeBlocker ?
How do you usually apply Blocking nodes method for prefab case ?
This is more of a general Unity question of how to handle prefabs.
Generally, you’d use a script to assign this reference at the same time that you instantiate the object into your scene.