Coroutine停止工作

本文关键字:停止工作 Coroutine | 更新日期: 2023-09-27 18:29:02

我有两个带有协程的脚本。它在第一场比赛中表现得很好,但在第二场比赛中却表现得很差,原因很明显。

它在以下情况下工作:

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityStandardAssets.ImageEffects;
public class GameStartController : MonoBehaviour {
    public Button startButton;
    public GameObject cubeSpawner;
    // Use this for initialization
    private void Start() {
        startButton = startButton.GetComponent<Button>();   
    }
    public void StartGame() {
        EnableCubeSpawner();
        SpawnStartingCubes();
        HideStartMenu();
        StartCoroutine("FocusCamera");
        PlayBackgroundMusic();
    }
    // Enables the cube spawner, so it can start spawning cubes
    private void EnableCubeSpawner() {
        cubeSpawner.SetActive(true);
    }
    private void SpawnStartingCubes() {
        cubeSpawner.GetComponent<CubeSpawner>().GenerateStartingCubes();
    }
    private void PlayBackgroundMusic() {
        var audio = GameObject.FindWithTag("Audio").GetComponent<AudioController>();
        audio.PlayBackgroundMusic();
    }
    private void HideStartMenu() {
        startButton.transform.parent.GetComponent<CanvasGroup>().interactable = false;
        startButton.transform.parent.GetComponent<CanvasGroup>().alpha = 0f;
    }
    private IEnumerator FocusCamera() {
        var camera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
        var velocity = 0f;
        while (Mathf.Abs(camera.GetComponent<DepthOfField>().aperture) > 0.001f) {
            Debug.Log(Mathf.Abs(camera.GetComponent<DepthOfField>().aperture));
            camera.GetComponent<DepthOfField>().aperture = Mathf.SmoothDamp(camera.GetComponent<DepthOfField>().aperture, 0f, ref velocity, 0.3f);
            yield return null;
        }
        camera.GetComponent<DepthOfField>().aperture = 0f;
    }
}

协同程序运行良好,相机光圈从0.6平滑到0。

但是在第二个脚本中没有发生这种情况:

using System.Collections;
using System.Linq;
using UnityEngine;
using UnityStandardAssets.ImageEffects;
public class GameOverController : MonoBehaviour {
    public void EndGame() {
        StartCoroutine("UnfocusCamera");
        DisableCubeSpawner();
        DestroyAllCubes();
        StopBackgroundMusic();
        ShowStartMenu();
    }
    // Disables the cube spawner, so it can stop spawning cubes
    private void DisableCubeSpawner() {
        var cubeSpawner = GameObject.FindWithTag("CubeSpawner");
        cubeSpawner.SetActive(false);
    }
    private void DestroyAllCubes() {
        var gameObjects = FindObjectsOfType(typeof(GameObject));
        foreach (var gameObject in gameObjects.Where(gameObject => gameObject.name.Contains("Cube"))) {
            Destroy(gameObject);
        }
    }
    private void StopBackgroundMusic() {
        var audio = GameObject.FindWithTag("Audio").GetComponent<AudioController>();
        audio.StopBackgroundMusic();
    }
    private void ShowStartMenu() {
        var startMenu = GameObject.FindWithTag("StartMenu");
        startMenu.GetComponent<CanvasGroup>().interactable = true;
        startMenu.GetComponent<CanvasGroup>().alpha = 1f;
    }
    private IEnumerator UnfocusCamera() {
        var camera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
        var velocity = 0f;
        while (camera.GetComponent<DepthOfField>().aperture < 0.6f) {
            Debug.Log(Mathf.Abs(camera.GetComponent<DepthOfField>().aperture));
            camera.GetComponent<DepthOfField>().aperture = Mathf.SmoothDamp(camera.GetComponent<DepthOfField>().aperture, 0.6f, ref velocity, 0.3f);
            yield return null;
        }
//        camera.GetComponent<DepthOfField>().aperture = 0f;
    }
}

它只适用于一帧(光圈从0到0.03),然后停止。为什么会发生这种情况

Coroutine停止工作

如果您销毁(或禁用)一个游戏对象,在附加到它的组件上运行的协同程序将停止。我找不到这方面的主要来源,但这里有另外两个堆栈溢出问题,这就是问题所在:

  • while循环后Unity3d协同程序停止
  • Unity-WaitForSeconds()不起作用

协同程序停止,因为GameOverController所连接的游戏对象已销毁。据推测,Unity在恢复协同之前会检查一个对象是否仍然存在,如果该对象被破坏,Unity不会继续执行它。

为了解决这个问题,你可以推迟销毁游戏对象,直到动画完成(也许把销毁代码放在协程中的while循环之后),或者把组件放在不会被销毁的游戏对象上。

在大多数情况下,这意味着您的对象或脚本变为非活动状态。检查这一点的最佳方法是将OnDisable()方法添加到脚本中,并从中调用日志记录