A* Pathfinding Project

How to add tags to graph nodes not at runtime


#1

Hello!

I want to export the graph using a script, and then also use tilemap tile data to tag certain nodes. However, the tags do not seem to work. My non-flying enemies walk right through the water (set to not traverse water in Seeker component) and the debug does not color the water a different color (I have it set to color tags in debug settings).

I have ExportAStarGraphTool.cs which basically just exports the graph data to a specific folder.

public static void ExportAStarGraph() {
	AstarPath.FindAstarPath();
	Selection.SetActiveObjectWithContext(AstarPath.active, AstarPath.active.gameObject);
	string assetPath = GetGraphPath();
	SerializeSettings serializationSettings = SerializeSettings.Settings;
	serializationSettings.nodes = true;
	AstarPath.active.Scan();
	byte[] data = AstarPath.active.data.SerializeGraphs(serializationSettings, out _);
	AstarPath.active.FlushWorkItems();
	string directory = Path.GetDirectoryName(assetPath);
	AstarSerializer.SaveToFile(assetPath, data);
	AssetDatabase.SaveAssets();
	AssetDatabase.Refresh();
}

And GraphUpdateSceneTilemap.cs which I use to tag Water and Pit nodes:

[RequireComponent(typeof(Tilemap))]
public class GraphUpdateSceneTilemap : GraphUpdateScene {

	public override void OnPostScan() {
		applyOnStart = false;
		Tilemap tilemap = GetComponent<Tilemap>();
		foreach (Vector3Int position in tilemap.cellBounds.allPositionsWithin) {
			TileBase tile = tilemap.GetTile(position);
			if (tile != null && (tile as BaseTile).AStarTag != AStarTag.None) {
				Bounds bounds = new Bounds(position, Vector2.one);
				GraphUpdateObject guo = new GraphUpdateObject(bounds) {
					modifyWalkability = false,
					setWalkability = false,
					addPenalty = 0,
					updatePhysics = false,
					updateErosion = false,
					resetPenaltyOnPhysics = false,
					modifyTag = true,
					setTag = (int) (tile as BaseTile).AStarTag
				};
				AstarPath.active.UpdateGraphs(guo);
			}
		}
	}
}

Is the right approach? Is there anything that you notice I am doing incorrectly?


#2

Update: I just tried using AddWorkItem and this does work.

private static void ApplyTilemapTileTags() {
	Dictionary<Vector3, uint> nodesToTag = new Dictionary<Vector3, uint>();
	List<Tilemap> groundTilemaps = TilemapUtility.GetTilemapsByLayer(TileLayer.GroundAndPits);
	foreach (Tilemap groundTilemap in groundTilemaps) {
		foreach (Vector3Int position in groundTilemap.cellBounds.allPositionsWithin) {
			TileBase tile = groundTilemap.GetTile(position);
			if (tile != null && (tile as BaseTile).AStarTag != AStarTag.None) {
				Vector3 nodePosition = position  + new Vector3(1, 1);
				if (!nodesToTag.ContainsKey(nodePosition)) {
					uint tag = (uint) (tile as BaseTile).AStarTag;
					nodesToTag.Add(nodePosition, tag);
				}
			}
		}
	}
	AstarPath.active.AddWorkItem(new AstarWorkItem(() => {
		foreach (var nodeToTag in nodesToTag) {
			GraphNode node = AstarPathUtility.GetNode(nodeToTag.Key);
			node.Tag = nodeToTag.Value;
		}
	}));
    AstarPath.active.FlushWorkItems();
}

So although my problem is solved, I’m still a bit curious as to why the other method did not work o.0.


#3

Hi

Hmm… I’m not sure why the first approach didn’t work either. Did the graph change in the scene view after the update?


#4

It used to work in the past. I just can pinpoint what changed. But no, the graph did not change in the scene view after the graph update.


#5

Ah. I see the issue. You have created a bounding box with a size of Vector2.one. This will create a bounding box which has no width at all along the Z dimension. If you are really lucky the nodes’ z coordinates will be exactly what you have stored, but more likely it will differ a bit.
I would suggest that you use Vector3.one instead.


#6

Ah, I see! Thanks so much for pointing that out. As always, I sincerely appreciate the fast and effective support!