Unity C#开发中Vector3传变量触发Rigidbody NaN报错问题咨询
问题描述
无C#基础,计划在大学一年级入学前暑假自学Unity,当前正在开发角色行走控制功能:实现角色朝向转向逻辑时,正向移动功能正常,但执行转向操作后,即使把角色旋转角度重置为0,后续控制角色前进时会触发报错:rigidbody.force assign attempt for 'Fox' is not valid. Input force is {NaN, 0.000000, NaN}.
原有实现代码如下:
using System.Collections; using System.Collections.Generic; using System; using UnityEngine; //private quaternion rotation; public class PlayerController : MonoBehaviour { public Rigidbody rb; public float moveSpeed = 10f; public float rotationSpeed = 7f; public float rotation; private float xInput; private float zInput; private float directionInput; public GameObject player; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { ProcessInputs(); if (Input.GetKeyDown("a")) { player.transform.Rotate(0f, -(rotationSpeed), 0f, Space.World); } if (Input.GetKeyDown("d")) { player.transform.Rotate(0f, rotationSpeed, 0f, Space.World); } } private void FixedUpdate() { //Movement Move(); } private void ProcessInputs() { xInput = Input.GetAxis("Horizontal"); zInput = Input.GetAxis("Vertical"); } private void Move() { //float xMove; //float zMove; rotation = player.transform.rotation.y; if (rotation == 0) { float xMove = 0f; float zMove = zInput; rb.AddForce(new Vector3(xMove, 0f, zMove) * moveSpeed); } else if (rotation <= 90) { float zMove = (float)(Math.Sqrt((zInput*zInput) - ((zInput * (1/(Math.Cos(90 - rotation)))) * (zInput * (1/(Math.Cos(90 - rotation))))) )); float xMove = (float)(Math.Sqrt((zInput*zInput) - ((zInput * (1/(Math.Sin(90 - rotation)))) * (zInput * (1/(Math.Sin(90 - rotation))))) )); rb.AddForce(new Vector3(xMove, 0f, zMove) * moveSpeed); } //Math.Sqrt((zInput*zInput) - ((zInput * (1/(Math.Cos(rotation)))) * (zInput * (1/(Math.Cos(rotation))))) ); //Math.Sqrt((zInput*zInput) - ((zInput * (1/(Math.Sin(rotation)))) * (zInput * (1/(Math.Sin(rotation))))) ); //rb.AddForce(new Vector3(0f, 0f, zInput) * moveSpeed); //rb.AddForce(new Vector3(xMove, 0f, zMove) * moveSpeed); } }
手动编写的旋转后移动分量计算逻辑存在缺陷,导致传入Vector3的分量出现NaN值,需要定位问题原因并获取正确实现方案。
问题根因
- 角度读取方式错误:
player.transform.rotation是四元数(Quaternion)类型,其y分量是四元数的内部计算值,不是直观的0-360度欧拉角,取值范围为-1到1,直接把这个值传入三角函数计算得到的结果完全不符合预期。 - 数学计算逻辑存在漏洞:手动实现的分量计算公式中,根号下的运算结果极易出现负数——当三角函数计算出的系数大于1时,平方差结果为负,对负数执行开平方运算会直接得到NaN(非数字)值,这就是刚体力赋值报错的直接原因。
- 转向触发逻辑不合理:使用
Input.GetKeyDown()检测转向输入,该API仅在按键按下的第一帧触发,按住按键不会持续触发转向,操作逻辑不符合常规游戏控制习惯。 - 帧率相关逻辑缺失:转向计算未考虑帧率差,不同设备上转向速度会随帧率波动,帧率越高转向越快。
正确实现方案
不需要手动编写三角函数计算移动分量,Unity原生提供了方向转换API,可以直接将角色本地空间的移动输入转换为世界空间的移动方向,完全规避手动计算带来的错误,代码逻辑更简洁稳定。
修正后完整代码如下:
using UnityEngine; public class PlayerController : MonoBehaviour { public Rigidbody rb; public float moveSpeed = 10f; public float rotationSpeed = 7f; private float xInput; private float zInput; void Update() { ProcessInputs(); // 按住A/D时持续转向,改用GetKey持续检测输入,乘以deltaTime保证不同帧率下转向速度一致 if (Input.GetKey(KeyCode.A)) { transform.Rotate(0f, -rotationSpeed * Time.deltaTime, 0f, Space.World); } if (Input.GetKey(KeyCode.D)) { transform.Rotate(0f, rotationSpeed * Time.deltaTime, 0f, Space.World); } } private void FixedUpdate() { Move(); } private void ProcessInputs() { xInput = Input.GetAxis("Horizontal"); zInput = Input.GetAxis("Vertical"); } private void Move() { // 本地移动方向:x轴对应左右,z轴对应前后,归一化保证斜向移动速度和正向一致 Vector3 localMoveDir = new Vector3(xInput, 0f, zInput).normalized; // 将本地方向转换为世界空间方向,自动适配角色当前朝向,无需手动计算三角函数 Vector3 worldMoveDir = transform.TransformDirection(localMoveDir); rb.AddForce(worldMoveDir * moveSpeed); } }
额外优化提示
- 给Rigidbody组件设置合适的
Drag(阻力)值,避免角色移动后一直滑动无法停下。 - 如果不需要完全手动控制转向,可以直接用
Quaternion.LookRotation配合移动输入实现更顺滑的自动朝向,不需要单独写A/D转向逻辑。
内容的提问来源于stack exchange,提问作者Sparkaward
相关产品推荐
相关产品推荐

