Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity/C# : How to execute a function after another function has finished its execution?

I've been trying to build a "event system" for a project that I'm working on . Here is how I'm doing it : I populate a list with reference to a gameObject and the functions that I need to execute from that gameObject . Then , when the "event" is triggered (in this case , when the player steps into a trigger collider) I just loop over the list and Invoke the functions inside it.

The problem with this is that every single function inside the list gets executed at the same time. This works fine in some cases but if I want to create a more cinematic event I need to have the ability to execute a function after the previous one has finished it's execution .Sadly I have no idea how to do that.

I've been reading a lot of the documentation of both Unity and C# about coroutines and delegates but I can't seem to wrap my head around all those things and find a way to do implement them on code .So I need your help with that :How can I achieve this?

like image 669
Francisco M. Avatar asked Jan 07 '23 12:01

Francisco M.


1 Answers

1) use Invoke

private void BeginRace()
{
Invoke("WaveFlag", 0.5f);
Invoke("Beeps", 1.5f);
Invoke("CrowdBeginsCheer", 2f);
Invoke("CarsStartMoving", 2.2f);
}

2) use coroutine

private void BeginRace()
{
StartCoroutine(RaceSequence());
}

private IEnumerator RaceSequence()
{
yield return new WaitForSeconds(.5f);
WaveFlag();
yield return new WaitForSeconds(1f);
Beeps();
yield return new WaitForSeconds(.5f);
CrowBeginsCheer();
yield return new WaitForSeconds(.2f);
CarsStartMoving();
}

You must master both coroutines and Invoke. Be sure to simply use Invoke when possible. Avoid coroutines when you are just learning Unity. (Advanced essay on coroutines.)

3) "I need to wait until the previous function has ended before executing the following one"

a) EACH OF THOSE FUNCTIONS must be an IEnumerator

private IEnumerator ExplodeCar()
 {
 ..
 }

private IEnumerator CrowdReaction()
 {
 ..
 }

private IEnumerator WinningCelebration()
 {
 ..
 }

b) To call them one after the other, waiting for each to finish

private void Sequence()
 {
 StartCoroutine(Seq())
 }

private IEnumerator Seq()
 {
 yield return StartCoroutine(ExplodeCar());
 yield return StartCoroutine(CrowdReaction());
 yield return StartCoroutine(WinningCelebration());
 }

Footnotes

If you want to wait until the next frame, use:

yield return null;

if you have a "stack" of things you want to do each frame, just do this

void Update()
  {
  if (newItem = yourStack.Pop())
    newItem();
  }

if you have a "stack" of things you want to do waiting for each to finish,

void Start()
 {
 StartCoroutine(YourStackLoop());
 }
private IEnumerator stackLoop()
  {
  while(true)
    {
    if (newItem = yourStack.Pop())
      yield return StartCoroutine(newItem());
    else
      yield return new;
    }
  }

Note that Update and a coroutine are fundamentally the same thing, read and study on this.

Note in the example, use your own usual Push/Pop (or FIFO, or whatever you wish). If unfamiliar, search many QA on here.

like image 131
Fattie Avatar answered Jan 14 '23 06:01

Fattie