问题描述
提前道歉!初学者在这里。我发现自己越来越频繁地使用我将要描述的功能来存储临时变量并调用它。我尝试查找它,但没有找到与我的问题特别相关的答案。
我正在尝试做一些非常简单的事情,一旦我了解它是如何完成的,我就可以将其应用于其他类型(等)。
假设我想更改灯光的颜色,但将原始灯光设置存储在一个变量中,然后在计时器用完后调用该设置。这是针对 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;
}
}
所以基本上我尝试了 Color original_color = lightIngame.color,但是一旦我调用原始颜色,灯光将不会更改为其原始设置。两行(颜色变化)用 ' 引用
我错过了什么?
解决方法
每帧都会创建临时变量,如果该函数每帧运行一次。您需要一个可以持续到 powerupTimer
耗尽的变量。
我建议:
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 已经提供了解释和一种可能的解决方案。
但是,您可以完全避免使用局部变量,方法是不在每帧 Update
中处理它,而是使用 Coroutine,其中局部变量在该例程的整个生命周期中都存在:
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# 有两种不同类型的对象:值类型和引用类型。 值类型是简单类型,如 int、bool、double 等。
在大多数情况下,所有其他/更复杂的类都是引用类型,这意味着当您将变量分配给另一个变量时,C# 不会复制对象,而只会分配对象的内存地址。
这意味着,当您调用 Color original_color = lightIngame.color;
时,C# 会将 lightIngame.color 的对象引用分配给您的变量 original_color。值不会被复制,但两个变量都指向同一个对象。
当您之后为 lightIngame.color 分配一个新值时,您同时更改了 lightIngame.color
和 original_color
的值,因为它们都指向同一个对象。
要解决此问题,您需要在保存时创建 lightIngame.color
的副本,例如通过复制构造函数。
这不是一个特定于 Unity 的问题,而是关于 c# 如何工作的一般事实。
,可能是 lightIngame.color
是引用类型。
如果在尝试保存其状态时深度复制 lightIngame.color
,它可能会起作用。
如果深层复制不是一种选择,您或许可以用代理值表示 lightIngame.color
。
例如,您可以创建一个枚举 ReferenceColours
以及何时要存储值调用
var initialColour = lightIngame.color.ToReferenceColour()
。
当你想把它设置回来时,你可以这样做
lightIngame.color = var initialColour.ToLightInGameColour()
注意,ToReferenceColour()
和 ToLightInGameColour()
必须是您创建的扩展方法。这里面的逻辑只是处理两者之间的映射。
编辑 - 已经通过对这篇文章的评论解释说,Color
实际上是一个 UnityEngine.Color
,它是一个结构体。这意味着它将按值传递,因此上述解决方案是不必要的。