Apologies in advance! Beginner here. I'm finding myself using a feature more and more often like this one I'm going to describe, to store a temporary variable and recalling it. I tried looking it up, but haven't found an answer specifically related to my issue.
I'm trying to do something very simple, once I understand how it's done I can apply it to other types (etc).
Let's say I want to change the color of a light, but store the original light setting in a variable, then recall that setting once the timer has run out. This is for a game in Unity.
if (powerupEnabled)
{
CameraShake.instance.shakeDuration = 5;
powerupTimer -= Time.deltaTime;
snakeheadFire.SetActive(true);
//lightIngame.intensity = 0.8f;
Color original_color = lightIngame.color; // <<<< Trying to store original color set in game in variable
lightIngame.color = Color.red;
if (lightIngame != null)
{
// add the amount of time that has passed since last frame
timeElapsed += Time.deltaTime;
// if the amount of time passed is greater than or equal to the delay
if (timeElapsed >= delay)
{
// reset the time elapsed
timeElapsed = 0;
// toggle the light
ToggleLight();
}
}
if (powerupTimer <= 0)
{
lightIngame.color = original_color; // <<<< Trying to restore original color set in game from variable
CameraShake.instance.shakeDuration = 0;
lightIngame.intensity = 1.12f;
print("Timer stopped!");
powerupTimer = 5f;
snakeheadFire.SetActive(false);
powerupEnabled = false;
}
}
So basically I tried Color original_color = lightIngame.color, but once I call original color back, the light won't change to its original setting. The two lines (color changes) are referenced with '<<<<'
What am I missing?
The temp variable is created every frame, if that function runs every frame. You need a variable that can survive until your powerupTimer runs out.
I suggest this:
private Color temp_value; // this lives in the class, not in the function.
void Update()
{
if (powerupEnabled)
{
// do stuff
if (powerupTimer <= 0)
{
setPowerupState(false); // disable powerup
}
}
}
void setPowerupState(bool enabled)
{
powerupEnabled = enabled;
if(enabled)
temp_value = lightIngame.color; // store the original color once, not every frame.
else
lightIngame.color = temp_value; // restore the saved value.
}
This answer already provides an explanation and one possible solution.
You could, however, avoid the local variable completely by not processing this in Update every frame but using a Coroutine where local variables exist for the entire lifetime of that routine:
void Update()
{
if (powerupEnabled)
{
// Make sure to start the routine only once
powerupEnabled = false;
StartCoroutine(PowerUpRoutine());
}
}
private IEnumerator PowerUpRoutine()
{
CameraShake.instance.shakeDuration = 5;
snakeheadFire.SetActive(true);
var original_color = lightIngame.color;
lightIngame.color = Color.red;
var powerupTimer = 5f;
var timeElapsed = 0f;
while(powerupTimer > 0 && lightIngame)
{
// add the amount of time that has passed since last frame
timeElapsed += Time.deltaTime;
// if the amount of time passed is greater than or equal to the delay
if (timeElapsed >= delay)
{
// reset the time elapsed
timeElapsed = 0;
// toggle the light
ToggleLight();
}
// This tells Unity to "pause" this routine, render this frame
// and continue from here in the next frame
yield return null;
powerupTimer -= Time.deltaTime;
}
lightIngame.color = original_color;
CameraShake.instance.shakeDuration = 0;
lightIngame.intensity = 1.12f;
print("Timer stopped!");
snakeheadFire.SetActive(false);
}
C# has two different types of objects: value types and reference types. Value types are simple types, like int, bool, double etc.
For the most part, all other / more complex classes are reference types, meaning when you assign a variable to another, instead of copying the object, C# will just assign the memory address of the object.
This means, when you call Color original_color = lightIngame.color;, C# will assign the object reference of lightIngame.color to your variable original_color. The value is not copied, but both variables point to the same object.
When you assign a new value to lightIngame.color afterwards, you are changing the value of lightIngame.color and original_color at the same time, as they both point to the same object.
To fix this, you need to create a copy of lightIngame.color when saving it, for example via copy constructors.
This is not a unity-specific issue, but a general fact about how c# works.