user10003487
user10003487

Reputation:

How can I make a C# script execute in a certain order?

I have a script conflict that checks if there is network connection and the version of the game (if it's up to date); but it's skipping those conditions and loading the game directly.

How do I make the script follow this pattern?:

  1. Check if there is internet connection
  2. Check the version of the game
  3. Only load the game if there is an internet connection and the version of the game is current

You'll notice there are some loading function who repeat themselves; I'm not sure which ones to apply.

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

Upvotes: 0

Views: 256

Answers (2)

derHugo
derHugo

Reputation: 90779

I can't give you a complete copy-pastable code here (mainy because I don't fully understand yet how all your scripts are connected between each other) but I see you are already using Coroutines.

I would as mentioned before use one central manager to handle all those things.

I will only give you a general pseudo-code here and hope you find your way frome here

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

And there are also some builtin ways for waiting like e.g. WaitUntil, WaitForSeconds etc.

Upvotes: 1

Asyranok
Asyranok

Reputation: 985

This is happening because you call the Invoke("loadMenuLevel", 3f); method in the Start() method in the SplashScrean.cs script.

Start() is invoked very soon after a MonoBehaviour is attached to an object. Ostensibly, you have it attached to a GameObject in the scene. All of these are being hit at once.

You also have it as invokable via left mouse click in the same script's Update() method:

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

I would add bools to each of the loading scripts that are set to true when each task completes. Then, in SplashScrean.cs, change the above condition to load the level automatically if all three are complete. Or, keep the key press condition and add the bools.

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

Now, if you also need the Loading MonoBehaviours to wait to execute their loading logic too, then consider adding Update() logic to them that checks the flag you set in CheckNetwork.cs.

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

Edits/Additional Notes As I notice:

CheckNetwork.cs references CheckVersion(); in the else clause. That seems pointless. It is impossible for LoadTxtData() to have set the logic that CheckVersion() relies on in that time frame. A sort of race condition, if you will. Plus, you handle that check in LoadTxtData() anyways, so I would just do that there.

Upvotes: 1

Related Questions