如何使C#脚本按特定顺序执行?

时间:2019-03-19 20:14:43

标签: c# unity3d networking connection

我有一个脚本冲突,检查是否存在网络连接和游戏版本(是否为最新版本);但它会跳过这些条件并直接加载游戏。

我如何使脚本遵循此模式?:

  1. 检查是否可以连接互联网
  2. 检查游戏的版本
  3. 仅在有互联网连接且游戏版本为最新版本时加载游戏

您会发现有一些加载函数会重复执行;我不确定要申请哪些。

CheckNetwork.cs

public Text AlertText;
public GameObject alert;
public string URL = "";
public string CurrentVersion;
string latestVersion;
public GameObject newVersionAvailable;

private void Start()
{
    StartCoroutine(LoadTxtData(URL));
}

void Awake()
{
    if (Application.internetReachability == NetworkReachability.NotReachable)
    {
        alert.SetActive(true);
        AlertText.text = "Sorry, you have to enable your conection to play this game";
        if (Input.GetKeyDown(KeyCode.Escape))
            Application.Quit();
    }
    else
    {
        alert.SetActive(false);
        CheckVersion();
    }
}

public void CheckVersion()
{
    if(CurrentVersion != latestVersion)
    {
        newVersionAvailable.SetActive(true);
    }
    else
    {
        newVersionAvailable.SetActive(false);
    }
}

private IEnumerator LoadTxtData(string url)
{
    UnityWebRequest www = UnityWebRequest.Get(url);
    yield return www.SendWebRequest();
    latestVersion = www.ToString();
    CheckVersion();
}

public void OpenURL(string url)
{
    Application.OpenURL(url);
}

Loading.cs

private Image progressBar;

private void Start()
{
    Invoke("LoadAsyncOperation", 3f);
    StartCoroutine(LoadAsyncOperation());
}

public IEnumerator LoadAsyncOperation()
{
    AsyncOperation gameLevel = SceneManager.LoadSceneAsync(1);
    while (gameLevel.progress < 1)
    {
        progressBar.fillAmount = gameLevel.progress;
        yield return new WaitForEndOfFrame();
    }
}

Loading2.cs

public GameObject loadingScreenObj;
public Slider slider;

AsyncOperation async;

public void StartGame()
{
    SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}

public void LoadScreen(int LVL)
{
    //StartCoroutine(loadingScreen());
}

IEnumerator LoadingScreen(int lvl)
{
    loadingScreenObj.SetActive(true);
    async = SceneManager.LoadSceneAsync(lvl);
    async.allowSceneActivation = false;

    while (async.isDone == false)
    {
        slider.value = async.progress;
        if (async.progress == 0.9f)
        {
            slider.value = 1f;
            async.allowSceneActivation = true;
        }
        yield return null;
    }
}

SplashScrean.cs

void Start()
{
    Invoke("loadMenuLevel", 3f);
    Screen.sleepTimeout = SleepTimeout.NeverSleep;
}

void loadMenuLevel()
{
    SceneManager.LoadScene("gameplay");
}

void Update()
{
    if (Input.GetKey(KeyCode.Mouse0)) 
    {
        loadMenuLevel();
    }
    if (Input.GetKey(KeyCode.Escape))
    {
        Application.Quit();
    }
}

2 个答案:

答案 0 :(得分:1)

之所以发生这种情况,是因为您在Invoke("loadMenuLevel", 3f);脚本的Start()方法中调用了SplashScrean.cs方法。

Start()附加到对象后很快调用

MonoBehaviour。表面上,您已将其附加到场景中的GameObject。所有这些都被立即击中。

您还可以通过在同一脚本的Update()方法中单击鼠标左键来调用它:

if (Input.GetKey(KeyCode.Mouse0)) 
{
    loadMenuLevel();
}

我将在每个任务完成时向设置为bools的每个加载脚本中添加true。然后,在SplashScrean.cs中,如果以上三个条件均已完成,则更改以上条件以自动加载级别。或者,保持按键状态并添加bools

if (Application.internetReachability != NetworkReachability.NotReachable 
    && loadScriptComplete && isCurrentVersion && Input.GetKey(KeyCode.Mouse0)) 
{
    loadMenuLevel();
}

现在,如果您还需要加载MonoBehaviours来等待执行其加载逻辑,那么可以考虑向其添加Update()逻辑来检查您在CheckNetwork.cs中设置的标志。 / p>

//For example. Instead of this
private void Start()
{
    Invoke("LoadAsyncOperation", 3f);
    StartCoroutine(LoadAsyncOperation());
}

//Do this
private void Update()
{
   //Note that we only need to check if it is a CurrentVersion, as if that is true, then we definitely have internet access.
   if(CheckNetwork.IsCurrentVersion) {
      Invoke("LoadAsyncOperation", 3f);
      StartCoroutine(LoadAsyncOperation());
   }
}

编辑/其他说明,我注意到:

CheckNetwork.csCheckVersion();子句中引用else。这似乎毫无意义。 LoadTxtData()无法在该时间范围内设置CheckVersion()所依赖的逻辑。如果您愿意的话,这是一种比赛条件。另外,您还是要处理LoadTxtData()中的支票,所以我就在那里进行。

答案 1 :(得分:1)

在这里我不能给您完整的可复制代码(主要是因为我还不完全了解您的所有脚本之间的连接方式),但是我发现您已经在使用Coroutines。 / p>

如前所述,我会使用一名中央经理来处理所有这些事情。

我在这里只给您一个通用的伪代码,希望您从这里找到自己的路

public class LoadManager
{
    public CheckNetwork check;
    public Loading loading;
    public Loading2 loading2;
    public SplashScrean splashScreen;

    // suprise: a not well documented fact 
    // you can simply make the Start method an IEnumerator (Coroutine)
    // so you can directly wait for anything you want
    private void IEnumerator Start()
    {
        // Next suprise: You can simply yield other IEnumerators
        // that makes them execute and at the same time waits until they are finished
        // so all methods that you want to wait for from here
        // should be IEnumerators

        // as said this is only an example 
        // you could directly within that single
        // Coroutine do your complete download and check routine together
        yield return check.CheckPermissions();
        if(!check.isReachable)
        {
            yield break;
        }

        // same for chekcing the version
        yield return check.CheckVersion();

        if(!check.isUpToDate)
        {
            // do something for update
            yield break;
        }

        // is up to date so start and wait for loading
        yield return loading.LoadAsyncOperation();

        // and so on
    }
}

还有一些内置的等待方式,例如WaitUntilWaitForSeconds等。