Unity 3D:如何持续测量固定与可移动卡尺间的距离
卡尺距离测量异常排查与解决
问题场景
使用两个立方体搭建卡尺测量装置:
- 通过PI脚本在参与者前方实例化固定的底部卡尺和可移动的顶部卡尺
- 通过CC脚本控制顶部卡尺上下移动,碰撞到底部卡尺时禁止向下移动
- 给顶部卡尺挂载
LiveDistanceBetweenCalipers脚本实时测量Y轴距离,但出现两个异常:- 场景中绘制的绿色连线位置与顶部卡尺视觉位置不符
- 输出的距离数值和实际视觉距离不匹配
现有代码
1. PI脚本(卡尺实例化)
public void InstantiateCalipersAtDistance() { if (headCamera != null) { float heightInMeters = participantHeightCm / 100f; float distance = heightInMeters; // Distance in front of the participant Vector3 headPosition = headCamera.transform.position; // Get the head camera position Vector3 forward = transform.forward; Vector3 baseCaliperPosition = headPosition + forward * distance; caliperSeparationDistance = Random.Range(0.05f, 0.25f); // Random distance between 0.05 and 0.25 meters baseCaliper = Instantiate(baseCaliperPrefab, baseCaliperPosition, Quaternion.identity); movingCaliper = Instantiate(movingCaliperPrefab, baseCaliperPosition + new Vector3(0, caliperSeparationDistance, 0), Quaternion.identity); } else { Debug.LogError("Head camera is not assigned."); } }
2. CC脚本(顶部卡尺移动控制)
void Update() { if (canMoveUp) { if (Input.GetKey(KeyCode.UpArrow)) { transform.Translate(0, speed * Time.deltaTime, 0); } } if (canMoveDown) { if (Input.GetKey(KeyCode.DownArrow)) { transform.Translate(0, -speed * Time.deltaTime, 0); } } } void OnCollisionEnter(Collision collision) { if (collision.gameObject.name == "BaseCaliper(Clone)") { canMoveDown = false; } } void OnCollisionExit(Collision collision) { if (collision.gameObject.name == "BaseCaliper(Clone)") { canMoveDown = true; } }
3. 距离测量脚本
using UnityEngine; public class LiveDistanceBetweenCalipers : MonoBehaviour { [SerializeField] public GameObject obj; // Reference to the other caliper (base caliper) public float yDistanceBetweenObjects; // Variable to store the Y distance private void Update() { if (obj != null) { // Calculate the Y distance between this object (moving caliper) and the other object (base caliper) yDistanceBetweenObjects = Mathf.Abs(transform.position.y - obj.transform.position.y); // Print the Y distance to the console Debug.Log("Y Distance between calipers: " + yDistanceBetweenObjects); // Optionally, draw a line between the objects for visualization Debug.DrawLine(transform.position, obj.transform.position, Color.green); } else { Debug.LogWarning("Reference to the other caliper (base caliper) is missing."); } } }
排查与解决方案
1. 预制体Pivot点偏移(最可能原因)
- 问题本质:
transform.position返回的是物体Pivot点的世界坐标,如果两个卡尺预制体的Pivot不在同一基准位置(比如一个在底部,一个在几何中心),计算出的Y差会和视觉距离不符,连线也会偏移。 - 解决步骤:
- 打开底部和顶部卡尺的预制体
- 用Unity编辑器的Rect Tool(快捷键T),将两个卡尺的Pivot调整到同一基准(比如都设置在物体底部,确保测量的是垂直方向的实际视觉距离)
- 或直接在Inspector的Transform组件中手动修改Pivot值(比如底部基准的话,Pivot的Y值设为0)
2. 脚本挂载对象错误
- 问题本质:如果
LiveDistanceBetweenCalipers脚本挂载在卡尺的子物体上,transform.position获取的是子物体位置,而非卡尺根物体位置,导致连线和数值错误。 - 解决步骤:
- 确认脚本挂载对象是卡尺的根GameObject
- 若必须挂载在子物体上,修改代码获取根物体位置:
// 替换原位置计算逻辑 Vector3 ownRootPosition = GetComponentInParent<Transform>().position; Vector3 targetRootPosition = obj.GetComponentInParent<Transform>().position; yDistanceBetweenObjects = Mathf.Abs(ownRootPosition.y - targetRootPosition.y); Debug.DrawLine(ownRootPosition, targetRootPosition, Color.green);
3. 手动引用赋值错误
- 问题本质:手动在Inspector中拖入底部卡尺时,可能误拖了无关对象(比如父物体、其他克隆体),导致
obj引用错误。 - 解决步骤:
去掉手动赋值,改为实例化时自动绑定引用,修改PI脚本的实例化代码:// 实例化后添加以下代码 var distanceScript = movingCaliper.GetComponent<LiveDistanceBetweenCalipers>(); if (distanceScript != null) { distanceScript.obj = baseCaliper; }
4. 碰撞体与模型位置不匹配
- 问题本质:如果卡尺的碰撞体位置和视觉模型偏移,碰撞停止时的实际位置和视觉贴合位置有偏差,进而影响距离计算。
- 解决步骤:
- 打开预制体,调整碰撞体的Position和Size,让它完全贴合视觉模型
- 可选:将
OnCollisionEnter/Exit改为OnTriggerEnter/Exit(需勾选碰撞体的Is Trigger),避免物理碰撞带来的位置偏移
内容的提问来源于stack exchange,提问作者Mr Awesome
相关产品推荐
相关产品推荐

