Maybe you don’t need the variable to be passed by reference. Just do whatever adjustments you end up using the variable for inside the loop of your coroutine (which I’m assuming you left out of this example for brevity, since otherwise this coroutine is pretty useless).
Iterators can’t have ref or out parameters, because the backing for an iterator in C# is a class that is generated by the compiler. Classes can’t have ref or out fields.
You can, however, create a Ref class to pass value types by reference.
public class Ref<T>
{
private T backing;
public T Value {get{return backing;}}
public Ref(T reference)
{
backing = reference;
}
}
Then use the Value of the reference anyplace you’d normally use the myVariable field.
I want to use that coroutine from multiple other classes to set value over some time. So I don’t think there is any way without using references. And yeah, the calculations would be done inside the loop, like this:
public static IEnumerator myCoroutine(ref float myVariable)
{
float time = 0;
float timeLimit = 1;
while (time < timeLimit)
{
// Do calculations
myVariable = newValue;
time += Time.deltaTime;
yield return null;
}
}
I want to be able to also set the variable, not only read, so that class doesn’t work.
Also, I will need to pass only single float, no any objects.
Doesn’t work because of this line: this.myFloat = result;
As I need to set value in other class.
The Ref class still uses a new field instead of a reference.
So I tried every solution I could find on the internet and I believe it may be impossible to get it working how I need. Guess I’ll have to think of another approach.
This is a great solution and it helps on many of my problems.
But I got to a new problem: what if I want to change the value of the variable and read it in the same coroutine?
Here is my problem:
IEnumerator PlayDialogueAfterWaiting(System.Action<bool> myCondition, int waitTime) {
myCondition(true);
yield return new WaitForSeconds(waitTime);
if (/* I want to read the value of my bool here, because it might have been changed by other functions during the wait time */) {
// Do something
}
}
The whole thread is very silly anyway. The standard solution is to pass in a reference to a class. No one wrote that since it’s so obvious and easy. It’s like if someone asked how to add 2 numbers, no one would say to use +. They assume you’re asking for other ways.
I can see why it seems that way, but no. Basic C# says everything is already in a class. No one would want to pass int score by reference. They would already have a class Score and would pass s1 to the coroutine, which would use member functions to change it.
I assumed Kru’s answer was a joke: “well, if you really want to do such a strange and silly thing, you could hack it with this oddball language feature which I won’t even explain how to use”.
public class WaitConditionRef<T> {
public bool abortCondition { get; set; }
private Coroutine coroutine;
public WaitConditionRef(MonoBehaviour caller, Action onUpdate, T yieldReturn, Action onFinish){
coroutine = caller.StartCoroutine (WaitUntilRef(onUpdate, yieldReturn, onFinish));
}
private IEnumerator WaitUntilRef<T>(Action onUpdate, T yieldReturn, Action onFinish){
while (!abortCondition) {
onUpdate ();
yield return yieldReturn;
}
onFinish ();
}
}
example Usage:
public IEnumerator BlinkObjects(List<GameObject> visuals){
bool visible = false;
var blinkObjectsWait = new WaitConditionRef<int> (this, ()=> {
for (int i = 0; i < visuals.Count; i++) {
visuals[i].SetActive (visible = !visible);
} }, 3, () => {
for (int i = 0; i < visuals.Count; i++) {
visuals[i].SetActive (true);
} } );
yield return ... //could be WaitUntil or fixxed time
blinkObjectsWait.abortCondition = true;
}
This example will blink the objects with the iterator step of 3 frames for as long as the abortCondition property is set to true. Afterwards enable these again when it stopped when they’re not visible.
You could also cache the WaitConditionRef instance and call the condition whenever / whereever you like.
Another simple and possibly useful approach depending on the use case is to invoke a function from the coroutine to set a public variable. Something like this: