Object script behaves differently if object is instantiated

Have a simple movement script for a navmesh agent.

If I play the prefab object in the scent, it performs as expected. If the object is instantiated, it has a slight bug. Here is the script:

public class Mover : MonoBehaviour
{
NavMeshAgent navMesh;
private float distanceToStop = 0f;
private bool inCombatMode = false;

private void Start()
{
    navMesh = GetComponent<NavMeshAgent>();
}

private void Update()
{
    if (navMesh.remainingDistance < distanceToStop)
    {
        StopCharacter();
    }
}

public void MoveCharacter(RaycastHit rayHit, float distance, bool CombatMode)
{
    distanceToStop = distance;
    navMesh.isStopped = false;
    navMesh.destination = rayHit.point;
    inCombatMode = CombatMode;
}

public void StopCharacter()
{
    navMesh.isStopped = true;
    if (inCombatMode)
        GetComponent<Combat>().AttackTarget();
}

}

When I click on an enemy it will move within the distanceToStop variable and stop as expected. IF I place the object this script is attached to in the scene.

But when the object is instantiated into the scene instead, it does a weird thing where you need to click on the enemy twice before it will start moving.

What it seems to be is:

  1. when the object is already in the scene and navMesh.destination = rayHit.point is called, navMesh.remainingDistance is updated first before the Update() on the mover script is.

  2. when the object is instantiated, the Update() on mover is run before navMesh.remaining distance is updated.

I dont see why or how to fix it? I have tried to rearrange the order of the MoveCharater function and it doesnt seem to make a difference. I have checked the variables that trigger the if statement at Update() and they are the same.

Any thoughts would be appreciated :slight_smile:

@invisage Here is a theory: NavMesh needs time to calculate the newly instantiated NavMeshAgent . When you place your agent in Edit mode, this is done by the time the game starts, but not ready instantly after the newly instantiated gameobject that contains the NavMeshAgent appears after instantiation. Probably not until you first try to get it to move. The upshot is, it cannot quickly calculate the destination the first time you set it.

As a result, If the destination position has not been calculated by the time your Update runs, NavMeshAgent.remainingDistance (according to the documentation) is infinity, and therefore your code sets the NavMeshAgent to stop. That’s why you have to click twice. Debug the remainingDistance in your Update loop to verify this.

If the theory holds true, the work around would be to not set NavMeshAgent.desitnation directly but use NavMeshAgent.SetDestination instead. Use NavMeshAgent.pathPending to decide if the NavMeshAgent has started moving. If it has, then you can test if it reached the destination. You’ll have to rejigger your code to set that up.