Search Unity

Calculating the required impulse to stop a rigidbody?

Discussion in 'Scripting' started by Nanako, Aug 4, 2015.

  1. Nanako

    Nanako

    Joined:
    Sep 24, 2014
    Posts:
    1,047
    A curious idea has come into my head, that i might use for my current project.

    Given rigidbody A moving at velocity B, and having mass C. how can i calculate the correct impulse to apply to A using Rigidbody.AddForce(force, ForceMode.Impulse) in order to make the velocity zero.

    I'd like to actually know how to calculate the required impulse in order to bring the velocity to any multiplier of its current value. Say, to cut it in half, or reduce it by 30.

    i'm currently poking around and testing with velocity and mass, but if anyone could give me some more exact math that'd be helpful
     
  2. Sean-Powell

    Sean-Powell

    Joined:
    Dec 18, 2014
    Posts:
    87
    F = mass * acceleration
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    Considering that F=ma, where F will be the result of our impulse.

    We know the mass, it's a property of the rigidbody.

    Because in unity an object doesn't accelerate unless force is applied to it, so thusly a (for acceleration) is constant and is its velocity. We want to move it in the opposite direction of the direction its currently moving. So we just need to impulse it in the opposite direction of its current velocity.

    We get:
    F=mass * -velocity

    or

    rigidbody.AddForce(-rigidbody.velocity * rigidbody.mass, ForceMode.Impulse);


    Note, that if you use ForceMode.VelocityChange, it ignores the mass, so you wouldn't have to include the mass:

    rigidbody.AddForce(-rigidbody.velocity, ForceMode.VelocityChange);


    Of course, you COULD just set its velocity to Vector3.zero. But this will trash simulations of collisions.
     
    Last edited: Aug 4, 2015
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    I notice you have another thread about counter acting gravity.

    If you are attempting to use this to counteract gravity, you would merely impulse in the opposite direction of gravity. Of course, because gravity is accelerative, and not constant, we need to take into account the acceleration that will occur that frame:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class TestScript03 : MonoBehaviour {
    6.  
    7.     // Use this for initialization
    8.     void Start () {
    9.  
    10.     }
    11.  
    12.     // Update is called once per frame
    13.     void Update () {
    14.  
    15.         if(Input.GetMouseButtonDown(0))
    16.         {
    17.             this.rigidbody.AddForce(Vector3.left * 10f);
    18.         }
    19.         if(Input.GetMouseButtonDown(1))
    20.         {
    21.             this.rigidbody.AddForce(Vector3.right * 10f);
    22.         }
    23.     }
    24.  
    25.     void FixedUpdate()
    26.     {
    27.         var gdir = Physics.gravity.normalized;
    28.         var d = Vector3.Dot(this.rigidbody.velocity, gdir);
    29.         d = Mathf.Max(0f, d); //if we don't clamp this we'd also remove upward velocities, if you want to do that as well... comment out this line
    30.         d += Physics.gravity.magnitude * Time.deltaTime;
    31.  
    32.         this.rigidbody.AddForce(-d * gdir * this.rigidbody.mass, ForceMode.Impulse);
    33.     }
    34. }
    35.  
    Here I show a script that you can attach to a rigidbody with gravity applied to it. Set its mass to something to demonstrate it works despite mass.

    Note it'll float in space, but if you click your mouse it'll start to move left or right (depending the mouse button).





    Now that's sort of what ForceMode.Accelation is for, so you could not use Impulse, and instead just use ForceMode.Acceleration:

    Code (csharp):
    1.  
    2.     void FixedUpdate()
    3.     {
    4.         //var gdir = Physics.gravity.normalized;
    5.         //var d = Vector3.Dot(this.rigidbody.velocity, gdir);
    6.         //d = Mathf.Max(0f, d);
    7.         //d += Physics.gravity.magnitude * Time.deltaTime;
    8.  
    9.         //this.rigidbody.AddForce(-d * gdir * this.rigidbody.mass, ForceMode.Impulse);
    10.  
    11.         this.rigidbody.AddForce(-Physics.gravity, ForceMode.Acceleration); //does the same thing if starting from rest
    12.     }
    13.  
    BUT, this implies that we started from rest.

    If you start this after the object is in motion, all it'll do is stop the acceleration of gravity, making the downward velocity constant rather than 0.

    Where as impulse will counteract no matter what.
     
    Last edited: Aug 4, 2015
    Andimator likes this.