繁体   English   中英

如何从 Unity 中的另一个脚本(使用 IEnumerator)获取值?

[英]How do I get a value from another script in Unity (with an IEnumerator)?

我想从不同的脚本中获取脚本中的值。 我有两个脚本:

public class CargarDatos : MonoBehaviour
{
    public string[] fechas;
    public string dia;

    IEnumerator Start()
    {
        UnityWebRequest www = UnityWebRequest.Get("http://localhost/Linx/Fechas.php");
        yield return www.SendWebRequest();
        string fechasDatos = www.downloadHandler.text;
        print(fechasDatos);
        fechas = fechasDatos.Split(';');
        dia = GetValorDatos(fechas[0], "Dia:");
        //print(dia);
    }

    string GetValorDatos(string datos, string index)
    {
        string valor = datos.Substring(datos.IndexOf(index)+index.Length);
        if(valor.Contains("|"))
        {
           valor = valor.Remove(valor.IndexOf("|")); 
        }
        return valor;
    }
}

在这里,如图所示,建立到数据库的连接并获取一个值 (dia)。 此脚本附加到主摄像机,因为我只希望它在游戏开始时连接。 在这里,function print(dia) 返回了正确的值,所以这个脚本有效。

问题是当我尝试获取此脚本中的值时:

public class BarraExperiencia : MonoBehaviour
{
    void Start()
    {
        print(GameObject.Find("Main Camera").GetComponent<CargarDatos>().dia);
    }
}

此脚本附加到 slider,我尝试打印它以查看它是否有效,但它不打印任何内容。 我做错了什么? 谢谢。

问题很可能是 BarraExperiencia 上的 Start 方法调用过早。

在这种情况下,您应该使用回调过程或事件。 有很多方法可以做到这一点,这是一种无需过多更改现有代码的方法。

我们首先需要修改 CargarDatos,我只保留相关部分,所以您需要保留所有其他成员和方法。

public class CargarDatos : MonoBehaviour
{
    public event Action<string> RaiseDataComplete;

    IEnumerator Start()
    {
        UnityWebRequest www = UnityWebRequest.Get("http://localhost/Linx/Fechas.php");
        yield return www.SendWebRequest();
        string fechasDatos = www.downloadHandler.text;
        fechas = fechasDatos.Split(';');
        dia = GetValorDatos(fechas[0], "Dia:");
        RaiseDataComplete?.Invoke(dia);
    }
}

这是另一个脚本:

public class BarraExperiencia : MonoBehaviour
{
    void Start()
    {
        GameObject.Find("Main Camera").GetComponent<CargarDatos>().RaiseDataComplete += OnComplete;
    }

    void OnComplete(string data){ print(data); }
}

第二个脚本找到 CargarDatos 并为该事件分配一个侦听器。 当数据加载到 CargarDatos 时,它将通知任何将数据作为参数传递的侦听器。

编辑:如果需要更多数据,

  1. 添加更多事件,以便每个侦听器都可以注册到该特定事件并仅获取该数据
  2. 将整个 class 传递给事件(不推荐但可能)
  3. 创建一个容器类型来传递所有需要的数据

    公共class存储{公共字符串直径{get; 私人套装; } 公共字符串 其他{ 获取; 私人套装; } 公共 int SomeValue{get; 私人套装; } 公共存储(字符串直径,字符串其他,int值){直径=直径; 其他=其他; SomeValue = 价值; } }

然后修改事件:

public event Action<Storage>RaiseDataComplete;

并通过新的 object:

RaiseDataComplete?.Invoke(new Storage(dia, "other string", 123));

然后监听器获取新的方法签名

void OnComplete(Storage data)
{ 
     print($"{data.Dia} {data.Other} {data.SomeValue}"); 
}

最后,您可以将 CargarDatos 中的所有成员设为私有,外部需要的任何内容都通过事件传递。

我认为您正试图在协程完成之前获得“直径”值。 仅在协程完成后尝试打印该值。

此外,使用FindObjectOfType获取组件会更快。

该值尚不可用。 我强烈建议您不要使用公共变量,而是将对值的访问封装在一个属性中,例如:

        private string dia = null;
        public string Dia {
            get {
                if(dia != null) {
                    return dia;
                }

                UnityWebRequest www = UnityWebRequest.Get ("http://localhost/Linx/Fechas.php");
                yield return www.SendWebRequest ();
                string fechasDatos = www.downloadHandler.text;
                print (fechasDatos);
                fechas = fechasDatos.Split (';');
                dia = GetValorDatos (fechas[0], "Dia:");
            }
        }

更新请查看以下针对您的场景的示例架构。 由于 Unity UnityWebRequest的异步性质,我们不能像我最初建议的那样将 yield 封装在属性中。

在下面,我们调用我们的服务并传入一个Action<User>类型的回调以在服务完成时运行。 这个回调现在可以从你的消费组件中做任何需要的事情——在这个例子中,我们更新了一个Text组件。

您可以将这些复制并粘贴到您的项目中,它们将从 Github 返回示例数据。

我的服务.cs

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

namespace MyCompany.MyGame {
    public class User {
        public string login;
    }

    public class MyService {
        public IEnumerator GetUser (Action<User> callback) {
            using (UnityWebRequest webRequest = UnityWebRequest.Get ("https://api.github.com/users/octocat")) {
                yield return webRequest.SendWebRequest ();
                callback (JsonUtility.FromJson<User> (webRequest.downloadHandler.text));
            }
        }
    }
}

入口.cs

using UnityEngine;
using UnityEngine.UI;

namespace MyCompany.MyGame {
    public class Entry : MonoBehaviour {
        MyService myService;

        [SerializeField]
        Text playerName;

        void Awake () {
            myService = new MyService ();
        }

        void Start () {
            StartCoroutine (myService.GetUser ((User result) => {
                Debug.Log (result);
                playerName.text = result.login;
            }));
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM