Unity中如何将物体从碰撞点平滑移动至目标物体末端?
Unity中实现球体碰撞后平滑移动至方形Sprite末端的问题修复
原脚本存在的核心问题:
elapsedTime未重置:作为类成员变量,第一次协程执行后值会保留,后续碰撞触发协程时会直接跳过循环,导致移动不生效。- 末端位置计算逻辑错误:
contactPoint.x是世界坐标,直接与Collider的尺寸做运算无法得到正确的末端位置,需要基于Roller的世界坐标范围计算。 - 物理组件冲突:直接修改
transform.position时,Rigidbody2D的物理属性(比如重力、碰撞)会干扰移动,应该暂时禁用物理或者使用Rigidbody的移动方法。 - 变量拼写错误:
rollerLegth应为rollerLength,属于不良编码习惯。
修正后的完整脚本:
public class HandleRollerMovement : MonoBehaviour { private float desiredDuration = 1f; private BoxCollider2D boxCollider2D; private float rollerLength; private void Start() { boxCollider2D = GetComponent<BoxCollider2D>(); rollerLength = boxCollider2D.bounds.size.x; } private void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.CompareTag("Egg")) { var eggRigidBody = collision.gameObject.GetComponent<Rigidbody2D>(); if (eggRigidBody == null) return; var startPosition = eggRigidBody.transform.position; if (collision.contacts.Length == 0) return; var contactPoint = collision.contacts[0].point; // 获取Roller的世界坐标左右边界 var rollerLeft = boxCollider2D.bounds.min.x; var rollerRight = boxCollider2D.bounds.max.x; // 根据碰撞点位置确定移动到Roller的哪一端 Vector3 endPosition; if (contactPoint.x < boxCollider2D.bounds.center.x) { endPosition = new Vector3(rollerRight, startPosition.y, 0); } else { endPosition = new Vector3(rollerLeft, startPosition.y, 0); } StartCoroutine(MoveEgg(eggRigidBody, startPosition, endPosition)); } } private IEnumerator MoveEgg(Rigidbody2D eggRb, Vector3 startPos, Vector3 endPos) { float elapsedTime = 0f; // 暂时禁用物理,避免干扰平滑移动 var originalBodyType = eggRb.bodyType; eggRb.bodyType = RigidbodyType2D.Kinematic; while (elapsedTime < desiredDuration) { var currentPos = Vector3.Lerp(startPos, endPos, elapsedTime / desiredDuration); eggRb.MovePosition(currentPos); elapsedTime += Time.deltaTime; yield return null; } // 确保最终位置准确 eggRb.MovePosition(endPos); // 恢复刚体原有物理状态 eggRb.bodyType = originalBodyType; } }
关键修改说明:
- 重置计时变量:将
elapsedTime改为协程内的局部变量,每次触发协程都会重新初始化,保证每次移动都能正常执行。 - 修正位置计算:通过
bounds.min.x和bounds.max.x获取Roller的世界坐标边界,根据碰撞点相对于Roller中心的位置,判断移动到左端还是右端,逻辑更准确。 - 处理物理干扰:移动时将Rigidbody设为
Kinematic,避免重力、碰撞等物理效果打断平滑移动,完成后恢复原属性。 - 规范移动方式:使用Rigidbody2D的
MovePosition方法而非直接修改transform.position,保证物理状态的一致性。 - 优化参数传递:将协程所需参数作为参数传入,避免依赖类成员变量,逻辑更清晰。
内容的提问来源于stack exchange,提问作者Coder
相关产品推荐
相关产品推荐

