2D - UpdateGraphObject respecting tagged areas

Hi everyone. Im working with Pro version (v4.2.15). I need a very specific solution and after many and different approaches I cannot get it working. This is what the grid graph looks like after scanning:

As you see I have a tagged area (Hole in yellow and with TAG 30) which is marked as non-walkable in the Graph.ObstacleLayerMask (to generate that erosion) and then set as walkable using an GraphUpdateObject. As this GraphUpdateObject applies right after scanning obstacle it generates the erosion properly. My problem comes when breaking one of these obstacles because the GraphUpdateObject that handles the area for each obstacle ends affecting the hole and making it walkable for everyone.

This is the given result:

And this one is the expected one:

I know that scanning the graph will work but I have dozens of these breakable obstacles in a single graph and the solution has to be efficient. I already tried with the following:

        private void Apply()
        {
	        int tagsConstraint = -1 & ~(1 << 30);
	        NNConstraint nodeConstraint = new NNConstraint()
	        {
		        constrainWalkability = false,
		        constrainDistance =  false,
		        constrainArea = false,
		        constrainTags = true,
		        tags = tagsConstraint,
	        };
	        
	        
            GraphUpdateObject guo = new GraphUpdateObject
            {
            	bounds = _collider.bounds,
            	updatePhysics = updatePhysics,
            	resetPenaltyOnPhysics = resetPenaltyOnPhysics,
            	updateErosion = updateErosion,
            	modifyWalkability = modifyWalkability,
            	setWalkability = setWalkability,
            	modifyTag = modifyTag,
            	setTag = setTag,
            	addPenalty = penaltyDelta,
                nnConstraint = nodeConstraint,
            };

            AstarPath.active.UpdateGraphs(guo);   
        }

Thanks for the help <3

Hmm. That’s kinda tricky because it’s very much not what the graph gives you by default.

Do I understand correctly that essentially what you want is:

  1. Have an obstacle marked with tag 30.
  2. Generate erosion tags around it.
  3. Everything else should work exactly the same as a regular graph.

Hi! Thanks for helping Aron <3

What I need is:

  1. Have an obstacle marked with tag 30 (Holes) and generate erosion around it
  2. Have another (breakable) obstacle that generates erosion around it, and when it is destroyed the physics is updated, its erosion disappears, but both the area and Holes erosion remain intact.

Thanks, If you need it I can try to explain the expected behaviour with better images

Hmm. That sounds like what I wrote I think?

I think you can achieve this using a custom grid graph rule. This will require you to use the beta version though. See https://www.arongranberg.com/astar/download

With a custom grid graph rule you could do this:

  1. Everything is scanned in the normal way but
  2. as a post-processing step, you modify the graph so that if the node is within your hole, then the tag is set to 30. This requires you to be able to get information about where holes are, though. You can do this using Physics2D.OverlapPoint with a mask that is just your hole collider layer mask.

See https://www.arongranberg.com/astar/documentation/dev_4_3_45_d1e5882a/gridruleswrite.html

using UnityEngine;
using Pathfinding;

// Mark with the Preserve attribute to ensure that this class is not removed when bytecode stripping is used. See https://docs.unity3d.com/Manual/IL2CPP-BytecodeStripping.html
[Pathfinding.Util.Preserve]
public class AfterErosionRuleTest : GridGraphRule {

    public override void Register (GridGraphRules rules) {
        // The Register method will be called once the first time the rule is used
        // and it will be called again if any settings for the rule changes in the inspector.
        // Use this part to do any precalculations that you need later.

       // Replace with whatever layer you actually use
        var mask = LayerMask.GetMask("TransparentFX");

        // Hook into the grid graph's calculation code
        rules.AddMainThreadPass(Pass.AfterErosion, context => {
            // This callback is called when scanning the graph and during graph updates.
            // Here you can modify the graph data as you wish.
            // The context.data object contains all the node data as NativeArrays
            // Not all data is valid for all passes since it may not have been calculated at that time.
            // You can find more info about that on the documentation for the GridGraphScanData object.

            // Get the data arrays we need
            var nodeWalkable = context.data.nodeWalkableWithErosion;
            var nodePositions = context.data.nodePositions;
            var nodeTags = context.data.nodeTags;
            var collisionRadius = context.graph.collision.diameter * context.graph.nodeSize * 0.5f;

            // We iterate through all nodes and mark them as walkable or unwalkable based on some perlin noise
            for (int i = 0; i < nodePositions.Length; i++) {
                var position = nodePositions[i];
                var isHole = Physics2D.OverlapPoint(position, mask) != null;
                //Physics.CheckSphere(position, collisionRadius, mask, QueryTriggerInteraction.Ignore);
                if (isHole) {
                    nodeWalkable[i] = true;
                    nodeTags[i] = 30;
                }
            }
        });
    }
}

image
image