在使用timeScale 0f暂停游戏时,如何暂停/恢复协程? [英] How can I pause/resume a Coroutine when pausing the game with timeScale 0f?

查看:598
本文介绍了在使用timeScale 0f暂停游戏时,如何暂停/恢复协程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如此协程.假设我有一个ui按钮可以暂停游戏:

For example this Coroutine. Let's say I have a ui button that pause the game :

Time.timeScale = 0f;

但是timeScale在协程上不起作用.

But timeScale is not working on Coroutines.

如果我在游戏中有很多协程,有没有办法找到所有的协程,然后在它们上循环并暂停它们,还是我需要在每个协程中添加一个暂停循环?

And if I have many Coroutines in the game is there a way to find all the Coroutines and then loop on them and pause them or do I need to add a pause loop to each Coroutine ?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PostProcessing;

public class DepthOfField : MonoBehaviour
{
    public UnityEngine.GameObject player;
    public PostProcessingProfile postProcessingProfile;
    public bool dephOfFieldFinished = false;
    public LockSystem playerLockMode;

    private Animator playerAnimator;
    private float clipLength;
    private Coroutine depthOfFieldRoutineRef;

    void Start()
    {
        if (depthOfFieldRoutineRef != null)
        {
            StopCoroutine(depthOfFieldRoutineRef);
        }

        playerAnimator = player.GetComponent<Animator>();

        AnimationClip[] clips = playerAnimator.runtimeAnimatorController.animationClips;
        foreach (AnimationClip clip in clips)
        {
            clipLength = clip.length;
        }

        var depthOfField = postProcessingProfile.depthOfField.settings;
        depthOfField.focalLength = 300;
        StartCoroutine(changeValueOverTime(depthOfField.focalLength, 1, clipLength));
        postProcessingProfile.depthOfField.settings = depthOfField;
    }

    IEnumerator changeValueOverTime(float fromVal, float toVal, float duration)
    {
        playerLockMode.PlayerLockState(true, true);

        float counter = 0f;

        while (counter < duration)
        {
            var dof = postProcessingProfile.depthOfField.settings;

            if (Time.timeScale == 0)
                counter += Time.unscaledDeltaTime;
            else
                counter += Time.deltaTime;

            float val = Mathf.Lerp(fromVal, toVal, counter / duration);

            dof.focalLength = val;
            postProcessingProfile.depthOfField.settings = dof;

            yield return null;
        }

        playerAnimator.enabled = false;
        dephOfFieldFinished = true;
        depthOfFieldRoutineRef = null;
    }
}

推荐答案

您可以使用观察者模式并为游戏创建一组状态,例如:LoadingGamePausedLoadingLevel等,并使用事件来掌握状态变化并采取适当的措施.

You could use the Observer Pattern and create a set of states for the game like: LoadingGame, Paused, LoadingLevel etc and use events to hook into state changes and take appropriate action.

例如:

 public enum GameState {
        LoadingGame,
        LoadingLevel,
        Paused,
        ...
    }

然后在全局管理器中,在状态更改时触发一个事件:

Then in a global manager, fire off an event when the state changes:

   public event Action<GameState, GameState> OnGameStateChange;

   public void SwitchGameState (GameState to) {
        previousState = CurrentState;
        CurrentState = to;

        switch (to) {
            case GameState.Paused:
                ...
                break;
            ...
        }

        OnGameStateChange?.Invoke (previousState, CurrentState);
    }

任何其他组件,例如您的DepthOfField,都可以监听事件并采取适当的措施:

Any other components, like your DepthOfField can listen to the event and take appropriate action:

    void Awake () {
        gameManager.OnGameStateChange += HandleGameStateChange;
    }

    void HandleGameStateChange (GameState from, GameState to) {
        switch (to) {
            case GameState.Paused:
                // stop or pause couroutine etc
                StartCoroutine(coroutine);
                break;
        }
    }

这篇关于在使用timeScale 0f暂停游戏时,如何暂停/恢复协程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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