【问题标题】:Bool returns different value when referenced in other scriptsBool 在其他脚本中引用时返回不同的值
【发布时间】:2019-03-04 23:48:08
【问题描述】:

我正在使用以下脚本检查互联网连接:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckInternets : MonoBehaviour
{
    private string url = "some photo on my google drive";
    private string wwww;

    public static bool InternetON = false; 

    // Start is called before the first frame update
    void Start()
    {        
        StartCoroutine(CheckConnection());
    }

    IEnumerator CheckConnection()
    {
        var www = new WWW(url);

        yield return www;

        if (www.isDone && www.bytesDownloaded > 0)
        {
            InternetON = true;
            Debug.Log("MAIN Script Check :: Online! :)");                        
        }

        if (www.isDone && www.bytesDownloaded == 0)
        {
            InternetON = false;
            Debug.LogWarning("MAIN Script Check :: Offline! :(");
        }
    }
}

在我的(Android)手机上试过这个,连接到移动数据(没有),它工作得很好。

一旦我在其他脚本中引用 InternetON bool 就会出现问题,也就是说,脚本总是将其读取为 false(或者如果我在 CheckInternets.cs 中将其设置为 true),所以我的直觉是我引用错误,或者我没有正确使用布尔值,但无法弄清楚如何。

其他脚本示例:

void Start()
{        
    if (CheckInternets.InternetON)
    {
        //do some stuff
        Debug.Log("OTHER Script Check :: Online! :)");
    }
    else
    {
        //do some other stuff
        Debug.Log("OTHER Script Check :: Offline! :(");
    }
}

在这种情况下,如果我在线,我的控制台将显示:

  • 其他脚本检查 :: 离线! :(

  • 主要脚本检查 :: 在线! :)

如果我处于离线状态,它会显示他们俩都处于离线状态。

有什么建议吗?干杯!

【问题讨论】:

  • 如果这是日志记录的顺序,并且它实际上是按照该顺序发生的,那么看起来其他脚本可能会在此脚本甚至测试/设置之前检查连接。
  • 也考虑了这一点,并将CheckInternets 放在脚本执行顺序的顶部,但没有效果——事实上它是列表中唯一的一个(在 Text Mesh Pro 之后那些,由于某种原因我根本无法删除)。
  • 您从“其他”脚本中检查得太早,即 Unity 在建立连接之前调用 SomeOther.Start() 方法。您无法通过简单地更改执行顺序来控制连接需要多长时间。无论何时启动协程,只要连接完成,协程就会结束。这就是 Unity 协程背后的理念,它们跨越多个框架(或某个时间框架等)。
  • 是的,很明显,我看到控制台日志消息以“错误”的顺序出现,但不知道我能做些什么。在实施@derHugo 的解决方案 1 之后,现在一切似乎都很好。

标签: c# unity3d


【解决方案1】:

StartCoroutine(CheckConnection());Start() 中启动coroutine ... 但是它在收到MoveNext() 调用之前不会被执行,该调用发生在之后它收到了Update 电话

来自Execution Order Documentation

正常的协程更新在Update 函数返回后运行。

Update 直到 all Start 在您的其他脚本中检查 bool 中的 Start 时才调用场景的调用,CheckConnection() 甚至不会执行第一个yield


相反,您必须等到检查完成。

以下是使用IEnumerator Start 的一些方法
Unity 允许这样做是为了延迟 Start 直到某事完成......这正是你想要做的:

  1. yieldCheckConnection

    您可以在协程中简单地 yield return 任何其他 IEnumerator 以便等到另一个完成

    public class CheckInternets : MonoBehaviour
    {
        private static string url = "some photo on my google drive";
        private static string wwww;
    
        public static bool InternetON = false; 
    
        public static IEnumerator CheckConnection()
        {
            var www = new WWW(url);
    
            yield return www;
    
            if (www.isDone && www.bytesDownloaded > 0)
            {
                InternetON = true;
                Debug.Log("MAIN Script Check :: Online! :)");                        
            }
    
            if (www.isDone && www.bytesDownloaded == 0)
            {
                InternetON = false;
                Debug.LogWarning("MAIN Script Check :: Offline! :(");
            }
        }
    }
    

    public class OtherScript : MonoBehaviour
    {
        IEnumerator Start()
        {
            // starts an internet check and waits until it finished
            yield return CheckInternets.CheckConnection();
    
            if (CheckInternets.InternetON)
            {
                //do some stuff
                Debug.Log("OTHER Script Check :: Online! :)");
            }
            else
            {
                //do some other stuff
                Debug.Log("OTHER Script Check :: Offline! :(");
            }
        }
    }
    
  2. 附加标志

    添加一个标志,例如checkFinished 并使用 WaitUntil

    public class CheckInternets : MonoBehaviour
    {
        private string url = "some photo on my google drive";
        private wwww;
    
        public static bool InternetON = false;
        public static bool IsFinished = false;
    
        // Start is called before the first frame update
        private void Start()
        {
            StartCoroutine(CheckConnection());
        }
    
        public IEnumerator CheckConnection()
        {
            IsFinished = false;
    
            var www = new WWW(url);
    
            yield return www;
    
            if (www.isDone && www.bytesDownloaded > 0)
            {
                InternetON = true;
                Debug.Log("MAIN Script Check :: Online! :)");
            }
    
            if (www.isDone && www.bytesDownloaded == 0)
            {
                InternetON = false;
                Debug.LogWarning("MAIN Script Check :: Offline! :(");
            }
    
            IsFinished = true;
        }
    }
    

    然后做

    public class OtherScript : MonoBehaviour
    {
        private IEnumerator Start()
        {
            // starts an internet check and waits until it finished
            yield return new WaitUntil(() => CheckInternets.IsFinished);
    
            if (CheckInternets.InternetON)
            {
                //do some stuff
                Debug.Log("OTHER Script Check :: Online! :)");
            }
            else
            {
                //do some other stuff
                Debug.Log("OTHER Script Check :: Offline! :(");
            }
        }
    }
    
  3. 回调

    添加回调Action,这样您就可以在不使用IEnumerator 的情况下等待结果

    public class CheckInternets : MonoBehaviour
    {
        private string url = "some photo on my google drive";
        private string wwww;
    
        // now you wouldn't need this anymore and could make it 
        // a local variable in the CheckConnectionRoutine
        public static bool InternetON = false;
    
        public void CheckConnection(Action<bool> callback)
        {
            StartCoroutine(CheckConnectionRoutine(callback));
        }
    
        private IEnumerator CheckConnectionRoutine(Action<bool> callback)
        {
            var www = new WWW(url);
    
            yield return www;
    
            if (www.isDone && www.bytesDownloaded > 0)
            {
                InternetON = true;
                Debug.Log("MAIN Script Check :: Online! :)");
            }
    
            if (www.isDone && www.bytesDownloaded == 0)
            {
                InternetON = false;
                Debug.LogWarning("MAIN Script Check :: Offline! :(");
            }
    
            callback?.Invoke(InternetON);
        }
    }
    

    并将其与方法一起使用

    public class OtherScript : MonoBehaviour
    {
        private void Start()
        {
            // somehow get a reference instead of using static
            // that's always the cleaner way
            var check = FindObjectOfType<CheckInternets>();
    
            // starts an internet check
            check?.CheckConnection(OnConnectionCheckFinished);
        }
    
        private void OnConnectionCheckFinished(bool isConnected)
        {
            if (isConnected)
            {
                //do some stuff
                Debug.Log("OTHER Script Check :: Online! :)");
            }
            else
            {
                //do some other stuff
                Debug.Log("OTHER Script Check :: Offline! :(");
            }
        }
    }
    

    或直接使用 lambda 表达式

    public class OtherScript : MonoBehaviour
    {
        private void Start()
        {
            // somehow get a reference instead of using static
            // that's always the cleaner way
            var check = FindObjectOfType<CheckInternets>();
    
            // starts an internet check
            check?.CheckConnection((isConnected) =>
            {
                if (isConnected)
                {
                    //do some stuff
                    Debug.Log("OTHER Script Check :: Online! :)");
                }
                else
                {
                    //do some other stuff
                    Debug.Log("OTHER Script Check :: Offline! :(");
                }
            });
        }
    }
    

【讨论】:

  • 感谢您的详细解答。我选择了第一个选项,一切都按预期工作。我将来可能会尝试其他选项。仔细检查一下:if (CheckInternet.CheckInternets.InternetON) 应该是if (CheckInternets.InternetON),对吧?我的意思是,我确实把它写成(CheckInternets.InternetON) 并且一切正常。
  • 是的,它应该只是 CheckInternets.InternetON .. 我不小心将您的示例复制到 Unity 的新类中,而不是替换内容;)
猜你喜欢
  • 1970-01-01
  • 2020-06-10
  • 2012-10-21
  • 2016-11-08
  • 1970-01-01
  • 1970-01-01
  • 2012-01-14
相关资源
最近更新 更多