Search Unity

Difference between ForceMode2D:Force and ForceMode2D:Impulse?

Discussion in 'Physics' started by SoftwareGeezers, Mar 24, 2019.

  1. SoftwareGeezers

    SoftwareGeezers

    Joined:
    Jun 22, 2013
    Posts:
    902
    Some experiments applying forces to stationary objects suggested that Impulse forces were just Force's applied scaled to refresh time, so these have the same result:

    Code (CSharp):
    1. rigidbody2D.AddForce(Vector2.up*40, ForceMode2D.Force);
    2. rigidbody2D.AddForce(Vector2.up*40*Time.fixedDeltaTime, ForceMode2D.Impulse);
    Code (CSharp):
    1. rigidbody2D.AddForce(Vector2.up*40/Time.fixedDeltaTime, ForceMode2D.Force);
    2. rigidbody2D.AddForce(Vector2.up*40, ForceMode2D.Impulse);
    However, trying to apply forces in my game, this isn't the case. I've a top-down space combat game with both free-floating and inertialess drives. The method for applying forces allows greater than max_speed velocities caused by slingshotting around gravity fields, but application of thrust in a direction slows down the ship. Or, in the case of inertialess drives, it can be accelerated by a force but then immediately reverts to its default speed when that force stops.

    Using this code, it works perfectly:
    Code (CSharp):
    1.     if (thrusting){
    2.         accel = (acceleration * mod.in_effect.dmg_accelX - mod.in_effect.dmg_accel);
    3.         delta_spd = accel / rb.mass;                // unit speed to be added from acceleration
    4.         // Add thrust force
    5.         // Increases speed by delta_spd
    6.         rb.AddForce(_transform.up*accel, ForceMode2D.Impulse);
    7.         mx_spd = max_speed * mod.in_effect.dmg_speedX - mod.in_effect.dmg_speed;
    8.         spd_diff = rb.velocity.magnitude - mx_spd;
    9.         if(spd_diff >= accel*2){
    10.             rb.AddForce(rb.velocity.normalized *-accel*2, ForceMode2D.Impulse);
    11.         }else if(spd_diff > 0){
    12.             // add exact retardation force to reach max_speed
    13.             // reuse delta_spd
    14.             delta_spd = spd_diff*rb.mass;
    15.             rb.AddForce(rb.velocity.normalized *-delta_spd, ForceMode2D.Impulse);
    16.         }
    17.     }else if(inertialess){
    18.         print("reset rb vel ");
    19.         rb.velocity = Vector2.zero;
    20.     }
    However, if I replace the AddForce calls with:

    Code (csharp):
    1.        rb.AddForce(rb.velocity.normalized *-delta_spd/Time.fixedDeltaTime);
    ...the final output actually includes essentially a lag in the force being applied. It's as if it isn't immediate.

    Can someone provide technical details on the difference between these two force modes and how to mix them correctly?

    Edit: Okay, confirmed in test scene. With two identical rigidbody2D's, use this code in Start() on test script:
    Code (csharp):
    1.  
    2.         rb1.AddForce(Vector2.up * 10, ForceMode2D.Force);
    3.         print(rb1.velocity.magnitude);
    4.         rb2.AddForce(Vector2.up * 10 * Time.fixedDeltaTime, ForceMode2D.Impulse);
    5.         print(rb2.velocity.magnitude);
    6.  
    Output is 0 for rb1 and 0.16666 for rb2, showing the velocity is immediately changed for impulse but after the next update for force. This needs to be explained in the documentation along with any other differences and notes on efficiency* please.

    * If force vectors are consolidated into one vector prior to applying to RBs for Forcemode2D:Force, that would be more efficient than applying individual forces as Forcemode2D:Impulse.
     
    Last edited: Mar 24, 2019
    AndrewHerrera1998 likes this.
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    To start, here's the docs: Force & Impulse. As it states for force, it's used during fixed-update (simulation) only.

    When you use "force", it is added to the current force being applied to a body i.e. each time you call it, it just gets added to a sum that is used only during the simulation at which point it is time-integrated and added to the velocity then this "force sum" is reset.

    When you use "impulse" it instantly gets added to the current velocity and is the same as you directly added a value to the velocity.
     
    MendProj, xXDarQXx, MomkeyDev and 2 others like this.