Unity2D Rigidbody2D Velocity异常:多次操作后残留速度求助
问题描述
需求:释放鼠标按键时,为Rigidbody2D物体添加速度,鼠标按住时长决定速度力度。
问题:前几次操作正常,但多次操作后,物体似乎保留之前的速度(已尝试重置velocity为0,但无效)。
原代码如下:
public class PlayerControl : MonoBehaviour { public UnityEngine.UI.Slider powerBar; private Rigidbody2D rb; private float holdDownStartTime; private float force; private bool moving = false; private Vector2 mousePosition; private Vector2 targetPosition; private Vector3 growthSize = new Vector3(0.1f,0.1f,0); private void Start() { powerBar.gameObject.SetActive(false); RectTransform rectTransform = powerBar.GetComponent<RectTransform>(); rb = GetComponent<Rigidbody2D>(); } void Update() { if (Input.GetMouseButtonDown(0)) { //reset RigidBody rb.velocity = Vector3.zero; rb.angularVelocity = 0; rb.position = transform.position; rb.isKinematic = true; //rb.rotation = transform.rotation; moving = false; holdDownStartTime = Time.time; powerBar.gameObject.SetActive(true); } if (Input.GetMouseButton(0)) { if (!moving) { powerBar.value = Time.time - holdDownStartTime; } } if (Input.GetMouseButtonUp(0)) { powerBar.gameObject.SetActive(false); float holdDownTime = Time.time - holdDownStartTime; force = CalculateHoldDownForce(holdDownTime); Move(force); } mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); RotateTowards(mousePosition); } private void OnTriggerEnter2D(Collider2D collision) { if(collision.tag == "Food") { Eat(); } } private void Eat() { this.transform.localScale += growthSize; } private void Move(float force) { targetPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); rb.velocity = new Vector2(targetPosition.x * force/100, targetPosition.y * force/100); } private void RotateTowards(Vector2 target) { Vector2 direction = (target - (Vector2)transform.position).normalized; var angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; var offset = 90f; transform.rotation = Quaternion.Euler(Vector3.forward * (angle + offset)); } private float CalculateHoldDownForce(float holdTime) { holdTime *= 3; float maxForceHoldTime = 2f; float holdTimeNormalized = Mathf.Clamp01(holdTime / maxForceHoldTime); float force = holdTimeNormalized * 100f; return force; } }
问题排查与修复方案
核心问题点
- Kinematic状态未恢复:按下鼠标时将Rigidbody2D设为Kinematic,但释放鼠标后未切换回Dynamic状态。Kinematic状态下,手动设置
velocity不会被物理系统处理,且后续的速度重置操作无效。 - 速度计算逻辑错误:原代码使用鼠标的世界坐标直接计算速度,而非物体指向鼠标的方向向量,导致速度不符合预期,易出现叠加问题。
- 冗余代码:
rb.position = transform.position无实际作用,可移除。
修复后的代码
public class PlayerControl : MonoBehaviour { public UnityEngine.UI.Slider powerBar; private Rigidbody2D rb; private float holdDownStartTime; private float force; private bool moving = false; private Vector2 mousePosition; private Vector3 growthSize = new Vector3(0.1f, 0.1f, 0); private void Start() { powerBar.gameObject.SetActive(false); rb = GetComponent<Rigidbody2D>(); // 确保初始状态为Dynamic rb.isKinematic = false; } void Update() { if (Input.GetMouseButtonDown(0)) { // 先切换回Dynamic再重置物理状态,确保操作生效 rb.isKinematic = false; rb.velocity = Vector2.zero; rb.angularVelocity = 0; moving = false; holdDownStartTime = Time.time; powerBar.gameObject.SetActive(true); } if (Input.GetMouseButton(0)) { if (!moving) { powerBar.value = Time.time - holdDownStartTime; } } if (Input.GetMouseButtonUp(0)) { powerBar.gameObject.SetActive(false); float holdDownTime = Time.time - holdDownStartTime; force = CalculateHoldDownForce(holdDownTime); Move(force); } mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); RotateTowards(mousePosition); } private void OnTriggerEnter2D(Collider2D collision) { if (collision.tag == "Food") { Eat(); } } private void Eat() { transform.localScale += growthSize; } private void Move(float force) { // 切换回Dynamic,确保物理系统接管 rb.isKinematic = false; // 计算物体指向鼠标的方向向量(归一化) Vector2 direction = (mousePosition - (Vector2)transform.position).normalized; // 根据方向和力度设置速度(除数可根据场景调整) rb.velocity = direction * force / 10f; } private void RotateTowards(Vector2 target) { Vector2 direction = (target - (Vector2)transform.position).normalized; var angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; var offset = 90f; transform.rotation = Quaternion.Euler(Vector3.forward * (angle + offset)); } private float CalculateHoldDownForce(float holdTime) { holdTime *= 3; float maxForceHoldTime = 2f; float holdTimeNormalized = Mathf.Clamp01(holdTime / maxForceHoldTime); float force = holdTimeNormalized * 100f; return force; } }
关键修复说明
- 在
Start方法中初始化Rigidbody2D为Dynamic状态,避免初始状态异常。 - 按下鼠标时先切换回Dynamic再重置速度,确保重置操作生效。
Move方法中改为计算方向向量,确保速度朝向鼠标方向,而非基于世界坐标的绝对速度。- 移除冗余的位置重置代码,优化代码简洁性。
内容的提问来源于stack exchange,提问作者Das CO
相关产品推荐
相关产品推荐

