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

如何通过协程修改Unity中bg对象旋转角并兼容按键控制?

解决方案:Unity中同时支持按键与协程独立控制对象旋转并同步目标位置

核心问题分析

  • Update中每次检测_testFlag都会启动新协程,导致多协程冲突
  • 目标位置计算依赖动态更新的_currentTargetPos,旋转叠加逻辑混乱
  • 按键与协程直接操作旋转值,导致两者控制逻辑互相干扰

可行解决方案

1. 统一目标旋转值,分离控制与执行

将bg的旋转目标值单独维护,按键和协程仅修改这个目标值,在Update中统一平滑过渡到目标旋转,保证两种控制方式互不干扰。

2. 保存目标对象的初始相对偏移

不再动态更新_currentTargetPos,而是保存_target相对于bg的初始本地偏移量,无论bg如何旋转,都能通过旋转矩阵计算正确的目标位置。

3. 防止协程重复启动

添加协程运行标志,确保同一时间只有一个协程执行旋转控制。

修改后的完整代码

using System.Collections;
using UnityEngine;

public class InputController : MonoBehaviour
{
    [SerializeField] private Transform bg; // 需在Inspector中赋值
    [SerializeField] private Transform _target;
    [SerializeField] private bool _testFlag; // 在编辑器中修改触发测试

    private Vector3 _initialLocalOffset; // _target相对于bg的初始本地偏移
    private float _targetRotationZ; // bg的目标Z轴旋转值
    private bool _isCoroutineRunning; // 协程运行标志,避免重复启动

    void Start()
    {
        // 保存初始相对偏移:bg本地空间下_target的位置
        _initialLocalOffset = bg.InverseTransformPoint(_target.position);
        // 初始化目标旋转为当前bg的旋转角度
        _targetRotationZ = bg.rotation.eulerAngles.z;
    }

    void Update()
    {
        // 按键控制:修改目标旋转值
        if (Input.GetKey(KeyCode.D))
        {
            _targetRotationZ -= 60f * Time.deltaTime;
        }
        else if (Input.GetKey(KeyCode.A))
        {
            _targetRotationZ += 60f * Time.deltaTime;
        }

        // 平滑过渡到目标旋转
        bg.rotation = Quaternion.Lerp(bg.rotation, Quaternion.Euler(0, 0, _targetRotationZ), 10f * Time.deltaTime);

        // 更新_target的位置
        UpdateTargetPosition();

        // 触发测试协程,确保仅启动一次
        if (_testFlag && !_isCoroutineRunning)
        {
            StartCoroutine(TestRotateToTargetAngle());
            _testFlag = false; // 立即重置标志,避免重复触发
        }
    }

    /// <summary>
    /// 根据bg当前旋转计算_target的正确位置
    /// </summary>
    private void UpdateTargetPosition()
    {
        // 将初始本地偏移通过bg的旋转转换为世界空间位置
        Vector3 worldPosition = bg.TransformPoint(_initialLocalOffset);
        _target.position = worldPosition;
    }

    /// <summary>
    /// 协程控制bg旋转到指定角度,与按键控制独立生效
    /// </summary>
    private IEnumerator TestRotateToTargetAngle()
    {
        _isCoroutineRunning = true;
        float startRotation = _targetRotationZ;
        float targetAngle = 20f; // 目标旋转角度
        float timer = 0f;
        float rotationDuration = 2f;

        while (timer < rotationDuration)
        {
            timer += Time.deltaTime;
            float t = Mathf.Clamp01(timer / rotationDuration);
            // 使用LerpAngle处理角度环绕(如350°到10°的平滑过渡)
            _targetRotationZ = Mathf.LerpAngle(startRotation, targetAngle, t);
            yield return null;
        }

        // 确保最终旋转准确设置到目标角度
        _targetRotationZ = targetAngle;
        _isCoroutineRunning = false;
    }
}

关键说明

  • 旋转控制分离:按键和协程仅修改_targetRotationZ,Update中统一执行旋转过渡,避免直接操作bg旋转导致的冲突。
  • 相对偏移保存:基于初始相对位置计算目标位置,不会出现旋转后位置偏移累积的问题。
  • 协程防重复:_isCoroutineRunning标志避免多协程同时修改旋转值,保证控制逻辑稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:05:37