0
\$\begingroup\$

According to this page Events in unity are suppose to execute in a specific order. Specifically, OnCollisionEnter is supposed to be called right after OnTriggerEnter; however, FixedUpdate and Update are both being called at least once in between calls to my OnTriggerEnter2D and OnCollisionEnter2D functions in my Enemy class, why is this the case?

Here is my code:

public class Enemy : Combatant
{
public int kill_points;
public float force;
public List<GameObject> path_verticies;
private int pathi;
private bool on_path;
private bool is_flying;
private bool ignore_collision;          //Used for ignoring collisions with walls, if the enemy has already touched an enemy_controller.

void Start ()
{   Init();
    pathi = 0;
    ignore_collision = false;
    is_flying = false;
    if (gameObject.tag.Contains("Fly")) is_flying = true;//Assuming contains is cheaper than a full string compare.
    on_path = null != path_verticies && 0 != path_verticies.Count;
}

private void FixedUpdate() { ignore_collision = false; }

void Update ()
{   if (!CheckBounds()) Destroy(gameObject);
    if (on_path)
    {   transform.LookAt(path_verticies[pathi].transform, Vector3.up);
        transform.Rotate(new Vector3(0,-90,0));
        phys.velocity = transform.right * speed;
    }
    else dx = Mathf.Sign(Cx) * speed;
}

public void Flip(){ Cx *= -1; }

#pragma warning disable CS0642 // Possible mistaken empty statement
private IEnumerator OnCollisionEnter2D(Collision2D collision)
{   if (on_path && path_verticies[pathi] == collision.gameObject)
    {   if (collision.gameObject == player)
        {   throw new System.NotImplementedException();
            yield return new WaitForSeconds(0.1f);//Used to prevent damage to the player if the player landed on top of the enemy.
            var atk = player.GetComponent<Combatant>().vigor.Attack(2);
            if (Health.Atk.DIES == atk) player.GetComponent<Life>().Die();
        } else pathi = (pathi+1) % path_verticies.Count;
        yield return new WaitForSeconds(0.0f);
    }
    else if (on_path)
    {   if (collision.gameObject == player)
        {   yield return new WaitForSeconds(0.1f);//Used to prevent damage to the player if the player landed on top of the enemy.
            var atk = player.GetComponent<Combatant>().vigor.Attack(2);
            if (Health.Atk.DIES == atk) player.GetComponent<Life>().Die();
        } else if (collision.collider == On(Truebounds)) /*nothing*/;
        else if (collision.gameObject.layer == 0 || collision.gameObject.layer == 8)// TODO
            /*take velocity in the direction opposite of the normal and add it to
             * the perpendicular component the enemy is moving in*/;
        yield return new WaitForSeconds(0.0f);
    }
    else
    {   if (collision.gameObject == player)
        {   yield return new WaitForSeconds(0.1f);//Used to prevent damage to the player if the player landed on top of the enemy.
            var atk = player.GetComponent<Combatant>().vigor.Attack(2);
            if (Health.Atk.DIES == atk) player.GetComponent<Life>().Die();
        } else if (ignore_collision) /*nothing*/;
        else if (collision.collider == On(Truebounds)) { if (is_flying) Flip(); }
        else if (collision.gameObject.layer == 0 || collision.gameObject.layer == 8) Flip();
        yield return new WaitForSeconds(0.0f);
    }
}

private IEnumerator OnTriggerEnter2D(Collider2D collider)
{   var component = collider.GetComponent<MonoBehaviour2>();
    if(!component) yield return null;
    else if (on_path && path_verticies[pathi] == collider.gameObject)
        pathi = (pathi+1) % path_verticies.Count;
    else if (on_path) /*nothing*/;
    else if (component.type == typeof(Enemy_Controller)) { Flip(); ignore_collision = true; }
    yield return null;
}
#pragma warning restore CS0642 // Possible mistaken empty statement

//public void OnDestroy(){  }
}

and these are my timestep settings: Project Settings/Time

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

FixedUpdate and Update are not tied together. FixedUpdate is called based on how much time has passed (in your case, 0.02 seconds), while Update is called each frame. Generally (I think) FixedUpdate is used to do physics, collision, and movement, while Update handles input, game state, etc.

If you need something to happen x times every second, use FixedUpdate. If you just need something to happen every frame (but that doesn't rely on the time between frames) use Update. However, you can't rely on either of these to be called before or after the other.

Unity Docs, from the page you cited:

FixedUpdate: FixedUpdate is often called more frequently than Update. It can be called multiple times per frame, if the frame rate is low and it may not be called between frames at all if the frame rate is high. All physics calculations and updates occur immediately after FixedUpdate. When applying movement calculations inside FixedUpdate, you do not need to multiply your values by Time.deltaTime. This is because FixedUpdate is called on a reliable timer, independent of the frame rate.

Update: Update is called once per frame. It is the main workhorse function for frame updates.

\$\endgroup\$
5
  • \$\begingroup\$ I agree with the FixedUpdate part, it can be called multiple times and is not frame relevant, its call is time related. Update, however, is called after every frame. From my understanding, OnTriggerXXXX should be followed by OnCollisionXXXX on the same frame, and then Update should be called, as provided by the documentation. \$\endgroup\$
    – Shraa1
    Jun 1, 2019 at 4:58
  • \$\begingroup\$ I don't see where the docs say that Update always follows OnTrigger or OnCollision. My understanding (from the flowchart) was that they get called once every physics step, like FixedUpdate. \$\endgroup\$
    – Alex F
    Jun 1, 2019 at 5:14
  • \$\begingroup\$ If update is being called independently of and possibly even in parallel to OnTrigger, and OnCollision functions that is fine, but how does FixedUpdate get called inbetween them? Re-read my question, I tried to clarify by editing out "after all OnTriggerEnter events have been called for every object", since I thought that was a bit confusing. \$\endgroup\$
    – Caston
    Jun 1, 2019 at 5:54
  • 1
    \$\begingroup\$ I'm assuming based on the part at the top of your question that you have a misunderstanding about when certain functions are called. It would be very helpful (meaning do this in the future) if you could tell us what your code is supposed to do, and what it is actually doing. Right now there are parts of your code that don't make sense to me (like why are you setting ignore_collision in FixedUpdate)? Clarifying both your intent and your results are very important for us, to be able to help fix your problem. \$\endgroup\$
    – Alex F
    Jun 1, 2019 at 6:04
  • \$\begingroup\$ When one of my enemies hits either a wall (collider) or an enemy controller (trigger) I want them to flip; however, one of my enemies is hitting a wall and a controller at the same time. The flip that occurs in the OnCollisionEnter2D cancels out that in OnTriggerEnter2D. Therefore I am setting a variable called ignore_collision to true in OnTriggerEnter2D, which then is supposed to be checked in OnCollisionEnter2D to see if the enemy has already been flipped. Finally, ignore_collision is supposed to be reset in FixedUpdate on the following interval. \$\endgroup\$
    – Caston
    Jun 5, 2019 at 7:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .