Search Unity

  1. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  2. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  3. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  4. Participate with students all over the world and build projects to teach people. Join now!
    Dismiss Notice
  5. Build games and experiences that can load instantly and without install. Explore the Project Tiny Preview today!
    Dismiss Notice
  6. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  7. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Framerate independent jump

Discussion in 'Scripting' started by KhenaB, Jul 13, 2018.

  1. KhenaB

    KhenaB

    Joined:
    Aug 21, 2014
    Posts:
    260
    Hey,

    I'm trying to build a raycast based character controller and I can't make the Jump method framerate independent no matter what I try, here is a test project from one of the tutorials I've been following, which is also not framerate independent.

    Just press play, move with arrows or wasd and jump with spacebar, and try to clear the pillar. Now change the public variable "Target Framerate" on the Player script from 30 to 60+ and try again. Why is the jump affected by the framerate in this scenario?

    Thanks
     

    Attached Files:

  2. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,773
    It's better to post your code rather than requiring a download.
    I noticed this line in the player:
    velocity.y += gravity * Time.deltaTime;

    A compiler will do multiplication before addition, so I think you want:
    (velocity.y += gravity) * Time.deltaTime;

    I didn't try it or anything.
     
  3. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    836
    Ditto on the posting of the relevant code, not a whole project.

    Anyway, so that others can assist, here's that code of yours:

    Code (CSharp):
    1. public class Player : MonoBehaviour {
    2.  
    3.     public int targetFramerate = 30;
    4.  
    5.     public float moveSpeed = 6;
    6.     public float jumpVelocity = 6;
    7.     public float gravity = -25;
    8.  
    9.     Vector3 velocity;
    10.     Controller2D controller;
    11.  
    12.     void Start()
    13.     {
    14.         controller = GetComponent<Controller2D> ();
    15.     }
    16.  
    17.     void Update()
    18.     {
    19.         Application.targetFrameRate = targetFramerate;
    20.  
    21.         if (controller.collisions.above || controller.collisions.below)
    22.             velocity.y = 0;
    23.  
    24.         Vector2 input = new Vector2 (Input.GetAxisRaw ("Horizontal"), Input.GetAxisRaw ("Vertical"));
    25.  
    26.         //JUMP
    27.         if (Input.GetKeyDown (KeyCode.Space) && controller.collisions.below)
    28.             velocity.y = jumpVelocity;
    29.  
    30.         //GRAVITY
    31.         velocity.y += gravity * Time.deltaTime;
    32.  
    33.         //MOVE
    34.         velocity.x = input.x * moveSpeed;
    35.        
    36.         controller.Move (velocity * Time.deltaTime);
    37.     }
    38. }
    Some reactions:

    It looks like you're applying gravity even when grounded. Maybe you shouldn't be doing that?

    As for the framerate issue, my hunch is that it's because you're multiplying by Time.deltaTime twice. I'd need to do some math on that to verify it, but it seems weird. You're reducing the velocity by a deltaTime-based amount, and then moving a deltaTime-based amount. Perhaps its compounding the time in a weird way.

    Maybe it should be like this?

    Code (CSharp):
    1.         //JUMP
    2.         if (Input.GetKeyDown (KeyCode.Space) && controller.collisions.below)
    3.             velocity.y = jumpVelocity;
    4.  
    5.  
    6.         //MOVE
    7.         velocity.x = input.x * moveSpeed;
    8.  
    9.         velocity *= Time.deltaTime;
    10.  
    11.         //GRAVITY
    12.         velocity.y += gravity * Time.deltaTime;
    13.      
    14.         controller.Move (velocity);
     
  4. KhenaB

    KhenaB

    Joined:
    Aug 21, 2014
    Posts:
    260
    I've figured out why this is happening thanks to Eno-Khaon on Unity Answers

    It's easier to understand by looking at it visually so I suggest taking a look at what he posted, basically the more frames, the smaller the subtracted amount will be (because it's multiplied every frame by delta) so the higher it will jump.

    I'll keep looking for a solution

    @dgoyette thanks for posting the code
     
  5. KhenaB

    KhenaB

    Joined:
    Aug 21, 2014
    Posts:
    260
    So Bunny31's solution at my Unity Answers post works perfectly, the gravity has to be applied in two parts, example:

    Code (CSharp):
    1. //GRAVITY
    2. velocity.y += gravity * 0.5f * Time.deltaTime;
    3.  
    4. //MOVE
    5. velocity.x = input.x * moveSpeed;
    6.  
    7. controller.Move (velocity * Time.deltaTime);
    8.  
    9. //GRAVITY
    10. velocity.y += gravity * 0.5f * Time.deltaTime;