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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Basic Rigidbody2D Movement

Discussion in '2D' started by brenp51597, May 12, 2020.

  1. brenp51597

    brenp51597

    Joined:
    May 12, 2020
    Posts:
    3
    So I've been trying to set up a basic player controller using a square sprite. I understand where I'm making the problem, but I don't know how to fix it. I feel like it's an issue with combining Rigidbody2D.MovePosition() for Move() and Rigidbody2D.velocity() for jump. Each function in a vacuum works perfectly for what I want, but when put together, the jump input seems to either get eaten or buffer for like 2 seconds and then the player sprite gets teleported up a few units. Any recommendations on how to fix it? I don't like the sudden jolt of velocity I get from altering velocity for horizontal movement.

    Here's an example of what's happening.
    https://gyazo.com/529f83ef7c9509ac47e2666132f272f6

    Here's my entire Movement script for reference. It's pretty small at the moment.

    Code (CSharp):
    1. namespace Platformer.Player
    2. {
    3.     public class Movement : MonoBehaviour
    4.     {
    5.         [SerializeField, Range(0f, 1f)] float moveSpeed = 1f;
    6.         [SerializeField, Range(2f, 150f)] float baseSpeedMultiplier = 5f;
    7.         [SerializeField, Range(1f, 100f)] float jumpVelocity = 1f;
    8.  
    9.         [SerializeField] Rigidbody2D rigidBody = null;
    10.  
    11.         void Awake()
    12.         {
    13.             if (GetComponent<Rigidbody2D>())
    14.             { rigidBody = GetComponent<Rigidbody2D>(); }
    15.             else { Debug.LogError("No Rigidbody2D attached to " + this.name); }
    16.         }
    17.  
    18.         void Update()
    19.         {
    20.             HandleMovement();
    21.         }
    22.  
    23.         private void HandleMovement()
    24.         {
    25.             Move();
    26.             Jump();
    27.         }
    28.  
    29.         private void Move()
    30.         {
    31.             float horizontalAxis = Input.GetAxis("Horizontal");
    32.             Vector2 startingPos = rigidBody.position;
    33.             Vector2 newPos = startingPos + new Vector2(horizontalAxis * Time.deltaTime * moveSpeed * baseSpeedMultiplier, 0f);
    34.             rigidBody.MovePosition(newPos);
    35.         }
    36.  
    37.         private void Jump()
    38.         {
    39.             if (Input.GetButtonDown("Jump"))
    40.             {
    41.                 rigidBody.velocity += Vector2.up * jumpVelocity;
    42.             }
    43.         }
    44.  
    45.     }
    46. }
     
  2. brenp51597

    brenp51597

    Joined:
    May 12, 2020
    Posts:
    3
    As an update, I've temporarily fixed the inability to move by assigning newPos's value to rigidBody.position. This however causes really bad catching and jittering on walls when walking into them, which is unacceptable in a game where I want to put in wall jumps and climbing.
     
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    You should step back and look at what things like MovePosition and Velocity actually do. Let's ignore the fact that physics doesn't run per-frame yet you're manipulating physics per-frame. Physics runs per fixed-update by default so unless you're manually running physics per-frame then you'll potentially have many render frames per simulation step.

    You tell the body to move to a specific position per-frame but that'll only be used when the simulation runs so only the last one you did will do anything. Because whenever the physic system runs it doesn't use its velocity because you're permanently telling it to move to a specific position and ignore that stuff yet at the same time you're manipulating velocity in the hope it jumps.

    MovePosition/MoveRotation are typicaly done with Kinematic bodies although in 2D they work with Dynamic bodies but if you're doing it continuously then it won't have a chance to do anything else.

    Choose a single way you want your bodies to move and stick to it. Modify its velocity, add forces or stick to MovePosition/MoveRotation. If you are setting the body position/rotation directly via those properties then they too will always move there but instantly and this will mean you're just instantly teleporting from one position to another.

    Physics is designed to move bodies via their velocity. MovePosition/MoveRotation do this and work with interpolation however if you use this continuously then that's the ONLY way you should move stuff. If you manipulate velocity then ONLY do that via directly setting velocity or adding forces or impulses. Certainly never change the Transform and avoid setting the body pose directly.
     
    brenp51597 likes this.
  4. brenp51597

    brenp51597

    Joined:
    May 12, 2020
    Posts:
    3
    I appreciate the lengthy and thorough response. The long and short of it is, if I'm understanding correctly, that I should keep my bodies moving in one singular way and that the best way is likely velocity rather than MovePosition, as MovePosition is clunkier with Dynamic, player-controlled bodies.
     
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    It's not "clunkier" or has any issue whatsoever, it's simply that you're doing multiple conflicting things i.e. continually move to specific positions but at the same time, set velocity to try to get it to move against the positions you're specifying.