Unity Start()调用ApplyRadius改绕转半径报position赋值异常
问题成因
报错直接原因是Transform.position赋值时Y轴传入了NaN值,具体触发逻辑如下:
- 首要触发点是除零运算:
delay字段未手动赋值时默认值为0。第一帧Update执行流程为:Start()调用ApplyRadius完成半径设置后进入Update,time累加首帧时间增量(约0.02s),此时time > delay(0.02>0)条件成立,逻辑块会将time重置为0,后续执行高度Lerp计算时,插值系数为time / delay = 0 / 0 = NaN,Mathf.Lerp接收NaN系数后直接返回NaN,赋值给Y轴触发报错。运行时修改半径时已过首帧初始化阶段,若此时你已设置非0的delay值就不会触发该异常。 - 潜在触发点:若脚本挂载物体初始位置与
objToRotateAround位置完全重合,ApplyRadius中计算两点方向向量时会得到零向量,零向量调用normalized属性会返回各分量为NaN的向量,直接导致position赋值携带NaN,污染后续所有位置计算逻辑。 - 初始值隐患:
prevHeight、height为私有float字段,默认初始值为0,首次插值前未初始化高度值,会出现首帧高度从0跳变的问题。
修复方案
所有原有变量、API、核心逻辑保持不变,仅添加异常防护和初始化逻辑,修改点如下:
- Start阶段提前初始化高度字段,避免首帧跳变
- ApplyRadius中添加空引用、零向量校验,避免归一化得到NaN
- 插值计算前添加除零保护,delay为0时直接取目标高度
- 给配置类字段加合理默认值,避免默认0导致的逻辑异常
修复后完整代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class RotateAroundPoint : MonoBehaviour { public GameObject objToRotateAround; [Header("The axis by which it will rotate around")] public Vector3 axis = Vector3.up; [Header("Angle covered per Second")] public float anglePerSecond = 30f; [SerializeField] private float radius = 5f; public float upperLimit = 5f; public float lowerLimit = 1f; public float delay = 2f; private float height; private float prevHeight; private float time; private float lastRadius; private void Start() { // 初始化高度值,避免首帧跳变 prevHeight = transform.position.y; height = Random.Range(lowerLimit, upperLimit); time = 0; ApplyRadius(); } void Update() { // Check if the radius was changed if (!Mathf.Approximately(radius, lastRadius)) { ApplyRadius(); } time += Time.deltaTime; if (time > delay) { prevHeight = height; height = Random.Range(lowerLimit, upperLimit); time = 0; } // Rotate with a frame-rate independent angle per second transform.RotateAround(objToRotateAround.transform.position, axis, anglePerSecond * Time.deltaTime); // For the Lerp you want a factor between 0 and 1 // not between 0 and delay // => divide by delay gives you a factor between 0 and 1 float lerpFactor = delay <= 0 ? 1f : time / delay; transform.position = new Vector3(transform.position.x, Mathf.Lerp(prevHeight, height, lerpFactor), transform.position.z); } private void ApplyRadius() { if (objToRotateAround == null) return; // Get the direction vector from the pivot to your current object position Vector3 offset = transform.position - objToRotateAround.transform.position; // 零向量校验,避免归一化得到NaN if (offset == Vector3.zero) { offset = objToRotateAround.transform.forward; } var direction = offset.normalized; // set your object in the same direction but at distance of radius transform.position = objToRotateAround.transform.position + direction * radius; lastRadius = radius; } }
修复后首帧初始化不会再触发NaN报错,运行时修改半径的原有逻辑完全保留,同时兼容delay被设为0的极端配置场景。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

