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

While循环导致游戏卡顿,TBS游戏中还有哪些实现物体旋转的方法?

解决TBS游戏回合结束光源平滑旋转的几种方法

嘿,很高兴看到你在做TBS的昼夜光源系统!之前用While循环导致卡顿太正常了——因为While会在单帧内强行执行完所有旋转逻辑,直接阻塞主线程,游戏自然就卡了。结合你已经实现的回合事件机制,我给你推荐几个顺滑且高效的实现方式:

1. 用协程(Coroutine)分帧平滑旋转

协程是Unity里处理分步任务的绝佳工具,它能让旋转逻辑分散到多帧执行,完全不会卡。你可以在接收回合事件的脚本里,收到阶段t后启动协程,逐步将光源旋转到对应角度(8个阶段对应每步45度,360/8):

// 订阅回合变更事件
void OnEnable()
{
    TurnManager.Time_Change += OnTimePhaseChanged;
}

void OnDisable()
{
    TurnManager.Time_Change -= OnTimePhaseChanged;
}

private void OnTimePhaseChanged(int t)
{
    // 计算当前阶段对应的目标Y轴旋转角度
    float targetYAngle = (t - 1) * 45f;
    // 启动旋转协程,这里可以自定义旋转时长
    StartCoroutine(RotateLightToTarget(targetYAngle, 1.2f));
}

private IEnumerator RotateLightToTarget(float targetYAngle, float rotationDuration)
{
    float startYAngle = transform.eulerAngles.y;
    // 计算最短旋转路径,避免绕大圈(比如从350度转到10度,直接转20度而不是340度)
    float angleDifference = Mathf.DeltaAngle(startYAngle, targetYAngle);
    float elapsedTime = 0f;

    while (elapsedTime < rotationDuration)
    {
        elapsedTime += Time.deltaTime;
        // 用平滑曲线让旋转开头结尾更自然,避免生硬的启停
        float smoothProgress = Mathf.SmoothStep(0f, 1f, elapsedTime / rotationDuration);
        float currentYAngle = startYAngle + angleDifference * smoothProgress;
        
        transform.rotation = Quaternion.Euler(0f, currentYAngle, 0f);
        yield return null; // 等待下一帧再执行
    }

    // 最后确保光源精准到位,避免浮点误差
    transform.rotation = Quaternion.Euler(0f, targetYAngle, 0f);
}

2. 在Update()中逐帧插值旋转

如果不想用协程,也可以用Update配合状态变量来实现,逻辑和协程类似,只是把循环放到Update里:

private bool isRotating = false;
private float startAngle;
private float targetAngle;
private float rotationStartTime;
private float rotationDuration = 1.2f;

void OnEnable()
{
    TurnManager.Time_Change += OnTimePhaseChanged;
}

void OnDisable()
{
    TurnManager.Time_Change -= OnTimePhaseChanged;
}

private void OnTimePhaseChanged(int t)
{
    targetAngle = (t - 1) * 45f;
    startAngle = transform.eulerAngles.y;
    rotationStartTime = Time.time;
    isRotating = true;
}

void Update()
{
    if (!isRotating) return;

    float elapsedTime = Time.time - rotationStartTime;
    if (elapsedTime >= rotationDuration)
    {
        transform.rotation = Quaternion.Euler(0f, targetAngle, 0f);
        isRotating = false;
        return;
    }

    float smoothProgress = Mathf.SmoothStep(0f, 1f, elapsedTime / rotationDuration);
    float currentAngle = startAngle + Mathf.DeltaAngle(startAngle, targetAngle) * smoothProgress;
    transform.rotation = Quaternion.Euler(0f, currentAngle, 0f);
}

3. 用Animator动画系统实现(适合复杂视觉效果)

如果你的光源不仅需要旋转,还需要配合亮度变化、颜色渐变等效果,用Unity的动画系统会更方便:

  • 给光源添加Animator组件,创建一个Animator Controller
  • 添加一个Int类型的参数TimePhase,然后制作8个动画片段,每个片段对应一个阶段的旋转(可以加上灯光参数的动画)
  • 在状态机里设置条件:当TimePhase等于对应数值时,切换到对应的动画状态
  • 最后在事件回调里直接设置参数:
    private void OnTimePhaseChanged(int t)
    {
        GetComponent<Animator>().SetInteger("TimePhase", t);
    }
    

为什么之前的While循环会卡顿?

简单来说,While循环是同步阻塞的——它会在一帧内反复执行旋转逻辑,直到循环结束,期间主线程无法处理其他游戏逻辑(比如渲染、输入),所以游戏会出现明显卡顿。而上面的方法都是异步分帧处理,每帧只做一小部分旋转计算,完全不会占用过多主线程资源。

内容的提问来源于stack exchange,提问作者Rich Cat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:42:07