Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question How much force do i need to apply in one frame in order for an object to stop at exact displacement?

Discussion in 'Physics' started by BlackRockShoota, May 23, 2023.

  1. BlackRockShoota

    BlackRockShoota

    Joined:
    Apr 12, 2018
    Posts:
    4
    Hi guys,

    I am doing an experiment that I want to apply a force in one frame to a rigidbody using add force and I want it to be stop by friction at some displacement. I tried to calculate the force I need in the following code:
    Code (CSharp):
    1.         hitPosition = this.transform.position;
    2.         isHitRecord = true;
    3.         hitTime = DateTime.Now;
    4.         var gravityDivide = Vector3.ProjectOnPlane(Physics.gravity, groundNormal) * ridbody.mass;
    5.         var gravityFrictionDivide = Physics.gravity - gravityDivide;
    6.         var frictionForceAcceleration =  bodyCollider.material.dynamicFriction * gravityFrictionDivide.magnitude;
    7.  
    8.         var desiredV0 = (float)Math.Sqrt((2 * frictionForceAcceleration * distance));
    9.         var acceleration = desiredV0 / Time.fixedDeltaTime;
    10.  
    to calculate my desired v0 and apply the force with m * a, but the result is not quite what I want. What am I doing wrong? Any help appreciated
     
  2. Maeslezo

    Maeslezo

    Joined:
    Jun 16, 2015
    Posts:
    325
    Drag is a not a constant force, since it depends of the velocity.

    However, you can approximate the behavior to an uniform accelerated motion if the displacement is small.

    https://en.wikipedia.org/wiki/Acceleration#Uniform_acceleration

    For instance, for displacement, the formula is speed = speed_initial^2 + 2*acceleration*displacement. Speed is 0, because you want to stop,
    So drag (acceleration) = -speed_initial^2/(2*expected_displacement)

    If you need an instant stop, you can generate an impulse opposite to the movement

    Here's an example

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Stop : MonoBehaviour
    4. {
    5.     public Rigidbody rb;
    6.  
    7.     public Vector3 dragAcc;
    8.  
    9.     public bool doDrag;
    10.     public float expectedTime = 1;
    11.     public float expectedDisplacement = 5f;
    12.  
    13.     public Vector3 positionStamp;
    14.     public float timeStamp;
    15.     void Start()
    16.     {
    17.      
    18.     }
    19.  
    20.     // Update is called once per frame
    21.     void Update()
    22.     {
    23.         if (Input.GetKeyDown(KeyCode.Space))
    24.         {
    25.             OneFrameStop();
    26.         }
    27.         if (Input.GetKeyDown(KeyCode.X))
    28.         {
    29.             //dragAcc = CalculateDragWithTime(rb.velocity, expectedTime);
    30.             dragAcc = CalculateDragWithDisplacement(rb.velocity, expectedDisplacement);
    31.             rb.useGravity = false;
    32.             doDrag = true;
    33.             positionStamp = transform.position;
    34.             timeStamp = Time.time;
    35.         }
    36.     }
    37.  
    38.     private void OneFrameStop()
    39.     {
    40.         Vector3 impulse = -rb.velocity; //just for testing
    41.         rb.AddForce(impulse, ForceMode.VelocityChange);
    42.         rb.useGravity = false;
    43.     }
    44.  
    45.     private void FixedUpdate()
    46.     {
    47.         if (doDrag && rb.velocity.magnitude < 0.01f)
    48.         {
    49.             doDrag = false;
    50.  
    51.             float displacement = (transform.position - positionStamp).magnitude;
    52.             float time = Time.time - timeStamp;
    53.  
    54.             print($"Time: Expected {expectedTime}. Actual {time}. Displacement: Expected {expectedDisplacement}. Actual {displacement}");
    55.         }
    56.  
    57.         if (doDrag)
    58.         {
    59.             rb.AddForce(dragAcc, ForceMode.Acceleration);
    60.         }
    61.     }
    62.  
    63.     private static Vector3 CalculateDragWithTime(Vector3 velocity, float expectedTime)
    64.     {
    65.  
    66.         return -velocity / expectedTime;
    67.     }
    68.  
    69.     private static Vector3 CalculateDragWithDisplacement(Vector3 velocity, float expectedDisplacement)
    70.     {
    71.  
    72.         float speed = velocity.magnitude;
    73.         return (-speed * speed) / (2f * expectedDisplacement) * velocity.normalized;
    74.     }
    75. }
    76.