I have a “Free mode” in my Turn Base Game where I want select 3-4 Units and move them to a single LevelGridNode. Currently, I sequential calculate the path, assign it to AILerp and every Unit moves to the same node.
Now I want to create some sort of avoidance. My train of though:
Click on the Target Node
Calculate the path for the first unit
Make the node unwalkable with a programmatically SingleNodeBlocker
Calculate the path for the second unit. Now that the original target node is unwalkable, I use GetNearest with walkable constraints to get next one.
And so one
Is this a good approach?
If yes, how do I create a block at the target position? Should I instantiate a new SingleNodeBlocker at the target position and add it to my obstacles? This seems cumbersome.
Or maybe I think too complicated
Sorry for the late reply.
Yes, this seems like a good solution. If you don’t want to use SingleNodeBlocker components you can implement your own ITraversalProvider and use whichever datastructure you desire (e.g. just a simple list of nodes). The interface only requires you to provide a few methods like “is this node walkable”.
Ah, that’s a good idea. I created a simple TraversalProvider that only contains a simple list of blocked nodes. On CanTraverse I just check return !blockedNodes.Contains(node);. This is my implementation to get multiple targetNodes:
public Dictionary<BaseUnit, GraphNode> GetNodesInRadius(LevelGridNode targetGridNode, List<BaseUnit> selectedUnits)
{
// My traversalProvider
UnitTraversalProvider traversalProvider = new();
// This will be returned, when done, every Unit will have it's own targetNode
Dictionary<BaseUnit, GraphNode> nodes = new Dictionary<BaseUnit, GraphNode>();
// I iterate over every unit to calculate the the actual targetNode
foreach (BaseUnit unit in selectedUnits)
{
// for my first unit, the target is the actual targetGridNode (already checked if walkable)
// the next iteration MUST NOT use the actual targetGridNode, here I need the nearest walkable
Path path = FindPath(unit.transform.position, (Vector3)targetGridNode.position, traversalProvider);
// I get the last node of the path
GraphNode lastNode = path.path.Last();
// add the node to my traversalProvider, because for the next unit, this node is blocked
traversalProvider.AddNode(lastNode);
// add the node to my return Dictionary
nodes.Add(unit, lastNode);
}
return nodes;
}
This works only for the first unit, but I don’t know how to get the nearest walkable node, but where can I inject my TraversalProvider? This is my current code to get the nearest walkable node
public LevelGridNode GetNearestWalkableNode(Vector3 position)
{
var constraint = NNConstraint.None;
constraint.constrainWalkability = true;
constraint.walkable = true;
return (LevelGridNode)AstarPath.active.graphs[0].GetNearest(position, constraint).node;
}