Using agent as obstacle on grid to force repathing [Dumb hack, but maybe useful to somebody?]

Hi there!

I started using A* today, and one thing I was struggling to do was:

  • Have 2 Agents on a room using AIPath:
    • Man: The Player character, who on click would move to the desired position, and then stay still until further instructions.
    • Dog: Runs around the room, should not be able to pass through Player, or to push Player out of the way, especially when Player is not ordered to move. Should also not just crash against Player forever when trying to follow a blocked path.

In short, to have an Agent that becomes a blocker for other Agents as much as possible, without it becoming a blocker to itself.

I searched in the forum and I was quickly made aware that current proposed solutions require that either the game is turned based, that one doesn’t use the AIPath, or that they would both need to use RVO Controller. This doesn’t work for me, because with RVO alone, the Dog would stay colliding against the Man instead of repathing when blocking the path is narrow enough that it becomes completely blocked by Man.

If someone has found a way to do this which is better than my current hack, please do mention or link to it. Otherwise, here’s my hack:

  • My A* settings are using a layer called Obstacles as an Obstacle Layer Mask.
  • Dog and Man do have RVO Controller, which I have for when they are both moving. I do have the Man set to the maximum priority, to try and make the Dog be the one that has to avoid more.
  • Dog and Man are in Layers that don’t affect each other (in my case, Agents and Player). [So the RVO isn’t in conflict with collisions, as explained in the documentation]
  • I create a GameObject as a child of Man, which by default is disabled. I call this object GridBlocker. It has a collider, which could have the same radius and height as Man’s collider/character controller collider or not, up to what works best for you. It also has a DynamicGridObstacle script attached (comes with A*). This GameObject is in the Obstacles layer.
  • I attach the following script into Man, and I drag GridBlocker onto the dynamicGridObstacle slot in the Editor:
using Pathfinding;
using UnityEngine;

public class ActivateDynamicGridObstacleWhenIdle : MonoBehaviour
{
    public GameObject dynamicGridObstacle;
    AIPath aiPath;

    // Start is called before the first frame update
    void Start()
    {
        aiPath = GetComponent<AIPath>();
    }

    // Update is called once per frame
    void Update()
    {
        if(aiPath.velocity.magnitude == 0 && aiPath.reachedEndOfPath)
        {
            SetAIPathingVars(false);
            SetDynamicGridObstacle(true);
        }
        else
        {
            SetDynamicGridObstacle(false);
            SetAIPathingVars(true);
        }
    }

    void SetAIPathingVars(bool value)
    {
        if(aiPath.canSearch != value)
            aiPath.canSearch = value;

        if(aiPath.canMove != value)
            aiPath.canMove = value;
    }

    void SetDynamicGridObstacle(bool value)
    {
        if (dynamicGridObstacle.activeSelf != value)
            dynamicGridObstacle.SetActive(value);
    }
}

That’s it. It’s working pretty well for what I want it to do (it does create some artifacts when starting to move again however). When Man is idle because it has ended the path and velocity is 0, it activates GridBlocker, and now the Dog knows this path isn’t accessible. When I click to set a new destination, reachedEndOfPath is false, so the script activates canSearch and canMove, Man starts moving, and Dog and Man now avoid each other with RVO until Man stops again.

Am I doing something horrible here?

Cheers!

1 Like

Hey,

I do think that the RVO updates ( included in the beta files ) supports Idle agents a lot better. Aron would be able to tell you more about this.

If it works, it works.

Just a small correction, you mentioned that the other solutions only work for Turnbased games, that isn’t really true. many of the turnbased solutions also work for other game types, however the order of path calculation isn’t guaranteed. So you’d lose on multi threading performance as you might have to calculate your paths synchronously, rather than async.

1 Like