【问题标题】:How to reduce 'speed' of a rigidbody without changing the distance it has to cover?如何在不改变刚体必须覆盖的距离的情况下降低刚体的“速度”?
【发布时间】:2022-06-25 15:14:57
【问题描述】:

我正在使用rb.AddForce(force,ForceMode.Impulse) 移动刚体,其中力是刚体必须达到的目标位置。

现在它的速度直接取决于它必须经过的距离。

假设到达目标位置所需的时间是 3 秒。我需要刚体在 5 秒内覆盖相同​​的目标位置。

  • 我不想更改时间刻度,因为它会影响我的游戏流程

  • 在改变刚体速度时无法到达目标位置

【问题讨论】:

  • 你想让你的刚体匀速移动到特定目标吗?
  • “假设到达目标位置所需的时间是 3 秒。我需要刚体在 5 秒内覆盖相同​​的目标位置” - 嗯?
  • 是的,匀速
  • 这里有很多很好的答案可以解释你的问题。也许你应该选择一个,这样赏金就不会浪费了

标签: c# unity3d rigid-bodies


【解决方案1】:

一些基本的物理/数学:

velocity = change-in-position / travel-time
force = mass * change-in-velocity / acceleration-time

为方便起见,我们将change-in-position 称为distance,将change-in-velocity/acceleration-time 称为acceleration

现在,由于您使用 Impulse,acceleration-time 分量实际上为零,我们将从等式中删除它(在数学术语中,我们将其设置为“1”)

force = mass * change-in-velocity

假设您的对象以零速度开始,我们可以将 change-in-velocity 简化为 velocity

force = mass * velocity

force = mass * distance / travel-time

要将它带回到 Unity 代码中:

var mass = rb.mass;
var distance = destination.position - transform.position;
var travelTime = 5f; // seconds

var force = mass * distance / travelTime;

rb.AddForce(force, ForceMode.Impulse);

请注意,这是假设无摩擦传输和恒定速度。

【讨论】:

  • 感谢您的努力。这里的问题是,var force = mass * distance / travelTime;对于力,我们将距离除以时间,因此它基本上减少了刚体必须经过的距离。对我来说它必须旅行目的地,只有旅行时间应该有所不同
  • @bolov 让我用一个例子来解释一下, rb.position = Vector3(0f,0f,0f); Destination.position = Vector3(0f,0f,20f); rb.mass = 1f; var 质量 = rb.mass; //质量= 1; var 距离 = 目的地. 位置 - 变换. 位置; //距离 = Vector3(0f,0f,20f); var travelTime = 5f; // 秒 var force = mass * distance / travelTime; //force = Vector3(0f,0f,4f); rb.AddForce(力,ForceMode.Impulse);现在刚体移动到Vector3(0f,0f,4f)的位置,但它的目的地是nvector3(0f,0f,20f)
  • @Nijanthan 听起来你有摩擦,需要增加额外的力量来对抗基于摩擦的减速(这超出了我愿意在这里深入探讨的范围)......或者制作 rb kinematic 并自己移动它。抱歉,我帮不上忙。
【解决方案2】:

如果忽略重力,这段代码解决了问题,这里我根据重量和距离改变了阻力,最后可能离目的地有点远,原因应该是阻力摩擦较大。

public void ForceToTarget(Transform target, float time = 1f)
{
    var rb = GetComponent<Rigidbody>();
    
    var vector = target.position - transform.position;

    var distance = vector.magnitude;
    
    rb.drag = distance/time;

    rb.AddForce(vector*rb.mass*distance/time, ForceMode.Impulse);
}

【讨论】:

    【解决方案3】:

    如果您想精确控制自己的速度,请停止使用ForceMode.Impulse,因为阻力等其他物理效果会使您的答案出错。相反,只需自己设置速度。您可以使用Coroutine 来控制时间和ForceMode.VelocityChange 来控制速度。基本上就是看你在哪里,目标在哪里,还剩多少时间,直接套用速度。

    private bool canMove = true;
    public void MoveTo(Vector3 targetPosition, float targetTime)
    {
        if(canMove)
        {
            StartCoroutine(MoveToCoroutine(targetPosition,targetTime));
        }
    }
    private IEnumerator MoveToCoroutine(Vector3 targetPosition, float time)
    {
        canMove = false;
        while(time > 0)
        {
            var positionDelta = transform.position - targetPosition;
            var targetSpeed = positionDelta / time;
            var speedDelta = targetSpeed - rb.velocity;
            rb.AddForce(speedDelta , ForceMode.VelocityChange);
            yield return null;
            time -= Time.deltaTime;
        }
        // Bring the object to a stop before fully releasing the coroutine
        rb.AddForce(-rb.velocity, ForceMode.VelocityChange);
        canMove = true;
    }
    

    我在文本编辑器中写了这个,没有 IDE,也没有测试过,但我很确定这会做你想要的。

    【讨论】:

      【解决方案4】:

      假设您按原样使用目标位置,则较大的矢量将导致施加比较小的矢量更大的力。类似地,如果按原样使用方向矢量,那么随着 rb 越接近目标,矢量的幅度就越小,因此施加的力就越小。

      要获得恒定的速度,请使用指向目标的方向和 Normalise 它。无论距离多远,方向向量的大小始终为 1,因此您可以将其乘以任意值以准确控制对象的速度:

      Rigidbody rb;
      public Transform target;
      public float dist;
      public float speed = 2f; // or whatever
      public float targetDistance = 40f; // or whatever
      
      private void Start()
      {
          rb = GetComponent<Rigidbody>();
          StartCoroutine("IMove");
      }
      
      IEnumerator IMove()
      {
      
          dist = Vector3.Distance(transform.position, target.position);
      
          while (dist > targetDistance)
          {
              dist = Vector3.Distance(transform.position, target.position);
              rb.AddForce(Vector3.Normalize(target.position - transform.position) * speed, ForceMode.Impulse);
              yield return new WaitForFixedUpdate();
          }
      
      }
      

      【讨论】:

        【解决方案5】:

        在不深入研究物理和数学的情况下,如果您希望它移动得更慢但距离相同,则需要减少它的重力和初始力。 请注意,在此示例中,我假设权重为 1,以使力的计算更容易一些。

        public class TrevelSpeedAdjusted
        {
            public float speedFactor = 1;
        
            void FixedUpdate() 
            {
                // Reduce the gravity on the object
                rb.AddForce(-Physics.gravity * rigidbody.mass * (1 - speedFactor));
            }
        
            public float AddAdjustedForce(Vector3 force, ForceMode forceMode)
            {
                rb.AddForce(force * speedFactor, forceMode);
            }
        }
        

        【讨论】:

          【解决方案6】:

          因此,您可以尝试使用 DoTween 包来轻松完成此操作,并且使用包而不是使用 Unity 的内置系统非常方便。 使用 doTween 使用: DOMove(Vector3 to, float duration, bool snapping) 条件可在您需要的持续时间内将您的物理游戏对象补间到给定的目标位置。

          如果需要,可以参考以下文档:http://dotween.demigiant.com/documentation.php

          让我举个例子:

          1. 安装 doTween 包。 http://dotween.demigiant.com/download
          2. 将其导入统一。
          3. 转到要实现问题中提到的功能的脚本,并添加此标题“使用 DG.Tweening”。
          4. 现在可以访问您的 RigidBody。 例如让我们说:我有一个带有刚性的立方体游戏对象,并且附加了这个脚本。 Cube 初始位置在 0,0,0。

          我希望它根据您的问题要求在 3 秒或 5 秒内移动到 5、5、5。假设我希望在我单击键盘上的空格键时发生这种情况。

          所以我会这样做。

          Rigidbody rb;
          void Start()
          {
          rb= GetComponent<Rigibody>();
          }
          
          void Update()
          {
          if(Input.GetButtonDown(Keycode.Space))
          {
          MoveCube(new Vector3(5,5,5),5);
          }
          }
          
          void MoveCube(Vector3 inTargetPosition , float durationToReachTheTarget)
          {
          //What this line does is first take in the target position you want your physics object to reach as it first parameter, Then takes in the duration in which you want it to reach there.
          rb.DoMove(inTargetPosition,durationToReachTheTarget);
          }
          

          这应该对您有所帮助。但请记住,这只有在您可以添加额外包的情况下。就个人而言,这个包非常好,我会向你推荐这个。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-04-29
            • 1970-01-01
            相关资源
            最近更新 更多