如何使 C# 脚本按特定顺序执行?
How can I make a C# script execute in a certain order?
我有一个脚本冲突,检查是否有网络连接和游戏版本(如果是最新的);但它会跳过这些条件并直接加载游戏。
如何使脚本遵循这种模式?:
- 检查是否有互联网连接
- 查看游戏版本
- 仅在有互联网连接且游戏版本为最新时才加载游戏
你会注意到有一些加载函数会重复自己;我不确定要申请哪些。
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();
}
}
发生这种情况是因为您在 SplashScrean.cs
脚本的 Start()
方法中调用了 Invoke("loadMenuLevel", 3f);
方法。
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();
}
现在,如果您还需要 Loading MonoBehaviours
等待执行它们的加载逻辑,请考虑向它们添加 Update()
逻辑以检查您在 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 笔记据我所知:
CheckNetwork.cs
在 else
子句中引用了 CheckVersion();
。这似乎毫无意义。 LoadTxtData()
不可能在那个时间范围内设置CheckVersion()
所依赖的逻辑。一种竞争条件,如果你愿意的话。另外,无论如何你都会处理 LoadTxtData()
的检查,所以我会在那里做。
我不能在这里给你一个完整的复制粘贴代码(主要是因为我还没有完全理解你所有的脚本是如何相互连接的)但我看到你已经在使用 Coroutines .
我会如前所述使用一个中央管理器来处理所有这些事情。
我在这里只给你一个通用的伪代码,希望你能从这里找到自己的方法
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
}
}
还有一些内置的等待方式,例如WaitUntil, WaitForSeconds等
我有一个脚本冲突,检查是否有网络连接和游戏版本(如果是最新的);但它会跳过这些条件并直接加载游戏。
如何使脚本遵循这种模式?:
- 检查是否有互联网连接
- 查看游戏版本
- 仅在有互联网连接且游戏版本为最新时才加载游戏
你会注意到有一些加载函数会重复自己;我不确定要申请哪些。
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();
}
}
发生这种情况是因为您在 SplashScrean.cs
脚本的 Start()
方法中调用了 Invoke("loadMenuLevel", 3f);
方法。
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();
}
现在,如果您还需要 Loading MonoBehaviours
等待执行它们的加载逻辑,请考虑向它们添加 Update()
逻辑以检查您在 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 笔记据我所知:
CheckNetwork.cs
在 else
子句中引用了 CheckVersion();
。这似乎毫无意义。 LoadTxtData()
不可能在那个时间范围内设置CheckVersion()
所依赖的逻辑。一种竞争条件,如果你愿意的话。另外,无论如何你都会处理 LoadTxtData()
的检查,所以我会在那里做。
我不能在这里给你一个完整的复制粘贴代码(主要是因为我还没有完全理解你所有的脚本是如何相互连接的)但我看到你已经在使用 Coroutines .
我会如前所述使用一个中央管理器来处理所有这些事情。
我在这里只给你一个通用的伪代码,希望你能从这里找到自己的方法
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
}
}
还有一些内置的等待方式,例如WaitUntil, WaitForSeconds等