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

Better way to move Rigidbody player in 2D than velocity?

Discussion in '2D' started by rizenmusic, Feb 15, 2021.

  1. rizenmusic

    rizenmusic

    Joined:
    Oct 2, 2019
    Posts:
    23
    Hi fellow developers!

    I've been playing with my PlayerController system and my movement system based on velocity seems to be far from perfect even though I've seen this same system in dozens different tutorials on youtube and here.

    if (!isWallSliding)
    {
    rdBody2D.velocity = new Vector2(moveInput * playerSpeed, rdBody2D.velocity.y);
    }

    For movement only it works like a charm, but when you start implementing another systems like walljumping or even knockback it doesn't work because when player isn't moving, their velocity is exactly zero which fixes them in the same x position and no matter what force I apply, the player would stay in the same place. The same issue happens when player is moving - velocity.x is constant and applied force to x doesn't work as intended. I could stop movement on some events but that doesn't look relyable enough.

    What should I use instead? Transform.Translate and Transform.Position are not used for Rigidbody movement. Addforce, if I remember correctly, has a moment of acceleration that I don't want in my game.

    Thanks for your advice.
     
  2. spacefrog

    spacefrog

    Joined:
    Jun 14, 2009
    Posts:
    731
    There's also MovePosition() and MoveRotation() on the Rigidody2D
    I think those should be used instead of their standard transform counterparts
     
    rizenmusic likes this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,529
    There's no "better way", it all comes down to what you want. You're also not really asking about how to move stuff as that's well established; you can add forces or impulses, set velocity directly or use MovePosition depending on how much control you want etc. What you're asking here is about character controller logic itself i.e. if I'm setting the velocity explicitly in the X axis then how do I deal with wall-jumping or knockback but the answer to that is script logic and has nothing to do with the physics mechanism you use to achieve it.

    It's common that during a jump of any kind you maintain that state and change how the player input affect the character. This'll be the same for wall-jumping or knock back. I suspect knock back will be where your player input for a small period of time isn't used but again, that's how you want it to work and not about how physics needs it because it doesn't really care.

    If you're going to apply an impulse for knock back then you cannot be setting velocity explicitly so you need to disable it during knock back etc etc.

    The only thing you need to be careful about for physics is to ensure you're not doing bad things and that simply comes down to NOT modifying the Transform but doing all movement via the Rigidbody2D API itself.
     
    rizenmusic likes this.
  4. rizenmusic

    rizenmusic

    Joined:
    Oct 2, 2019
    Posts:
    23
    @spacefrog thanks, I'll think about it.

    @MelvMay well, that was really helpful. Yes, I think my question refers to script logic and if timers are common for things like this then I will use them for sure. Though I've been thinking about some kind of force that would override my current movement force because I've used timers already for knockback and trajectory of knockback using velocity movement doesn't look good because when the timer ends, movement controller keeps messing with velocity and instead of knockback arc I get something like this:

    91d154e69756de93ed85c237a18a3ad5.png

    instead of this:

    05264ce6d124af30f20773f949a9d2c9.png
     
  5. gimmethatmod

    gimmethatmod

    Joined:
    Feb 4, 2019
    Posts:
    1

    The reason why it is dropping all your attempts to have other forces be applied to your rigidbody's velocity is because its hard setting it to a new vector2 on each frame. It wont care about any other input other than that vector2.

    a simple way to deal with this :

    Create a new Vector2 as a variable
    yknow like this
    Code (CSharp):
    1. public Vector2 Velocity;
    and then apply Velocity to your rigidbody velocity
    rdBody2D.velocity = Velocity;
    but make sure to do this at the end of your update()
    and then change that new vector2 you made using += instead of settings it directly. and use a clamp for max speed
    Code (CSharp):
    1. public float speed;
    2. public float maxspeed;
    so for example movement would be something like (really bad example please dont copy paste)
    Code (CSharp):
    1. Velocity.x += Input.GetAxisRaw("Horizontal") * Speed * Time.deltaTime;
    2. Velocity.x = Mathf.Clamp(Velocity.x, -maxspeed, maxspeed)
    and then for stopping the player you would want to use a friction variable (really bad example please dont copy paste)
    Code (CSharp):
    1. public float friction;
    2.  
    3. void Update()
    4. {
    5.      if(Input.GetAxisRaw("Horizontal" ) == 0)
    6.      {
    7.          Velocity.x = Mathf.MoveTowards(Velocity.x, 0, friction * time.deltaTime);
    8.      }
    9. }
    so then something like knockback can be done like this (really bad example please dont copy paste)
    Code (CSharp):
    1. public void knockback(float force)
    2. {
    3.     Velocity.x -= force;
    4. }
    now i know this may not be the absolute best solution in the world it sure as hell works for most things i do, hopefully i explained simple enough but always reply if you want more clarification
     
  6. lsdland34

    lsdland34

    Joined:
    Jul 18, 2022
    Posts:
    1
    Code (CSharp):
    1.     private void Update()
    2.     {
    3.         Move(GetDirection());
    4.     }
    5.     private void Move(Vector2 direction)
    6.     {
    7.         rigidbody.AddForce(direction.normalized * moveSpeed * Time.deltaTime);
    8.     }
    9.     private Vector2 GetDirection()
    10.     {
    11.         float horizontal = Input.GetAxis("Horizontal");
    12.         float vertical = Input.GetAxis("Vertical");
    13.         return new Vector2(horizontal, vertical);
    14.     }
    Here is my solution using AddForce. Make sure the Linear drag is greater than zero.