I am working on my first project in Unity using C# and I am currently trying to design a menu system that does the following sequence of events when a user clicks a button:
- Button does some effect for some milliseconds (for example, flashes)
- Menu1 does its closing sequence for some milliseconds (for example, buttons fly off screen)
- Menu2 does its opening sequence for some milliseconds (for example, buttons fly on screen)
The exact animations of the UI elements don't matter for the purpose of my question.
So far, the only design pattern I've found to achieve this kind of sequence is by using coroutines. So I ended up with something like the following:
void OnStartButtonClick()
{
StartCoroutine(_OnStartButtonClick());
}
IEnumerator _OnStartButtonClick()
{
yield return start_button.GetComponent<ButtonController>().DoEffect();
StartCoroutine(MenuTransition(main_menu, data_menu));
}
IEnumerator MenuTransition(GameObject menu1, GameObject menu2)
{
// main menu to data select
if (menu1 == main_menu && menu2 == data_menu)
{
yield return CloseMainMenu();
yield return OpenDataMenu();
}
}
public Coroutine OpenMainMenu()
{
return StartCoroutine(_OpenMainMenu());
}
IEnumerator _OpenMainMenu()
{
main_menu.SetActive(true);
// main menu opening sequence here
yield return null;
}
public Coroutine CloseMainMenu()
{
return StartCoroutine(_CloseMainMenu());
}
IEnumerator _CloseMainMenu()
{
// main menu closing sequence here
main_menu.SetActive(false);
yield return null;
}
public Coroutine OpenDataMenu()
{
return StartCoroutine(_OpenDataMenu());
}
IEnumerator _OpenDataMenu()
{
data_menu.SetActive(true);
// open data menu sequence
yield return null;
}
public Coroutine CloseDataMenu()
{
return StartCoroutine(_CloseDataMenu());
}
IEnumerator _CloseDataMenu()
{
// data menu closing sequence here
data_menu.SetActive(false);
yield return null;
}
And the code on my button likewise utilizes coroutines:
public Coroutine DoEffect()
{
return StartCoroutine(_DoEffect());
}
IEnumerator _DoEffect()
{
// imagine some code that does the effect
yield return new WaitForSeconds(1f);
}
This seems to work well enough and allows me to completely control the effect-->close-->open sequence. But it's getting a bit unwieldy as I build it out for more menus and transitions between them, resulting in a ton of methods with Coroutine return type wrapping IEnumerators (which I've been prefixing with underscore). I can't help but feel like there's a more elegant way to do this, and that I am using coroutines as a crutch ...
So my question is whether there is a more suitable or efficient design pattern that can allow me to achieve the kind of sequencing of events that I want without the proliferation of Coroutines & IEnumerators? Or are Coroutines & IEnumerators exactly the devices to solve this kind of problem?