Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Lord_Grumpledorf · Jul 06, 2021 at 09:29 PM · scripting problemfpscharactercontrollerframeratetime.deltatime

Problems with player movement at higher frame rates (Time.deltaTime not producing consistent results)

Hey all,


Working on an FPS game where I'm using the Unity CharacterController to handle movement. I had to try for a while to get a decent feeling Inertia system to work, but I got there and recently decided to add a mini debug menu where I can set Vsync and FPS limits for testing. If I increased FPS past ~100 the player would stop moving altogether. I believe that as the time between the frames decreases the move value that I'm creating gets so small that the engine essentially reads it as a zero, but mathematically the behavior should still be the same at high and low FPS (in my head at least). Any help would be much appreciated; I really hate the way VSync feels in shooters and I kinda need to be able to disable it and allow players to set their own frame rate.


Removing the inertial calculations (If I can call them that, kinda brute forced them 'til they worked) would solve the problem but I'm trying to make the game play slower/tactical so that's not really an option.


For some context:
This is all happening in Update() and the "move" variable is a vector3 that contains only x and z components. It gets added to a vector3 "velocity" variable that contains only a y component in the move command.
Also I'm using 2019.4.18f1

      if (grounded)
     {


         if (Mathf.Abs(controller.velocity.magnitude) < maxSpeed)
         {
             if (x != lastX || z != lastZ)
                 move = (currVel * decelSpeed) + ((transform.right * x + transform.forward * z) * accelSpeed * Time.deltaTime);
             else
                 move = currVel + ((transform.right * x + transform.forward * z) * accelSpeed * Time.deltaTime);
             
         }
         else if (Mathf.Abs(controller.velocity.magnitude) >= maxSpeed)
         {
             


             if (x != lastX || z != lastZ)
             {
                 move = (currVel * decelSpeed) + ((transform.right * x + transform.forward * z) * accelSpeed * Time.deltaTime);
             
             }
             else
             {
                 move = ((transform.right * x + transform.forward * z)) * maxSpeed;
             }

            

         }


         if (x == 0 && z == 0)
         {
             move = controller.velocity;

             move *= decelSpeed;
         }

         if (x != lastX)
             lastX = x;
         if (z != lastZ)
             lastZ = z;

         airTime = 0f;

     }

     

     controller.Move((move * Time.deltaTime) + (velocity * Time.deltaTime));
     currVel = controller.velocity;




To break this down, it checks player input (x / z) against a stored previous input. If they're different it modifies current velocity by a deceleration value and then adds the regular acceleration. If values are the same it does the acceleration calculation which is based off a stored velocity value. If the velocity exceeds a maximum it clamps to the maximum unless the new player input direction differs from the last in which case it slows down and starts over, essentially.


What I've tried:
1. Moving and altogether removing the Time.DeltaTime from the calculation.
2. Clamping what delta time value is acceptable to 0.01 (the lowest value that consistently worked), though this obviously lead to different results based on framerate. I was able to move at 144 fps, but it accelerated far faster and the inertia was practically non-existent. In addition if I exceeded 144 the same problem occurred, which rules out Time.deltaTime as part of the calculation being a problem, kind of...
3. Separating the Time.DeltaTime into it's own bit of the calculation. (IE move *= Time.DeltaTime;). This resulted in jerky movements when accel was kept at 15 and was too fast at higher values.


From what I've deduced from testing, my only conclusion is that Time.DeltaTime is too small (between 0.006 and 0.007) at higher framerates and called too frequently to make significant changes to velocity. In comparison it sits around 0.016 or so when Vsync is on which clearly massively effects the calculation.
For my given values of "acceleration = 15", "deceleration = 0.7", and "x" and "z" at most being equal to 1 (positive or negative depending on input axis) the calculation would go as follows:

For initial movement :
"currVel" 0 + (("no input x" 0 + "true forward z" 1) * "accelSpeed" 15) x time.deltatime --> this should equal 0.24 at 60 FPS. This is an additional 0.24 movement added per frame (on average). However at high FPS this goes down to 0.0975 at 144 FPS (average). Mathematically the result should be similar if not identical over a set amount of time but instead no movement occurs.



Can't get ShadowPlay to record the app, but I have a script outputting the Time.deltatime values used above so they're accurate. I don't have the "move" variable being set anywhere other than in this loop, so I'm entirely unsure what could be causing this behavior.


Please don't hesitate to let me know if there's additional information needed, I've been trying to fix this for a few days now and am unable to find a solution. Thank you! Sorry for the long post, wanted to get as much detail as possible.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Lord_Grumpledorf · Jul 13, 2021 at 06:50 PM

No idea if anyone's seen this yet, or if anyone will but I managed to solve the problem by changing the math around a bit and then moving my calculations in fixed update instead of regular update. Feels good and responsive enough and stays consistent regardless of framerate. Behavior is mildly different at higher framerates, but the average player won't notice since the movement logic (the actual controller.move()) is still in update and the values being fed are small enough to not cause massive changes.

Please see updated code below.

     if (grounded)
     {
         if (Mathf.Abs(controller.velocity.magnitude) < maxSpeed)
         {
             if (x != lastX || z != lastZ)
             {
                 move = (currVel * decelSpeed) + ((transform.right * x + transform.forward * z) * (accelSpeed * Time.deltaTime / 1 / Time.deltaTime));
             }
             else
             {
                 move = currVel + ((transform.right * x + transform.forward * z) * (accelSpeed * Time.deltaTime / 1 / Time.deltaTime));
             }
         }
         else if (Mathf.Abs(controller.velocity.magnitude) >= maxSpeed)
         {
             if (x != lastX || z != lastZ)
             {
                 move = (currVel * decelSpeed) + ((transform.right * x + transform.forward * z) * (accelSpeed * Time.deltaTime / 1 / Time.deltaTime));
             
             }
             else
             {
                 move = ((transform.right * x + transform.forward * z)) * maxSpeed;
             }
         }
         if (x == 0 && z == 0)
         {
             move = controller.velocity;

             move *= decelSpeed;
         }

         if (x != lastX)
             lastX = x;
         if (z != lastZ)
             lastZ = z;

         airTime = 0f;
     }



Got the idea for this from a velocity/acceleration post that you can find here: https://gamedev.stackexchange.com/questions/117250/movement-appears-to-be-frame-rate-dependent-despite-use-of-time-deltatime
Took a bit of fiddling to get it working the way I wanted, but it works wonderfully now.



The change, while likely not entirely necessary, is not causing any problems at runtime and is consistent while simultaneously making the movespeed variable more human-readable so I'm happy with how it is for now. Just wanted to let everyone know that I've figured it out. If the code seems applicable to your project, don't hesitate to use it. It's based on the Brackey's character controller video, so it should be easily implementable in most projects with that as a player movement base.



Also, just to prove it works I managed to get ShadowPlay to work so I've put a link below. https://youtu.be/ASn4eXS1a4Q

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

310 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Character controller (3d) don´t move whith a moving platform. 1 Answer

Character controller without Deltatime 1 Answer

if the fps is high the camera rotate much faster 1 Answer

Jumping Issue on Different Computers 0 Answers

How would i rewrite this script with a Character Controller? C# 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges