You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

缩放与旋转周期结束时如何暂停游戏及协程?

Unity游戏无法暂停问题排查与修复

问题描述

我尝试在缩放旋转完成后暂停游戏,先后试过以下操作但均无效:

  • 在代码末尾添加Time.timeScale = 0f; yield break;
  • 将yield return null;替换为yield return new WaitForEndOfFrame();
  • 单独使用Time.timeScale = 0f;,后续添加break;和StopAllCoroutines();

完整脚本如下:

using System.Collections;
using Unity.VisualScripting;
using UnityEngine;

public class Scaling : MonoBehaviour
{
    public GameObject objectToScale;
    public float duration = 1f;
    public Vector3 minSize;
    public Vector3 maxSize;
    public bool scaleUp = false;
    public Coroutine scaleCoroutine;

    public bool automatic = false;
    public bool coroutineIsRunning = false;

    private Quaternion endRotationScaleDown;
    bool rotationAndScalingComplete = false;

    private void Start()
    {

    }

    private void Update()
    {
        if (automatic)
        {
            if (!coroutineIsRunning)
            {
                Scale();
            }
        }
        else
        {
            if (Input.GetKeyDown(KeyCode.G))
            {
                Scale();
            }
        }
    }

    private void Scale()
    {
        scaleUp = !scaleUp;

        if (scaleCoroutine != null)
        {
            StopCoroutine(scaleCoroutine);
        }

        scaleCoroutine = StartCoroutine(ScaleOverTime(objectToScale, scaleUp ? maxSize : minSize, duration, scaleUp));
    }

    private IEnumerator ScaleOverTime(GameObject targetObj, Vector3 toScale, float duration, bool isScalingUp)
    {
        float counter = 0;
        Vector3 startScaleSize = targetObj.transform.localScale;
        Quaternion startRotation = targetObj.transform.rotation;

        Quaternion endRotationScaleUp = Quaternion.Euler(0, 0, 0); // Example end rotation when scaling up
        Quaternion endRotationScaleDown = Quaternion.Euler(0, 180, 0); // Example end rotation when scaling down

        // Generate a random angle (0 or 1)
        int randomAngle = Random.Range(0, 2);

        // Set the rotation angle based on the random value
        float t = (randomAngle == 0) ? 180f : -180f;

        // Choose the end rotation based on the scaling direction.
        Quaternion endRotation = isScalingUp ? endRotationScaleUp : Quaternion.Euler(0, t, 0);

        targetObj.transform.rotation = endRotation;

        coroutineIsRunning = true;

        while (counter < duration)
        {
            counter += Time.deltaTime;
            float lerpFactor = counter / duration;

            targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, lerpFactor);
            targetObj.transform.rotation = Quaternion.Lerp(startRotation, endRotation, lerpFactor);

            if (counter >= duration)
            {
                coroutineIsRunning = false;
                // Ensuring the final state matches exactly
                targetObj.transform.localScale = toScale;
                targetObj.transform.rotation = endRotation;

                rotationAndScalingComplete = true;
            }

            yield return null;
        }

        if (rotationAndScalingComplete)
        {
            Time.timeScale = 0f;
            yield break;
        }
    }
}

问题根源

  1. 成员变量状态未重置:rotationAndScalingComplete是类级成员变量,一旦被设为true后不会自动重置,后续协程会直接触发暂停逻辑,但实际第一次循环内就已经将其设为true,导致逻辑时序混乱。
  2. 暂停逻辑位置错误:暂停代码放在while循环之后,但循环结束时counter >= duration已经成立,此时协程已经完成大部分逻辑,且变量状态异常导致暂停逻辑执行时机不对。

修复方案

方案1:改用局部变量并调整暂停逻辑位置

将rotationAndScalingComplete改为协程内的局部变量,并在缩放旋转完成时直接执行暂停逻辑:

private IEnumerator ScaleOverTime(GameObject targetObj, Vector3 toScale, float duration, bool isScalingUp)
{
    float counter = 0;
    Vector3 startScaleSize = targetObj.transform.localScale;
    Quaternion startRotation = targetObj.transform.rotation;

    Quaternion endRotationScaleUp = Quaternion.Euler(0, 0, 0); // 放大时目标旋转
    // 随机生成旋转角度(180°或-180°)
    float t = Random.Range(0, 2) == 0 ? 180f : -180f;
    Quaternion endRotation = isScalingUp ? endRotationScaleUp : Quaternion.Euler(0, t, 0);

    coroutineIsRunning = true;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        float lerpFactor = counter / duration;

        targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, lerpFactor);
        targetObj.transform.rotation = Quaternion.Lerp(startRotation, endRotation, lerpFactor);

        if (counter >= duration)
        {
            coroutineIsRunning = false;
            // 确保最终状态完全匹配目标值
            targetObj.transform.localScale = toScale;
            targetObj.transform.rotation = endRotation;

            // 缩放旋转完成后立即暂停
            Time.timeScale = 0f;
            yield break; // 终止协程
        }

        yield return null;
    }
}

方案2:保留成员变量但重置状态

如果必须使用类成员变量rotationAndScalingComplete,需要在协程启动时强制重置其状态:

private IEnumerator ScaleOverTime(GameObject targetObj, Vector3 toScale, float duration, bool isScalingUp)
{
    rotationAndScalingComplete = false; // 每次协程启动时重置状态
    // 剩余原有代码...
}

额外优化建议

Time.timeScale = 0仅会暂停依赖时间的逻辑(如Time.deltaTime驱动的动画),但Update函数和协程仍会按帧率执行。如果需要完全屏蔽输入,可添加全局暂停标志:

public bool isPaused = false;

private void Update()
{
    if (isPaused) return; // 暂停时不执行任何交互逻辑
    // 原有Update代码...
}

在设置Time.timeScale = 0时同步设置isPaused = true即可。

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 03:24:53