- Home /
Yield until color has been chosen, return color (or Color index)
Hey guys,
I need your help with a little "problem".
I want to choose a color by calling a method in a ColorPicker class. A color picker then opens and when the user has chosen the color, the method is supposed to return the chosen color or in another method the color index.
I'm almost there, but I don't understand how to implement the yield return here ...
Here is what I've got.
I want to call the method like this:
int newColorIndex = ColorPicker.chooseColorIndex();
Here is the method:
public int chooseColorIndex() {
colorChosen = false;
openColorPicker ();
while (!colorChosen) yield return null;
return chosenColor.colorIndex;
}
This is what happens when a color button is pressed:
public void assignColor() {
chosenColor = UIEventTrigger.current.GetComponent<ColorPickerColor> ();
colorChosen = true;
closeColorPicker ();
}
Now I want chooseColorIndex to return the index to the variable it has been called from (newColorIndex). I guess I'm messing up the yields here ... I am kind of new to coroutines and yields, so could you please help me out? Edit: I know now that i need the return type IEnumerator and a Coroutine, so please consider the code above as pseudo-code to illustrate what I am trying to do.
How do I tell chooseColorIndex to wait until the user has chosen the color, then return the color index (which is read from a component in the button)?
Thanks!
ps.: here's the error I get
The body of `ColorPicker.chooseColorIndex()' cannot be an iterator block because `int' is not an iterator interface type
Answer by ArkaneX · Apr 30, 2014 at 02:55 PM
1) Coroutines must return IEnumerator, that's why compiler complains about int.
2) To call coroutine, you have to use StartCoroutine, e.g. StartCoroutine(ColorPicker.chooseColorIndex())
3) You can't call coroutine and wait for it to return a specific value. That's not the way coroutines work. Instead, you can declare a variable in your class, and set it to a specific value inside coroutine.
You can change your chooseColorIndex method to:
public IEnumerator chooseColorIndex()
{
colorChosen = false;
openColorPicker ();
while (!colorChosen) yield return null;
// do what you want with color index here
}
and call it with:
StartCoroutine(ColorPicker.chooseColorIndex());
If you want to read more about coroutines, I strongly suggest this UnityGems article.
Alternatively, you can avoid coroutine at all - just call ColorPicker.chooseColorIndex()
, and then check ColorPicker.colorChosen
in Update
method. If it becomes true, execute the code you need. This requires both colorChosen
and chosenColor
to be public/internal static.
EDIT: another option, maybe better in your case - pass some action to coroutine. E.g.
public static IEnumerator chooseColorIndex(System.Action<int> action)
{
colorChosen = false;
openColorPicker ();
while (!colorChosen) yield return null;
action(chosenColor.colorIndex);
}
and call it with:
System.Action<int> action = (i) =>
{
sprite.color = availableColors[i];
};
StartCoroutine(ColorPicker.chooseColorIndex(action));
It's a pity that I can not return the color index then ... It makes the code really messed up because now I have to save which color variable is supposed to receive the color from chooseColorIndex and call a further function when the color has been chosen to apply this chosen color. It would have been so much easier and cleaner if I could just call
int colorIndex = ColorPicker.chooseColorIndex();
and wait for the user to pick his color. Then do
sprite.color = availableColors[colorIndex];
Anyway, this seems not to be possible here. So thank you!
It's not possible to wait, because that would mean blocked thread. And for single threaded game it doesn't sound good :)
Anyway - please check my answer. I updated it, and maybe this approach will be better in your case.
I don't really see the point of passing a delegate that will modify a global variable, you might as well access the variable directly in the coroutine. That would make sense if the coroutine was doing something more general and then the action does a specific action that may change on situation. Here, it is defined to work mainly in this color/setting color situation.
@fafase - you can't access sprite from this coroutine, because it is defined in a separate ColorPicker
class.
You can of course pass sprite directly to this method, but this would not be good solution, because then its name should be changed to modifySpriteColor
. Delegate allows to achieve some flexibility.