GraphUpdateScene using bounding box and not collision box

Hi there! I’m currently using a custom navmesh with a custom AI path for my enemies (based on Navmesh on a spherical planet). I have enemies traversing a 3D environment, and everything is just about working. It’s looking very promising!

The one thing that I haven’t figured out is why my obstacles use the object’s bounding box (max limits in X/Y/Z), and not just its collision box. For example:

For the object on the wall, I want it to use the pink collision box, but it’s using the big white one instead. Some things to note:

  • If I remove the rotation on the object, it works as expected. However, I need the custom rotations for these objects.
  • My graph has plenty of nodes. That wall is a grid of about 20x30.
  • The obstacle is literally just a stretched out primitive cube with the GraphUpdateScene script attached to it.

Will I need to make a custom script that just grabs the nodes inside its own box collider (the pink box), or is there a setting that I’m missing on the GraphUpdateScene script?

Thanks! :slight_smile:

1 Like

Hi

Unfortunately the GraphUpdateScene just grabs the bounding box for colliders, not their actual shape (which can be a bit complex). So yes, you will need a custom script I’m afraid.

You may be able to set the shape using the GraphUpdateScene’s custom points (you can ctrl-click in the scene view to add new points). However I don’t think that will work perfectly well with arbitrary rotations.

1 Like

Is there a way to loop through individual nodes intersecting with a trigger, then set the tag for each node? like:

private void Start() {
  for(int i = 0; i < navMeshGraphNodes.length; i++) {
    if(navMeshGraphNodes[i] intersects with a collider/trigger with a specific object tag) {
      navMeshGraphNodes[i].tag = NoPathTag;
    }
  }
}

I would imagine it would add a second or two to my loading time, but this would help immensely with level creation.

Hi

You can subclass the GraphUpdateObject class and override the Apply method.

public virtual void Apply (GraphNode node) {
}

It will be called with every node inside the bounding box that you provided. Then you can check if it is actually inside the collider and if so, apply the tag.

Kay, so I’ve spent most of this evening trying to get this to work, and I seem to have run into a brick wall. First I tried the following:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;

public class NoPath : GraphUpdateObject
{
    public override void Apply(GraphNode node)
    {
        node.Tag = 1;
    }
}

However, I can’t attach that to any GameObjects since it’s not a MonoBehaviour. Then I tried making the script a MonoBehaviour:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;

public class NoPath : MonoBehaviour
{
    public virtual void Apply(GraphNode node)
    {
        node.Tag = 1;
    }
}

That doesn’t work either, since it doesn’t look like the Apply function is ever called. Do you have any recommendations on how I can attach this script to a gameobject so it applies my tag to all nodes in the bounding box? Once I get this working, I’ll be able to apply my custom logic to it.

Hi

A GraphUpdateObject is not a MonoBehaviour or something you attach as a component, you just use it through code:

var guo = new NoPath();
guo.bounds = ...;
AstarPath.active.UpdateGraphs(guo);

The Apply method on the NoPath object will be called with every node that intersects the bounding box.

1 Like

This is perfect. Officially got it working! Thanks Aron!

Oh yeah, I should probably include my code in case someone else has a similar question in the future.

Attach this to the gameobject

public class NoPath : MonoBehaviour
{
    void Start()
    {
        var guo = new NoPathGraphUpdateObject();
        guo.bounds = GetComponent<Collider>().bounds;
        // Update the graph and apply tags
        AstarPath.active.UpdateGraphs(guo);
    }
}

Then keep this in your project:

public class NoPathGraphUpdateObject : GraphUpdateObject
{
    public override void Apply(GraphNode node)
    {
        // Make sure that the object's layer and the layer mask here match
        Collider[] colliderChecker = Physics.OverlapSphere((Vector3)node.position, 0.5f, 1 << 17);
        if (colliderChecker.Length > 0)
        {
            node.Tag = 1;
        }
    }
}
2 Likes

Big thanks for this, Im doing the same thing for gridgraph and was just thinking about how to implement this properly. I will try your solution and come back with the results.

Slightly improved code performance for NoPathGraphUpdateObject. It also accommodates the navmesh graph’s scale and increases its checking radius accordingly:

public class NoPathGraphUpdateObject : GraphUpdateObject
{
    public override void Apply(GraphNode node)
    {
        // Check node colliding with the obstacle object. Radius is the NavMeshGraph's radius * 0.71 (approx. half of sqrt(2)/2), layer 17 is my obstacle layer
        if (Physics.CheckSphere((Vector3)node.position, AstarPath.active.data.navmesh.scale * 0.71f, 1 << 17, QueryTriggerInteraction.Collide))
        {
            node.Tag = 1;
        }
    }
}
1 Like

Just checking back in. I plan on using GrphUpdate to update tags in runtime. I assume I have to call the apply method for each update of the tags positions, every few frames or during movement.