Unity复刻Breakout游戏时Ball对象NaN位置错误原因求助
问题
我正在Unity中复刻Atari Breakout游戏(一款通过底部可控paddle反弹移动小球来击破方块的游戏)。我在Ball脚本中添加了一段代码,用于根据小球与paddle碰撞时的相对位置控制小球的反弹角度,代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Ball : MonoBehaviour { public float speed = 5; float deltaX; float deltaY; double angleConst = 7 * System.Math.PI / 8 / 1.8; // Start is called before the first frame update void Start() { transform.position = new Vector2(Random.Range(-6, 6), -1); deltaX = Random.Range(-1 * (float)System.Math.Sqrt(speed), (float)System.Math.Sqrt(speed)); deltaY = (float)System.Math.Sqrt(speed - System.Math.Pow(deltaX, 2)); } void OnTriggerEnter2D(Collider2D col) { if(col.gameObject.tag == "Player") { // ball's horizontal position on the paddle double positionDiff = GameObject.Find("Paddle").transform.position.x - transform.position.x + 0.9; deltaX = (float)System.Math.Sqrt(speed * System.Math.Cos(positionDiff * angleConst)); deltaY = (float)System.Math.Sqrt(-1 * speed * System.Math.Sin(positionDiff * angleConst)); } else if(col.gameObject.tag == "Horizontal") { deltaY = -1 * deltaY; } else if(col.gameObject.tag == "Vertical") { deltaX = -1 * deltaX; } } // Update is called once per frame void FixedUpdate() { transform.Translate(Vector2.right * deltaX * Time.fixedDeltaTime); transform.Translate(Vector2.down * deltaY * Time.fixedDeltaTime); } }
当我在paddle碰撞时的deltaX、deltaY重新赋值中添加Math.Sqrt函数后,小球接触paddle就会持续弹出错误:“transform.position assign attempt for 'Ball' is not valid. Input position is { NaN, NaN, NaN }”,直至程序停止。未添加平方根函数前脚本运行正常,我查阅资料得知该错误可能与除零有关,但未发现脚本中有除零场景,请问是什么导致输入返回NaN?
分析与解决
出现NaN的核心原因是你给Math.Sqrt()传入了负数——平方根函数对负数计算会直接返回NaN,后续用这个NaN值更新小球位置,就会触发Unity的位置无效错误。
具体看代码里的两处问题:
- 计算
deltaX时:speed * System.Math.Cos(positionDiff * angleConst),当Cos返回负数时,整个表达式结果为负,传给Sqrt就会得到NaN。 - 计算
deltaY时:-1 * speed * System.Math.Sin(positionDiff * angleConst),当Sin返回正数时,整个表达式结果为负,同样会让Sqrt返回NaN。
另外还有几个潜在问题需要注意:
GameObject.Find("Paddle")每次碰撞都执行查找,效率极低,建议提前用[SerializeField] private GameObject paddle;在编辑器中赋值,避免运行时重复查找。- 你试图用平方根拆分速度分量的逻辑本身就有问题,正确的做法是先计算角度对应的方向向量,再乘以速度值,而非对三角函数结果开平方。
修正后的代码示例:
void OnTriggerEnter2D(Collider2D col) { if(col.gameObject.tag == "Player") { // 计算小球相对于 paddle 中心的水平偏移比例(假设 paddle 宽度为1.8) float paddleCenterX = GameObject.Find("Paddle").transform.position.x; float relativeOffset = (transform.position.x - paddleCenterX) / 1.8f; // 限制反弹角度范围,避免垂直或接近垂直的反弹 double bounceAngle = relativeOffset * (7 * System.Math.PI / 8); // 根据角度计算速度分量 deltaX = (float)(speed * System.Math.Cos(bounceAngle)); // 碰撞 paddle 后小球必须向上反弹,确保Y分量为正 deltaY = Mathf.Abs((float)(speed * System.Math.Sin(bounceAngle))); } else if(col.gameObject.tag == "Horizontal") { deltaY = -1 * deltaY; } else if(col.gameObject.tag == "Vertical") { deltaX = -1 * deltaX; } }
内容的提问来源于stack exchange,提问作者JustAnotherMusician7
相关产品推荐
相关产品推荐

