Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Knockback towards the origin 2D

Discussion in 'Scripting' started by Calumniator, Sep 25, 2023.

  1. Calumniator

    Calumniator

    Joined:
    Jul 5, 2023
    Posts:
    24
    Hello,

    what I want is to have a special kind of knockback. Usually I used something like this for the knockback:

    Code (CSharp):
    1.     private void OnTriggerEnter2D(Collider2D collision)
    2.     {
    3.         if (collision.tag == "Player")
    4.         {
    5.             collision.GetComponent<PlayerHealth>().PlayerTakeDamage(damageToPlayer);
    6.  
    7.             // knockback
    8.             Rigidbody2D player = collision.GetComponent<Rigidbody2D>();
    9.             Vector2 difference = player.transform.position - transform.position;
    10.             difference = difference.normalized * -knockbackForce;
    11.             player.AddForce(difference, ForceMode2D.Impulse);
    12.         }
    13.     }
    And while this kind of knockback is somewhat ok in most cases it is not what I want this time. What I want is a kind of knockback that sends the player right back to the direction he came from.

    For example: I have an object (green) with a circle collider. My player (blue) can collide with the object from different directions (black arrows). On collision I want to add a force that sents the player back to to the direction where he came from (red arrows). No matter if the objekt is moving or not or how fast the object or the player moves I don't care I just want to apply a fixed amount of force. Any ideas? I'm to stupid to figure it out myself. ^^
     
    Last edited: Sep 25, 2023
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    Keep the previous player position in a field, updated at the end of FixedUpdate (use RigidBody position since you are working with a physics object).

    Previous position minus current position gives you the direction (and speed) of travel. Push the player back in this direction (normalize first, then multiply with knockback factor).
     
    Calumniator likes this.
  3. Calumniator

    Calumniator

    Joined:
    Jul 5, 2023
    Posts:
    24
    That's a great idea. Now I only need to figure out how to keep that previous position. :)
    Thanks a lot!
     
  4. Calumniator

    Calumniator

    Joined:
    Jul 5, 2023
    Posts:
    24
    Well I guess I'm to stupid to understand your advice. :(
    Here is what I did but even though I don't get any errors nothing works:

    Code (CSharp):
    1. public Vector3 oldPosition;
    2. public Vector3 newPosition;
    3.  
    4. private void FixedUpdate()
    5. {
    6.         oldPosition = transform.position;
    7.  
    8.         ApplyMovement();
    9.  
    10.         newPosition = transform.position;
    11. }
    12.  
    13. private void OnTriggerEnter2D(Collider2D collision)
    14. {
    15.         if (collision.tag == "Enemy")
    16.         {
    17.             Vector3 direction = (newPosition - oldPosition).normalized;
    18.             direction *= -knockbackForce;
    19.             rb.AddForce(direction, ForceMode2D.Impulse);
    20.         }
    21. }
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Why not just use a tweening package like DOTween or LeanTween and just script out the motion you want?

    Otherwise, if you wanna wrangle all that yourself:

    Smoothing movement between any two particular values:

    https://forum.unity.com/threads/beginner-need-help-with-smoothdamp.988959/#post-6430100

    You have currentQuantity and desiredQuantity.
    - only set desiredQuantity
    - the code always moves currentQuantity towards desiredQuantity
    - read currentQuantity for the smoothed value

    Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.

    The code: https://gist.github.com/kurtdekker/fb3c33ec6911a1d9bfcb23e9f62adac4

    Another approach would be to use a tweening package such as LeanTween, DOTween or iTween.
     
    Calumniator likes this.
  6. Calumniator

    Calumniator

    Joined:
    Jul 5, 2023
    Posts:
    24
    Thanks for the input, I'll check the provided links. And I don't use a tweening library because I'm a newbie and do not even know what tweening is. ^^
    edit: I'm not sure you answered in the right thread because smooth movement is none of my problems, I need to understand how to store two positions (current frame and last frame)
     
    Last edited: Sep 25, 2023
  7. MarcusHimself

    MarcusHimself

    Joined:
    Mar 20, 2013
    Posts:
    10
    In your ApplyMovement() function you calculate the move direction of the player, right? So why not just take this move direction and store it in a variable. Then when you collide with the object you use this stored direction, invert it (-direction) and use it as pushback direction.
     
    Last edited: Sep 26, 2023
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Code (csharp):
    1. private Vector3 LastFramePosition;
    Code (csharp):
    1. void Update()
    2. {
    3.   Vector3 currentPosition = transform.position;
    4.  
    5. // do all your computation that requires the delta between current and last here...
    6.   Vector3 delta = currentPosition - LastFramePosition;
    7.  
    8.   LastFramePosition = currentPosition;
    9. }
    To avoid a transient spike at the beginning, assign
    transform.position
    to
    LastFramePosition
    in your
    Start()
    method.
     
    Calumniator likes this.
  9. Calumniator

    Calumniator

    Joined:
    Jul 5, 2023
    Posts:
    24
    Thank You!