You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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; 
    }
}
问题排查与修复方案

核心问题点

  1. Kinematic状态未恢复:按下鼠标时将Rigidbody2D设为Kinematic,但释放鼠标后未切换回Dynamic状态。Kinematic状态下,手动设置velocity不会被物理系统处理,且后续的速度重置操作无效。
  2. 速度计算逻辑错误:原代码使用鼠标的世界坐标直接计算速度,而非物体指向鼠标的方向向量,导致速度不符合预期,易出现叠加问题。
  3. 冗余代码: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 18:45:09