【问题标题】:How do I store and call a temporary variable in C#如何在 C# 中存储和调用临时变量
【发布时间】:2021-02-26 09:56:19
【问题描述】:

提前致歉!初学者在这里。我发现自己越来越频繁地使用一个特性,就像我将要描述的那样,存储一个临时变量并调用它。我尝试查找它,但没有找到与我的问题特别相关的答案。

我正在尝试做一些非常简单的事情,一旦我了解它是如何完成的,我就可以将它应用到其他类型(等等)。

假设我想更改灯光的颜色,但将原始灯光设置存储在一个变量中,然后在计时器用完后重新调用该设置。这是针对 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,但是一旦我调用原始颜色,灯光就不会改变到原来的设置。两条线(颜色变化)用 ' 引用

我错过了什么?

【问题讨论】:

    标签: c# unity3d light


    【解决方案1】:

    如果该函数每帧运行,则每帧都会创建临时变量。您需要一个能够在您的 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.
    }
    

    【讨论】:

    • 哇!!非常感谢您花时间阅读并回答我的问题!它就像一个魅力!它可能看起来很基础很愚蠢,但你不知道这些信息有多么有价值,我可以将它应用到我需要的任何临时值(这很常见),并且我现在了解如何存储临时值。
    • 如果你使用协程,你可以完全避开本地字段!见here
    【解决方案2】:

    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);
    }
    

    【讨论】:

      【解决方案3】:

      C# 有两种不同类型的对象:值类型和引用类型。 值类型是简单的类型,如 int、bool、double 等。

      在大多数情况下,所有其他/更复杂的类都是引用类型,这意味着当您将变量分配给另一个变量时,C# 不会复制对象,而只会分配对象的内存地址。

      这意味着,当您调用Color original_color = lightIngame.color; 时,C# 会将 lightIngame.color 的对象引用分配给您的变量 original_color。该值没有被复制,但两个变量都指向同一个对象。

      当您之后为 lightIngame.color 分配新值时,您将同时更改 lightIngame.colororiginal_color 的值,因为它们都指向同一个对象。

      要解决此问题,您需要在保存时创建lightIngame.color 的副本,例如通过复制构造函数。

      这不是一个特定于统一的问题,而是关于 c# 如何工作的一般事实。

      【讨论】:

      【解决方案4】:

      可能lightIngame.color 是一个引用类型。

      如果您在尝试保存其状态时深复制lightIngame.color,它可能会起作用。

      如果不能选择深度复制,您或许可以使用代理值来表示 lightIngame.color

      例如,您也许可以创建一个枚举 ReferenceColours 并在您想要存储值时调用

      var initialColour = lightIngame.color.ToReferenceColour().

      当你想把它放回去时,你可以这样做

      lightIngame.color = var initialColour.ToLightInGameColour()

      注意,ToReferenceColour()ToLightInGameColour() 必须是您创建的扩展方法。这里面的逻辑只是处理两者之间的映射。

      编辑 - 在这篇文章中通过 cmets 解释说,Color 实际上是一个 UnityEngine.Color,它是一个结构。这意味着它将按值传递,因此上述解决方案是不必要的。

      【讨论】:

      • 颜色是结构体,不能被引用
      • @GIVE-ME-CHICKEN 有关UnityEngine.Color 的更多信息,请参阅the Unity docs
      猜你喜欢
      • 1970-01-01
      • 2016-06-18
      • 1970-01-01
      • 2018-11-04
      • 1970-01-01
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多