AIBase.FixedUpdate Performance Issues

Hi, I’m experiencing some performance issues and I have no idea how to fix it, maybe it’s just a setting issue.
In my scene I have two Graphs, one is a Layered Graph and the other one is a normal Grid Graph.
The Normal Grid Graph is kind of big 350x350, the other one is smaller around 100x100.

I have around 40 agents which are in “sleep” mode, they are inactive (all the mono behaviors are disabled) until they get close to the player. Agents have the RVO Controller attached.

I’m using version 4.2.10 and Unity 2018.4, time step is at 0.025

Here is two screenshots of the profiler, normal profile and deep profile.

Normal Profile

Deep Profile

If you have any suggestions or ideas it will be very helpful. thanks so much!

Hey!

For our project we don’t rely on the Unity update loop.
So I’ve renamed all the update / fixedUpdate functions, and manually call them.
Based on the distance from player to my agent group I slowly ramp up the update calls.

Hi @ToastyStoemp thanks for your reply!
I’m not sure what you mean though :thinking:
I used the update loop to assign the player position as destination and calculate if the destination is reachable, as the player can jump to locations where enemies can’t reach.
I realized the calculation on the Update can be the one of the issues, so I’m trying new approaches (I’m trying with a coroutine as I don’t need to calculate it each frame)… if you have any better idea how to do that, I’m very interested to know how :wink:

This is the Coroutine I’m using:

WaitForSeconds wfs_CalculatePath = new WaitForSeconds(.1f);
        IEnumerator _CalculatePath()
        {
            // AI / Path // Get last Path calculated
            while (true)
            {
                path = ABPath.Construct(cachedTransform.position, targetDestination, null);

                nn = NNConstraint.None;

                if (cachedTransform.position.y < -10)
                {
                    nn.graphMask = 1 << 0;
                }
                else
                {
                    nn.graphMask = 1 << 1;
                }

                path.nnConstraint = nn;
                seeker.StartPath(path, OnPathComplete);

                yield return wfs_CalculatePath;

            }
        }
        
        void OnPathComplete(Path p)
        {
            //We got our path back
            if (p.error)
            {
                isPath = false;
            }
            else
            {
                isPath = true;
            }
        }

You said your agents are disable till the player gets near,
But you still have 160 calls on Finalize Movement. ( Are you disabling the entire agent, or the movement script ? Are you using rootmotion ? )

Your coroutine won’t affect the finalize movement call.

What movement script are you using ?

Ps. Here is what I meant with manually calling the update.
I call CustomUpdate and CustomFixedUpdate from an over arching system.

/// <summary>
/// Called every frame.
/// If no rigidbodies are used then all movement happens here.
/// </summary>
protected virtual void Update () {
    if (autoUpdate)
        CustomUpdate ();
}

protected virtual void CustomUpdate () {
    if (shouldRecalculatePath)
        SearchPath ();

    // If gravity is used depends on a lot of things.
    // For example when a non-kinematic rigidbody is used then the rigidbody will apply the gravity itself
    // Note that the gravity can contain NaN's, which is why the comparison uses !(a==b) instead of just a!=b.
    usingGravity = !(gravity == Vector3.zero) && (!updatePosition || ((rigid == null || rigid.isKinematic) && (rigid2D == null || rigid2D.isKinematic)));
    if (rigid == null && rigid2D == null && canMove) {
        Vector3 nextPosition;
        Quaternion nextRotation;
        MovementUpdate (Time.deltaTime, out nextPosition, out nextRotation);
        FinalizeMovement (nextPosition, nextRotation);
    }
}

/// <summary>
/// Called every physics update.
/// If rigidbodies are used then all movement happens here.
/// </summary>
protected virtual void FixedUpdate () {
    if (autoUpdate)
        CustomFixedUpdate ();
}

protected virtual void CustomFixedUpdate () {
    if (!(rigid == null && rigid2D == null) && canMove) {
        Vector3 nextPosition;
        Quaternion nextRotation;
        MovementUpdate (Time.fixedDeltaTime, out nextPosition, out nextRotation);
        FinalizeMovement (nextPosition, nextRotation);
    }
}

using delegates I’m able to easily subscribe to the time update calls:

public virtual void LinkToGameTick () {
    if (!linkedToGameTick) {
        linkedToGameTick = true;
        agent.frequentUpdate += CustomUpdate;
    }
}

public virtual void UnlinkFromGameTick () {
    if (linkedToGameTick && agent.frequentUpdate != null) {
        agent.frequentUpdate -= CustomUpdate;
        linkedToGameTick = false;
    }
}
1 Like

I’m using AIPath for the movement. All monobehaviors attached to the player got disabled until the player enters in radius (around 20 units)… hope that helps

Fixed update should not be called on disabled monoBehaviours, so you’ll have to investigate where this call is coming from.

1 Like

Hi! Thanks for pointing this out!
I made a very silly mistake and after disabling all my mono behaviors I had a piece of code activating only the AI, that’s why all my agents where still calculating the path.
Now I’m running again at a good frame rate.
Thanks so much for your help! It helped me to narrow down the issue :slight_smile:

2 Likes

the latest beta version seems covered your case (1 system calling Updates on all agents) already. I think it worths your time to look at.

1 Like