WaitForSeconds()Conoutine导致游戏无限期冻结(已编辑) [英] WaitForSeconds() Coroutine causes Game to freeze Indefinitely (Edited)

查看:871
本文介绍了WaitForSeconds()Conoutine导致游戏无限期冻结(已编辑)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个有四个场景的游戏,一个菜单场景,一个装载场景和两个游戏场景。一切都很好,当我从菜单场景转换到我的游戏场景时,只要从我的游戏场景转换到我的菜单场景或重新加载游戏场景,加载场景就会停止响应。我收到一条警告信息,表示NetworkManager在编辑器中检测到脚本重新加载,这导致网络仅在我尝试重新加载当前活动的游戏场景时关闭当我在构建中玩时,这个问题也是存在的。我使用print语句来跟踪代码停止运行的位置,我发现这是导致游戏的Yield Return New WaitForSeconds()冻结。为什么?



我有两个脚本来控制转换。 一个简单的脚本在UIButtons上调用,用于告诉在预加载场景中调用的第二个更复杂的脚本来加载它应该加载和创建动画的场景。我已经确保我正在加载到正确的场景,并将所有场景都添加到我的构建设置中。



以下图片显示加载场景未响应。第一张照片显示当我尝试重新加载当前游戏场景时会发生什么,第二张照片显示当我尝试加载菜单场景时会发生什么:







我的载入场景脚本:

  public class LoadingScreenManager:MonoBehaviour { 

[Header(Loading Visuals)]
public Image loadIcon;
public Image loadDoneIcon;
public Text loadText;
public Image progressBar;
public Image fadeOverlay;

[Header(Timing Settings)]
public float waitOnLoadEnd = 0.25f;
public float fadeDuration = 0.25f;

[Header(Loading Settings)]
public LoadSceneMode loadSceneMode = LoadSceneMode.Single;
public ThreadPriority loadThreadPriority;

[Header(Other)]
//如果加载加法器,链接到摄像机音频监听器,以避免多个活动音频监听器
public AudioListener audioListener;

AsyncOperation操作;
场景currentScene;

public static int sceneToLoad = -1;
//重要!这是您的加载场景的构建索引。你需要改变这个来匹配你的实际场景索引
static int loadSceneIndex = 1;

public static void LoadScene(int levelNum){
Application.backgroundLoadingPriority = ThreadPriority.High;
sceneToLoad = levelNum;
SceneManager.LoadScene(loadingSceneIndex);
}

void Start(){
if(sceneToLoad< 0)
return;

fadeOverlay.gameObject.SetActive(true); //确保它可以交叉淡化Alpha
currentScene = SceneManager.GetActiveScene();
StartCoroutine(LoadAsync(sceneToLoad));
}

private IEnumerator LoadAsync(int levelNum){
ShowLoadingVisuals();

yield返回null;

FadeIn();
StartOperation(levelNum);

float lastProgress = 0f;

//操作不会自动激活场景,所以它停留在0.9
的同时(DoneLoading()== false){
yield return null;

if(Mathf.Approximately(operation.progress,lastProgress)== false){
progressBar.fillAmount = operation.progress;
lastProgress = operation.progress;
}
}

if(loadSceneMode == LoadSceneMode.Additive)
audioListener.enabled = false;

ShowCompletionVisuals();
//打印声明在这里工作精细! waitOnLoadEnd的值只有1
yield返回新的WaitForSeconds(waitOnLoadEnd);
//打印声明在这里正常运行!
FadeOut();

yield返回新的WaitForSeconds(fadeDuration);

if(loadSceneMode == LoadSceneMode.Additive)
SceneManager.UnloadScene(currentScene.name);
else
operation.allowSceneActivation = true;
}

private void StartOperation(int levelNum){
Application.backgroundLoadingPriority = loadThreadPriority;
operation = SceneManager.LoadSceneAsync(levelNum,loadSceneMode);


if(loadSceneMode == LoadSceneMode.Single)
operation.allowSceneActivation = false;
}

private bool DoneLoading(){
return(loadSceneMode == LoadSceneMode.Additive&& operation.isDone)|| (loadSceneMode == LoadSceneMode.Single&& operation.progress> = 0.9f);
}

void FadeIn(){
fadeOverlay.CrossFadeAlpha(0,fadeDuration,true);
}

void FadeOut(){
fadeOverlay.CrossFadeAlpha(1,fadeDuration,true);
}

void ShowLoadingVisuals(){
loadingIcon.gameObject.SetActive(true);
loadDoneIcon.gameObject.SetActive(false);

progressBar.fillAmount = 0f;
loadingText.text =LOADING ...;
}

void ShowCompletionVisuals(){
loadIcon.gameObject.SetActive(false);
loadDoneIcon.gameObject.SetActive(true);

progressBar.fillAmount = 1f;
loadingText.text =LOADING DONE;
}

}

调用上述的UIButtons上的脚本脚本:

  public class LoadingSceneButton:MonoBehaviour {

public void LoadSceneWithLoadingScreen(int sceneNumber){
if(sceneNumber< 0 || sceneNumber> = SceneManager.sceneCountInBuildSettings){
Debug.LogWarning(Can not Load Scene,because it does not Exist!);
}

LoadingScreenManager.LoadScene(sceneNumber);
}
}


解决方案

1)不要使用打印,请使用:

  Debug.Log(fadeDuration is ..... ..,fadeDuration.ToString(f4); 

在你之前添加一行代码调用 FadeOut ,并将其添加到 FadeOut






(2) CrossFadeAlpha



的问题请注意,CrossFadeAlpha是极难使用!这是一个真正的痛苦!它只适用于 UnityEngine.UI.Graphic ,与协同程序一起使用时很棘手。 p>

  public static void FadeOut(this Graphic g)
{
g.GetComponent< CanvasRenderer>()SetAlpha (1f);
g.CrossFadeAlpha(0f,.15f,false);
}






(3)在Unity5中加载场景的问题!!!



是的,有一个



已知问题



其中卡住了0.9。也许这是手头的主要问题。



查看... http://answers.unity3d.com/answers/1146173/view.html



和... http://answers.unity3d.com/answers/1073667/view.html



一些基本的工作代码示例....

  public void LaunchSoundboard )
{
StartCoroutine(_soundboard());
}
private IEnumerator _soundboard()
{
Grid.music.Duck();

yield返回新的WaitForSeconds(.2f);

AsyncOperation ao;
ao = UnityEngine.SceneManagement
.SceneManager.LoadSceneAsync(YourSceneName);

while(!ao.isDone)
{
yield return null;
}

//这里,新场景IS LOADED
SoundBoard soundBoard = Object.FindObjectOfType&SoundBoard>();
if(soundBoard == null)Debug.Log(WOE!);
soundBoard.SomeFunctionInSoundboardScript();
}



请注意,您等待.isDone,而不是观看浮动。






(4)#你实际上必须有一个名为preload的场景,只有预载。



不幸的是,菜单场景可以不是您的预加载场景。



你必须实际上有一个单独的预加载场景,除了preload之外什么都不做。



注意任何游戏经理你必须在预加载的场景。这是有点烦人,但这是怎么回事。



预加载场景的目的是持有任何游戏经理。



您标记为不加载销毁的场景必须预加载场景。这很简单。



这有点麻烦,但非常简单可靠。


I have a game with four scenes, a menu scene, a loading scene, and two game scenes. All is well, when I am transitioning from my menu scene to my game scenes, but whenever I transition from my game scenes back to my menu scene or reload the game scene, the loading scene simply stops responding. I get a warning message that says "NetworkManager detected a script reload in the editor. This has caused the network to be shut down" only when I try to reload the currently active game scene. This issue is also present when I play in the build! I used print statements to trace down where my code stopped running, and I figured out that it was the Yield Return New WaitForSeconds() which caused the game to freeze. Why is that?

I have two scripts that controls transitioning. One simple script called on UIButtons for telling the second more complex script called in the preload scene to load the scene it's supposed to load and create animations. I have made sure that I was loading on to the correct scene, and that all of the scenes were added into my build settings.

The following pictures show the loading scene not responding. The first picture shows what happens when I try to reload the current game scene, and the second picture shows what happens when I try to load the menu scene:

My Loading Scene Script:

public class LoadingScreenManager : MonoBehaviour {

[Header("Loading Visuals")]
public Image loadingIcon;
public Image loadingDoneIcon;
public Text loadingText;
public Image progressBar;
public Image fadeOverlay;

[Header("Timing Settings")]
public float waitOnLoadEnd = 0.25f;
public float fadeDuration = 0.25f;

[Header("Loading Settings")]
public LoadSceneMode loadSceneMode = LoadSceneMode.Single;
public ThreadPriority loadThreadPriority;

[Header("Other")]
// If loading additive, link to the cameras audio listener, to avoid multiple active audio listeners
public AudioListener audioListener;

AsyncOperation operation;
Scene currentScene;

public static int sceneToLoad = -1;
// IMPORTANT! This is the build index of your loading scene. You need to change this to match your actual scene index
static int loadingSceneIndex = 1;

public static void LoadScene(int levelNum) {                
    Application.backgroundLoadingPriority = ThreadPriority.High;
    sceneToLoad = levelNum;
    SceneManager.LoadScene(loadingSceneIndex);
}

void Start() {
    if (sceneToLoad < 0)
        return;

    fadeOverlay.gameObject.SetActive(true); // Making sure it's on so that we can crossfade Alpha
    currentScene = SceneManager.GetActiveScene();
    StartCoroutine(LoadAsync(sceneToLoad));
}

private IEnumerator LoadAsync(int levelNum) {
    ShowLoadingVisuals();

    yield return null; 

    FadeIn();
    StartOperation(levelNum);

    float lastProgress = 0f;

    // operation does not auto-activate scene, so it's stuck at 0.9
    while (DoneLoading() == false) {
        yield return null;

        if (Mathf.Approximately(operation.progress, lastProgress) == false) {
            progressBar.fillAmount = operation.progress;
            lastProgress = operation.progress;
        }
    }

    if (loadSceneMode == LoadSceneMode.Additive)
        audioListener.enabled = false;

    ShowCompletionVisuals();
  //THE PRINT STATEMENT WORKS FINE RIGHT HERE! The value of waitOnLoadEnd is only 1
    yield return new WaitForSeconds(waitOnLoadEnd);
 //THE PRINT STATEMENT STOPS RUNNING RIGHT HERE!  
    FadeOut();

    yield return new WaitForSeconds(fadeDuration);

    if (loadSceneMode == LoadSceneMode.Additive)
        SceneManager.UnloadScene(currentScene.name);
    else
        operation.allowSceneActivation = true;
}

private void StartOperation(int levelNum) {
    Application.backgroundLoadingPriority = loadThreadPriority;
    operation = SceneManager.LoadSceneAsync(levelNum, loadSceneMode);


    if (loadSceneMode == LoadSceneMode.Single)
        operation.allowSceneActivation = false;
}

private bool DoneLoading() {
    return (loadSceneMode == LoadSceneMode.Additive && operation.isDone) || (loadSceneMode == LoadSceneMode.Single && operation.progress >= 0.9f); 
}

void FadeIn() {
    fadeOverlay.CrossFadeAlpha(0, fadeDuration, true);
}

void FadeOut() {
    fadeOverlay.CrossFadeAlpha(1, fadeDuration, true);
}

void ShowLoadingVisuals() {
    loadingIcon.gameObject.SetActive(true);
    loadingDoneIcon.gameObject.SetActive(false);

    progressBar.fillAmount = 0f;
    loadingText.text = "LOADING...";
}

void ShowCompletionVisuals() {
    loadingIcon.gameObject.SetActive(false);
    loadingDoneIcon.gameObject.SetActive(true);

    progressBar.fillAmount = 1f;
    loadingText.text = "LOADING DONE";
}

}

Script on UIButtons that call the above script:

 public class LoadingSceneButton : MonoBehaviour {

public void LoadSceneWithLoadingScreen(int sceneNumber){
    if (sceneNumber < 0 || sceneNumber >= SceneManager.sceneCountInBuildSettings) {
        Debug.LogWarning ("Can't Load Scene, because It Doesn't Exist!");
    }

    LoadingScreenManager.LoadScene (sceneNumber);
}
}

解决方案

(1) Don't use "print", please use this:

  Debug.Log("fadeDuration is ....... " , fadeDuration.ToString("f4");

add that line of code just before you call FadeOut and also please add it inside FadeOut


(2) problems with CrossFadeAlpha

Please note that CrossFadeAlpha is extremely difficult to use! It's a real pain! It only works on UnityEngine.UI.Graphic, and it's tricky when used with coroutines.

public static void FadeOut(this Graphic g)
    {
    g.GetComponent<CanvasRenderer>().SetAlpha(1f);
    g.CrossFadeAlpha(0f,.15f,false);
    }


(3) problems with loading a scene in Unity5 !!!

Yes there is a

known issue

where it gets stuck on 0.9. Maybe this is the main problem at hand.

check out ... http://answers.unity3d.com/answers/1146173/view.html

and ... http://answers.unity3d.com/answers/1073667/view.html

Some basic working code example....

public void LaunchSoundboard()
    {
    StartCoroutine(_soundboard());
    }
private IEnumerator _soundboard()
    {
    Grid.music.Duck();

    yield return new WaitForSeconds(.2f);

    AsyncOperation ao;
    ao = UnityEngine.SceneManagement
       .SceneManager.LoadSceneAsync("YourSceneName");

    while (!ao.isDone)
        {
        yield return null;
        }

    // here, the new scene IS LOADED
    SoundBoard soundBoard = Object.FindObjectOfType<SoundBoard>();
    if(soundBoard==null) Debug.Log("WOE!");
    soundBoard.SomeFunctionInSoundboardScript();
    }

Note that you wait on ".isDone", rather than watch the float.


(4) #You actually have to have a scene called "preload", which ONLY preloads.

unfortunately the menu scene can not be your preload scene.

You have to actually have a separate preload scene which does nothing but that, "preload".

Note that any "game managers" you have must be on the preload scene. It's a bit annoying but that's how it is.

The purpose of the "preload" scene is to hold any game managers you have.

The only scene that you mark "don't destroy on load" must be only the "preload" scene. It's that simple.

It's a bit of a nuisance but very simple and reliable.

这篇关于WaitForSeconds()Conoutine导致游戏无限期冻结(已编辑)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆