Crossing Tag boundries

I’d like to know when a Path crosses a Tag boundary.

My project is a turn based tactical game (no hexes/squares) that has varied unit types and I’ve been prototyping the movement in this system(currently using Unity’s default pathfinding).
Infantry, tanks, mechs have different traversal profiles which I have been able to create with the Valid Tags and Tag Penalties in the Seeker script.

What I don’t get back from the Path.path and Path.vectorPath are two things

  1. I’d like to be able to see the point where it switches from one Tag to another, because I’d like to modify the animation/movement speeds as a unit moves and I draw an arrow from the path start-to-end and i’d like to modify color/texture to indicate slow/normal/fast movement on different terrains.

  2. I’d like to be able to see the costs of a generated path, so if I find a path that’s, say, 5000 units long, but the Unit is only able to do 3000 units this turn, I’d like to be able to find the last point it could move to. I understand that I might have to calculate this a bit myself which is why I relate to point #1

Possible solution?
I’m currently looking at modifying Path to have a List<int> tagPath that matches up with the vectorPath and making a FunnelModifier variant that doesn’t just get the smooth path, but also finds the points where the Path GraphNodes switch Tags.

This seems like it would work, but I was kind of hoping that someone knew how to do this in an easier fashion.

Hi

You can get the information from the path list.

var path = ...;
for (int i = 0; i < path.path.Count - 1; i++) {
    if (path.path[i].Tag != path.path[i+1].Tag) Debug.Log("Tag changed!");
}

After the funnel modifier has been applied the information is lost however since particular points that the funnel modifier generates do not necessarily correspond to a specific node.

I’m not quite sure how you would define the cost for a turn based game however. It seems like you are using a recast graph. What exactly do you define as the movement cost? Would it include how far the unit moves through a node (in a corner it may only move a very short distance through a node)?

I understand that I can access the Tag on the path.path Nodes. I actually did (almost) exactly the code you suggested before I realized that the vectorPath was the ‘cleaned’ version.

This is what the path comes up with

The funnel comes through and cleans it up to 2 points

I was planning to modify things so that my funnel comes back with 3 points, and an associated list of tags, so that I know when it crosses borders.

Ah. Unfortunately that is not possible at the moment. However you should be able to calculate an approximate version using something like this:

for (int i = 0; i < vectorPath.Count - 1; i++) {
     const float dt = 0.1f;
     for (float t = 0; t < 1.0f; t += dt) {
          var p1 = Vector3.Lerp(vectorPath[i], vectorPath[i+1], t);
          var p2 = Vector3.Lerp(vectorPath[i], vectorPath[i+1], t + dt);
          var node1 = AstarPath.active.GetNearest(p1).node;
          var node2 = AstarPath.active.GetNearest(p2).node;
          if (node1.Tag != node2.Tag) {
              // Insert new point here
          }
     }
}

If higher precision is needed (and you cannot decrease dt too much due to performance issues) you can always use a binary search.

1 Like

I just started digging into your Pathfinding solution yesterday so I’m still figuring out what options I need for my project. I was looking at the RecastGraph examples earlier because it does seem like the direct correlation to what I’m doing currently.

This is a current test map using Unity’s pathfinding

I’ve been modifying the Penalties example to see if I can get the results I wanted. I came up with this.

Crouch 10M and 20M refer to areas in which tall mechs would have to crouch to pass under, the number is tallest that a unit could be to pass under. The red area on the right defines a Road that allows for faster movement. Woods/Roads/Crouch10/20 are all defined as Tags currently.

This is the Seeker settings for a Tank. Not allowed to enter Woods, basic ground has a 1000 cost, roads have significantly less and basically ignores Crouch regions. I was able to get overlapping tags by having the regions only update a Start.

For an infantry unit; allowed to go everywhere, but high costs to go through woods and a much smaller speed bonus to travel on Roads.

Settings for a giant mech; not allowed in Woods or Crouch10m (but is allowed on Crouch 20M with a significant movement penalty) and Roads only allow for a moderate benefit.

At this point, I’d love to hear what your suggestions are before I commit to a solution.

One important thing that you should know is that the costs on a navmesh based graph (this also applies to Unity pathfinding) are not exact. The pathfinding algorithm operates on nodes, so the cost that the pathfinding algorithm uses is based on that jagged path in your first image while the final smoothed path was actually shorter. This means that the pathfinding algorithm may not always find the shortest path after smoothing (this is also mentioned in the Unity documentation). For costs this has the effect that they may not be perfectly accurately reflected in the movement costs. Since you are making a turn based game I assume you want very accurate costs that players can reason about (correct?) and in that case I would suggest a grid graph instead.

Yes, there is a difference in lengths.
In a locked to grid/hex based project it would be immediately apparent that lengths aren’t exact, but it’s pretty much ignored by the user in a project like this because the user really can’t be that precise.

<all placeholder art>
The yellow dot is the start point, the unit is standing on the green circle that’s the calculated endpoint and the green/blue line is placed on the path coming back from the system.

It’s not as big of deal if movement range is slightly off because they can see the weapons ranges before they finalize the move.
<again, all temp art>

If the error in ranges is a minimal amount then the user will have no problem, because they really won’t be able to see it. If it’s large enough to identify then obviously I would need a different solution.

I’m hoping to switch up to the Unity terrain to be able to get Height changes/water/etc. Would you still recommend the grid graph instead?

If you maps are not so large that the memory usage of the grid graph would be a problem, I would recommend using a grid graph. It will be a lot simpler for you to deal with when applying penalties since all nodes have the same size and it will be more easily grasped by people playing your game.

…wait. You were modifying the Penalties example scene. That already uses a grid graph. So I guess my suggestion is just to continue with what you were doing.

Yes. I wasn’t having much luck using the GraphUpdateScene to modify a RecastGraph in the scene I created.

That’s likely because a graph update scene component will modify the existing nodes in the graph. However there is no guarantee that the nodes will be shaped to fit your graph update scene component, so the region might be a bit off.
There is a small tutorial about this here: http://arongranberg.com/astar/docs/class_pathfinding_1_1_recast_mesh_obj.php#a5008f5aaa9ef50b1510e309dce9205d7
In the future I plan to make it possible to simply set the tag on the RecastMeshObj component however instead of having to use both a RecastMeshObj and a GraphUpdateScene component (this would be similar to what Unity’s navmesh system does right now).