How to pass reference to variable in IEnumerator method in C#?
using UnityEngine;
using System.Collections;
public class myTimer : MonoBehaviour {
public int myInt1;
public int myInt2;
public int myInt3;
void Start()
{
StartCoroutine(ValueFader(0f, 100f, 5f, myInt1));
StartCoroutine(ValueFader(0f, 180f, 5f, myInt2));
StartCoroutine(ValueFader(0f, 115f, 5f, myInt3));
}
void Update()
{
//...
}
public IEnumerator ValueFader(float myStartValue, float myEndValue, float myDuration, out int myValue)
{
float myStartTime = Time.time;
while (Time.time < myStartTime + myDuration)
{
myValue = (int)(myStartValue + ((myEndValue - myStartValue) * ((Time.time - myStartTime) / myDuration)));
yield return null;
}
myValue = myEndValue;
}
void OnGUI()
{
GUI.Label(new Rect(0, 0, 80, 20), "myValue: " + myInt1);
GUI.Label(new Rect(0, 20, 80, 20), "myValue: " + myInt2);
GUI.Label(new Rect(0, 40, 80, 20), "myValue: " + myInt3);
}
}
Unity tells me: Error CS1623: Iterators cannot have ref or out parameters
What I want to do, is to be able to input/reference a specific variabel, whose value will be changed, from myStartValue to myEndValue, over time = myDuration.
Why doesn't it work? Can it be made to work? If not, how can I do this in a different way? I don't want to depend on Update(), preferably.
Thank you for your time! :]
Answer by ArkaneX · Oct 08, 2013 at 03:03 PM
Instead of passing ref/out parameters, you can pass Action
:
public IEnumerator ValueFader(float myStartValue, float myEndValue, float myDuration, System.Action<int> action)
and then call the action every time the value changes:
action(myValue);
Of course in this case you have to declare myValue
inside of method, because it is no longer a parameter.
You can call changed coroutine passing lambda expression as action. For example:
StartCoroutine(ValueFader(0f, 100f, 5f, (x) => myInt1 = x));
Here's a convenient full example of that:
private float stars; // it could even be a Property
private IEnumerator _transition(string letterCode)
{
yield return StartCoroutine(
Tween((x)=>stars=x, 3f,300f, 1f) );
yield return new WaitForSeconds(1f);
yield return StartCoroutine(
Tween((x)=>stars=x, 300f,3f, 1f) );
}
private IEnumerator Tween( System.Action<float> var,
float aa, float zz, float duration )
{
float sT = Time.time;
float eT = sT + duration;
while (Time.time < eT)
{
float t = (Time.time-sT)/duration;
var( Mathf.SmoothStep(aa,zz, t) );
yield return null;
}
var(zz);
}
Hope it saves some typing.
You should also cache the lambda function in a member field in order to not feed the GC monster.
Hi, landon91235! Could you provide an example of how to cache the lambda function in a member field, please? I would highly appreciate it.
Answer by jschieck · Oct 08, 2013 at 03:11 PM
Well a different way of doing it would be to store the ints in an int[] then passing in the index, and setting that index in the coroutine like this
using UnityEngine;
using System.Collections;
public class TestScript : MonoBehaviour
{
public int[] myInts;
void Start()
{
myInts = new int[3];
StartCoroutine(ValueFader(0f, 100f, 5f, 0));
StartCoroutine(ValueFader(0f, 180f, 5f, 1));
StartCoroutine(ValueFader(0f, 115f, 5f, 2));
}
void Update()
{
//...
}
public IEnumerator ValueFader(float myStartValue, float myEndValue, float myDuration, int myIndex)
{
float myStartTime = Time.time;
while (Time.time < myStartTime + myDuration)
{
myInts[myIndex] = (int)(myStartValue + ((myEndValue - myStartValue) * ((Time.time - myStartTime) / myDuration)));
yield return null;
}
myInts[myIndex] = (int)myEndValue;
}
void OnGUI()
{
GUI.Label(new Rect(0, 0, 80, 20), "myValue: " + myInts[0]);
GUI.Label(new Rect(0, 20, 80, 20), "myValue: " + myInts[1]);
GUI.Label(new Rect(0, 40, 80, 20), "myValue: " + myInts[2]);
}
}
To sum up, to pass a reference, pass a reference (in this ex, you could pass the array name and the index, for more flexibility.)
An array is a reference. A class variable is also a reference. In practice, your variables will often be in a class anyway, so you don't need to do anything extra.
In C++, you could pass a real reference, by just giving a pointer to an int. But C# won't allow that. The int must be bound up in some larger, memory-managed, object.
Your answer
Follow this Question
Related Questions
Why is my referenced variable changing values? 1 Answer
Why is refrence to parent variable not updating 1 Answer
What are some best practices for static variables in multiplayer? 0 Answers
Access Main Camera and store it in a variable for quick access? 2 Answers
Component refrence goes null randomly? 3 Answers