Unity2D基于子对象计算父物体旋转时出现异常抖动问题咨询
Unity物体旋转逻辑异常抖动问题排查
问题复现场景
- 场景内共3个对象:
RotatePoint(黑色圆形,根父对象)、Square(红色矩形,子对象)、Circle(白色圆形,子对象),三者组成层级组合,RotatePoint为旋转中心
- 预期实现效果:以RotatePoint为中心,整个对象组合跟随鼠标位置平滑旋转
- 初始挂载在RotatePoint上的实现脚本如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestRotate : MonoBehaviour { //旋转中心对象 public Transform rotatePoint; //白色圆形子对象 public Transform circle; void Update() { Vector3 MouseWorldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition); Debug.LogWarning("circle.pos" + circle.position); Vector3 direction = MouseWorldPoint - circle.position; float radians = Mathf.Atan2(direction.y, direction.x); float degrees = radians * Mathf.Rad2Deg; rotatePoint.eulerAngles = new Vector3(0,0,degrees); Debug.DrawLine(circle.position,MouseWorldPoint,Color.red); } }
异常表现
- 鼠标距离Circle子对象较远时,旋转效果符合预期,整个组合以RotatePoint为中心跟随鼠标平滑旋转

- 鼠标移动到距离Circle子对象一定阈值范围内时,整个组合开始弹跳抖动,距离越近越容易出现无规律360度旋转的问题

临时修复方案
将方向计算的参考坐标从子对象Circle的位置替换为父对象RotatePoint自身位置后,所有距离下的旋转效果均恢复正常,修改后代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestRotate : MonoBehaviour { //旋转中心对象 public Transform rotatePoint; //白色圆形子对象 public Transform circle; void Update() { Vector3 MouseWorldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition); //将参考点从circle.position修改为rotatePoint.position Vector3 direction = MouseWorldPoint - rotatePoint.position; Debug.LogWarning("circle.pos" + circle.position); float radians = Mathf.Atan2(direction.y, direction.x); float degrees = radians * Mathf.Rad2Deg; rotatePoint.eulerAngles = new Vector3(0,0,degrees); Debug.DrawLine(circle.position,MouseWorldPoint,Color.red); } }

问题成因说明
该问题不属于Unity引擎Bug,是典型的闭环反馈逻辑错误,触发逻辑如下:
- 初始代码形成了自反馈循环:用会随父对象旋转改变世界坐标的子对象位置作为角度计算参考点,计算出的角度又反过来赋值给父对象修改旋转状态,父对象旋转会立刻改变子对象的世界坐标,形成因果闭环。
- 鼠标距离Circle较远时,单帧旋转带来的Circle位置偏移量,相对于鼠标到Circle的总距离占比极小,计算出的角度误差可以忽略,因此看起来运行正常。
- 鼠标距离Circle极近时,单帧旋转带来的Circle位置偏移量占总距离的比例会被急剧放大:当前帧算出角度A赋值给父对象,父对象旋转后Circle立刻移动到新位置,此时鼠标相对于新位置的方向直接跳到角度B,下一帧又按角度B旋转,Circle再次位移,方向又跳到角度C,最终表现为无规律抖动、疯狂旋转。
- 参考点替换为RotatePoint后问题消失,是因为RotatePoint作为旋转中心,旋转时自身世界坐标不会发生任何变化,计算参考点固定,不会触发反馈循环,因此旋转始终稳定。
额外注意:2D场景下使用
Camera.main.ScreenToWorldPoint转换鼠标坐标时,需要给鼠标屏幕坐标设置正确的Z值(即正交相机到2D平面的距离),否则坐标转换结果也会出现偏差。
内容的提问来源于stack exchange,提问作者li ming
相关产品推荐
相关产品推荐

