Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Running a coroutine in update

Discussion in 'Scripting' started by joshszman09, Feb 24, 2018.

  1. joshszman09

    joshszman09

    Joined:
    Mar 12, 2017
    Posts:
    8
    Hi! I'm making a custom particle system where the particles orbit around the center of the system like stars around a galaxy. To do this, I implemented the code below. It works well, but when I have a lot of particles, the framerate gets slowed way down because the for loop has to run thousands of times. I figured a coroutine might be a good option to speed things up. I have to put the function in update so I set it up to only run the coroutine again once the previous run has completed. I also put the yield statement inside the for loop because I need Unity to be able to stop the for loop and move onto the next frame before picking it back up.

    Something is wrong, though, because when I run this code, none of my particles update their position. I'm pretty sure that it is never even entering into the for loop. Does anyone know what I did wrong here? Thanks.

    Code (CSharp):
    1.     private void Update()
    2.     {
    3.         if (!isUpdating) //Note: isUpdating is set to false on start.
    4.         {
    5.             StartCoroutine(UpdatePosition());
    6.             isUpdating = true;
    7.         }
    8.     }
    Code (CSharp):
    1.    IEnumerator UpdatePosition()
    2.     {
    3.         // GetParticles is allocation free because we reuse the m_Particles buffer between updates
    4.         numParticlesAlive = m_System.GetParticles(m_Particles);
    5.         // Change only the particles that are alive
    6.         for (int i = 0; i < numParticlesAlive; i++)
    7.         {
    8.             Debug.Log(i);
    9.             m_Particles[i].velocity = new Vector3(0, 0, 0);
    10.             float r = m_Particles[i].position.magnitude;
    11.             float T = 2 * Mathf.PI * Mathf.Sqrt(Mathf.Pow(r, 3.0f) / GM);
    12.             float Theta_dot = 360f / T;
    13.             float Theta_new = Theta_dot * Time.deltaTime * timeMultiplier;
    14.             m_Particles[i].position = Quaternion.Euler(0, Theta_new, 0) * m_Particles[i].position;
    15.             yield return null;
    16.         }
    17.         // Apply the particle changes to the particle system
    18.         m_System.SetParticles(m_Particles, numParticlesAlive);
    19.         isUpdating = false;
    20.     }
     
  2. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    isUpdating = true i think should be inside your coroutine at the top.
     
  3. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    i heard debug.log can cause issues try using a ui text instead as the debug can fill up and cause it to crash
     
  4. joshszman09

    joshszman09

    Joined:
    Mar 12, 2017
    Posts:
    8
    Okay, that seemed to fix the problem of it not entering the for loop.

    But now I'm having a different issue. It seems like the for loop is not being picked back up where it left off. The highest it gets is a few hundred. Any thoughts on what might be happening here?
     
  5. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    numParticlesAlive = m_System.GetParticles(m_Particles); is getting updated every time it goes back to the coroutine. try removing it and passing a variable you assign right before the coroutine starts
     
  6. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    1. private void Update()
    2. {
    3. if (!isUpdating) //Note: isUpdating is set to false on start.
    4. {
    5. numParticlesAlive = m_System.GetParticles(m_Particles);
    6. StartCoroutine(UpdatePosition());
    7. }
    8. }
     
  7. joshszman09

    joshszman09

    Joined:
    Mar 12, 2017
    Posts:
    8
    I just tried it and I am still having the same issue. The coroutine is restarting the loop at the beginning every time. Maybe I am just misunderstanding coroutines, but I thought it was supposed to pick up where it left off.
     
  8. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    it should be. im wondering if your numparticles alive is a very small number. coroutines can do 10,000 (i) really quick
     
  9. joshszman09

    joshszman09

    Joined:
    Mar 12, 2017
    Posts:
    8
    This seems to be working. numParticlesAlive needed to be at the beginning of update. So now it is working as intended, but for some reason the loop is running extremely slow. I figured it would just spread out the UpdatePosition function over a few frames, but it is taking minutes in real time to run through the loop.

    Code (CSharp):
    1. private void Update()
    2. {
    3. numParticlesAlive = m_System.GetParticles(m_Particles);
    4. if (!isUpdating) //Note: isUpdating is set to false on start.
    5. {
    6. StartCoroutine(UpdatePosition());
    7. }
    8. }
     
  10. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    im wondering if particles are disaperring while the loop is running causing it to exit
     
  11. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    yield return null returns control to unity after every frame you may need one that does it after a few secs or add a variable to time it. like say only return null after timer = 100 then set it back to 0
     
  12. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26
    timer = timer + 1;
    if (timer => 100) {
    timer = 0;
    yield return null;
    }
     
  13. joshszman09

    joshszman09

    Joined:
    Mar 12, 2017
    Posts:
    8
    Great idea. it is working great now!

    Code (CSharp):
    1.     IEnumerator UpdatePosition()
    2.     //void UpdatePosition()
    3.     {
    4.         isUpdating = true;
    5.         // GetParticles is allocation free because we reuse the m_Particles buffer between updates
    6.         //numParticlesAlive = m_System.GetParticles(m_Particles);
    7.         // Change only the particles that are alive
    8.         int counter = 0;
    9.         for (int i = 0; i < numParticlesAlive; i++)
    10.         {
    11.             //Debug.Log(i);
    12.             m_Particles[i].velocity = new Vector3(0, 0, 0);
    13.             float r = m_Particles[i].position.magnitude;
    14.             float T = 2 * Mathf.PI * Mathf.Sqrt(Mathf.Pow(r, 3.0f) / GM);
    15.             float Theta_dot = 360f / T;
    16.             float Theta_new = Theta_dot * Time.deltaTime * timeMultiplier;
    17.             m_Particles[i].position = Quaternion.Euler(0, Theta_new, 0) * m_Particles[i].position;
    18.             if (counter < 1000)
    19.             { counter++; }
    20.             else { counter = 0; m_System.SetParticles(m_Particles, numParticlesAlive); yield return null;  }
    21.         }
    22.         // Apply the particle changes to the particle system
    23.         m_System.SetParticles(m_Particles, numParticlesAlive);
    24.        
    25.         isUpdating = false;
    26.         yield return null;
    27.     }
     
  14. joshszman09

    joshszman09

    Joined:
    Mar 12, 2017
    Posts:
    8
    Just looked at my framerate and it has quadrupled! Thank you for the help!
     
  15. superfryme

    superfryme

    Joined:
    Jun 9, 2017
    Posts:
    26