- Home /
Block until Dropdown value has changed?
I want to wait for the user select an option from a Dropdown. I am prototyping a turn based battle and using the Dropdown to give a list of actions like "Attack", "Block', etc. I want to block anything from happening until the user selects an action. I have tried to introduce a boolean variable that changes in OnValueChanged, but I don't know how to block other than while(!valueNotChanged) {}, which causes an infinite loop and I have to close Unity. Here is what I'm talking about:
public class Encounter : MonoBehaviour {
[SerializeField]
public Dropdown dropDown;
private bool choiceMade;
// Use this for initialization
void Start ()
{
choiceMade = false;
dropDown = GameObject.Find ("/GUI/TopicList").GetComponent<Dropdown> ();
dropDown.onValueChanged.AddListener(DropdownValueChanged);
}
private void DropdownValueChanged(int choice)
{
choiceMade = true;
}
public void go()
{
// Populate the Dropdown
dropDown.ClearOptions ();
dropDown.AddOptions (player.GetTopicStrings());
// Set to false
choiceMade = false;
// while the enemy is not dead
while(enemy.hp > 0)
{
while(!choiceMade)
{
Debug.Log ("Waiting for choice");
}
// Get the choice from the Dropdown
int choice = dropDown.value;
// Do stuff depending on choice made by player
Is there a way to achieve what I want, or do I need to switch from using Dropdowns entirely?
Answer by Brogan89 · Jul 25, 2017 at 03:47 AM
Dropdowns are event based, so nothing will be triggered until the user selected an option. This means you don't need "wait" for the user...
If i understand what you're trying to do is you want to option to always be "Block" unless the user picks something different?
If so, there a few ways of doing this... based on you code you have now I'm guessing you are calling go() from another script. So what you should do is add a callback which will be invoked once dropdown option has changed...
Maybe try this
public void go(UnityAction<int> callback)
{
// Populate the Dropdown
dropDown.ClearOptions();
dropDown.AddOptions(player.GetTopicStrings());
dropDown.onValueChanged.AddListener(callback);
}
then from your other script you would go like this
encounter.go(choice =>
{
//... whatever you want to do with that choice
});
Thanks for your suggestions! "nothing will be triggered until the user selected an option. This means you don't need "wait" for the user". If I don't "wait", then it just takes whatever value is selected in the Dropdown, and proceeds with my while loop. I want to wait for a new value to be selected so that 1) it feels like a turn and 2) it gives the user some time to think about what they want to select. Your approach seems like it would only trigger if the user selects something, but the user is free to do other things in the meantime. What I want is for the user to be "locked in" to selecting something from the dropdown.
Creating a "wait" function in Unity can only really be done in a Coroutine or in a polling situation in the Update function.
Calling Coroutines from outside the script can be a little long winded, so you could do something like this:
public void go()
{
// Populate the Dropdown
dropDown.ClearOptions();
dropDown.AddOptions(player.GetTopicStrings());
StartCoroutine(Go());
}
private IEnumerator Go()
{
// Set to false
choice$$anonymous$$ade = false;
// while the enemy is not dead
while (enemy.hp > 0)
{
while (!choice$$anonymous$$ade)
{
Debug.Log("Waiting for choice");
yield return null;
}
// Get the choice from the Dropdown
int choice = dropDown.value;
// Do stuff depending on choice made by player
yield return null;
}
}
which you still calling go()
but it off loads to a coroutine. you're script will then continuously be looping within while(!choice$$anonymous$$ade)
coroutines allow you to do this without making the game hang or even crash... Unity doesn't really like while loops, so its best to put it in coroutine, its kind of like another thread, but not exactly.