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

No Gravity using RigidBody.MovePosition?

Discussion in 'Physics' started by BlackDove634, Feb 17, 2020.

  1. BlackDove634

    BlackDove634

    Joined:
    Jan 30, 2020
    Posts:
    14
    Hi everyone,

    I've been doing a lot of reading and can't seem to find a solution to fit my situation. I'm creating a 2D platformer and have chosen to try character movement using rb.MovePosition (my first movement attempts were getting sprite jitters on collisions).

    Everything is going okay except my guess is that gravity seems to be overridden by my movement function? I can move along X okay, but in the air my character controls more like a spaceship that falls very slowly. I.e. UpArrow moves me up, DownArrow moves down, no input = slow fall. Because of this my Jump inputs don't work either.

    I used this video as the basis for my movement function. When the video demos rb.MovePosition, it doesn't seem to have the gravity problem.

    Sorry my code is probably garbage, I'm new and only been at this for about three weeks. Any help would be greatly appreciated, I'm pulling my hair out over this!

    RigidBody settings are all default

    Code (CSharp):
    1. public class RBMovement2D : MonoBehaviour
    2. {
    3.     Rigidbody2D rb;
    4.     SpriteRenderer flip;
    5.     SpriteRenderer starFlip;
    6.  
    7.     //Movement
    8.     public float speed = 10.0f;
    9.     Vector2 movement;
    10.  
    11.     //Jumping
    12.     public bool isGrounded;
    13.     private bool canJump;
    14.     public float jumpPower;
    15.  
    16.     void Start()
    17.     {
    18.         rb = GetComponent<Rigidbody2D>();
    19.         flip = GetComponent<SpriteRenderer>();
    20.         starFlip = GameObject.Find("Stars").GetComponent<SpriteRenderer>();
    21.  
    22.     }
    23.  
    24.     void Update()
    25.     {
    26.         //Inputs ===================
    27.  
    28.         //GetAxis
    29.         movement = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
    30.      
    31.         //Jumping
    32.         if (isGrounded && ((Input.GetKeyDown(KeyCode.Space)) || (Input.GetKeyDown(KeyCode.UpArrow))))
    33.         {
    34.             canJump = true;
    35.         }
    36.         else
    37.         {
    38.             canJump = false;
    39.         }
    40.  
    41.         //Flip Sprite X ======================
    42.         if (Input.GetKey("right"))
    43.         {
    44.             flip.flipX = false;
    45.             starFlip.flipX = false;
    46.         }
    47.         else if (Input.GetKey("left"))
    48.         {
    49.             flip.flipX = true;
    50.             starFlip.flipX = true;
    51.         }
    52.  
    53.  
    54.     }
    55.  
    56.     private void FixedUpdate()
    57.     {
    58.         moveCharacter(movement);
    59.     }
    60.  
    61.     private void moveCharacter(Vector2 direction)
    62.     {
    63.         //Movement
    64.         rb.MovePosition((Vector2)transform.position + (direction * speed * Time.fixedDeltaTime));
    65.      
    66.         //Jumping
    67.         if (canJump)
    68.         {
    69.             rb.AddForce(new Vector2(0, jumpPower), ForceMode2D.Impulse);
    70.         }
    71.     }
    72.  
    73.     private void OnTriggerEnter2D(Collider2D col)
    74.     {
    75.         if (col.tag.Contains("Ground"))
    76.         {
    77.             isGrounded = true;
    78.         }
    79.     }
    80.  
    81.     private void OnTriggerExit2D(Collider2D col)
    82.     {
    83.             isGrounded = false;
    84.  
    85.     }
    86. }
     
    Last edited: Feb 19, 2020
  2. unit_dev123

    unit_dev123

    Joined:
    Feb 10, 2020
    Posts:
    989
    not checked but maybe increase gravity if object falls too slowly
     
  3. BlackDove634

    BlackDove634

    Joined:
    Jan 30, 2020
    Posts:
    14
    If I up the Gravity Scale, jumping seems to become impossible without using huge AddForce values. Slopes also become very sluggish
     
  4. unit_dev123

    unit_dev123

    Joined:
    Feb 10, 2020
    Posts:
    989
    alternate add downforce when not grounded and release jump key
     
  5. BlackDove634

    BlackDove634

    Joined:
    Jan 30, 2020
    Posts:
    14

    Thank you for your replies, but applying downward force after a jump... is that really the best solution? RigidBody's are supposed to respond to gravity, so if you have to program your own gravity wouldn't it be better to just use no RigidBody?

    My understanding is that rb.MovePosition resets the rb.velocity each FixedUpdate. So how do you use rb.MovePosition without constantly reseting the rb.velocity.y?
     
  6. unit_dev123

    unit_dev123

    Joined:
    Feb 10, 2020
    Posts:
    989
    as i understand sir all work - except object not falling fast enough, so either increase gravity and adjust other settings or add downforce??
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    What's going wrong is that you're constantly telling the body to move to a specific position. How can it then get to that position AND use gravity? The answer, of course, is that it cannot. An analogy would be telling a person to stand on a spot in a corner but then expect them to be 5 meter away (without telling them).

    You should add in the gravity term to your target position which is easy (add Physics2D.gravity * rb.gravityScale). MovePosition is typically used for Kinematic motion (which do not automatically have gravity applied or any other forces) however when used for Dynamic motion continuously you are overriding positions it dynamically wants to go it and this'll include responses to collisions.

    Using AddForce to modify the bodies velocity then overriding its use and using MovePosition continuously like you do makes no sense btw. Also, you should base your input position on Rigidbody2D.position and not Transform.position as these will be different if you use interpolation.

    Finally, MovePosition does not modify the body velocity after the simulation step. It actually restores the velocity to what it was prior to the step. It does this because MovePosition needs to use velocity to move through the world. The same as it disabling linear drag during the simulation step then restoring it otherwise it wouldn't get to the exact position.

    In short, you're mixing functionality in an odd way which is giving you odd results.
     
    Last edited: Feb 20, 2020
    RrAaJj and BlackDove634 like this.
  8. BlackDove634

    BlackDove634

    Joined:
    Jan 30, 2020
    Posts:
    14
    Thank you for your reply!

    To give you a sense of how I got to this point: I started off with a character controller using transform.translate for movement, but then found that the sprite "jitters" upon collision because (to my understanding) you're forcing the Game Object into a collider that then "rejects" the RigidBody2D during the physics step. Solutions I've read recommend moving the RigidBody to solve this issue using either AddForce (not very smooth, but commonly used for jumping?), Velocity, or MovePosition, but now rb.velocity and rb.moveposition are creating gravity issues. I've also read that you can still use transform.translate and solve sprite jitters using Raycasts, but I'm not sure that's the best way to do things for a simple 2D Platformer.

    So according to your answer, you're saying that I could still use rb.moveposition on a dynamic rb, so long as I pass in (Physics2D.gravity * rb.gravityScale) somewhere? I think that this line of code is the culprit:

    Code (CSharp):
    1. rb.MovePosition((Vector2)transform.position + (direction * speed * Time.fixedDeltaTime));
    If that's true, could you please show me how to "add the gravity term to [my] target position"? I've been trying to do that with my limited knowledge, but I'm still at a loss (again please forgive my ignorance, as I'm only 3 weeks into learning Unity/C#), and my own research is coming up empty.

    Thank you for your help!
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    Something like:
    Code (CSharp):
    1. var positionOffset = (Physics2D.gravity * rb.gravityScale) + (direction * speed);
    2. rb.MovePosition(rb.position + positionOffset * Time.fixedDeltaTime);
     
  10. BlackDove634

    BlackDove634

    Joined:
    Jan 30, 2020
    Posts:
    14
    Thank you, that seems to have fixed things! Movement is a little janky (the character feels very heavy), but that at least gives me a good starting point. Thanks!