#####################################################
EDIT - I posted a solution I am currently using below, but I’ll post it here so people can see it better (probably isnt the best solution for performance, but its fine in my case). Long story short, depending on how low our framerate is, we will update more times that frame, similar to how fixedupdate works.
Click for a solution
I saw in a post on a different forum somewhere that talked about basically doing what was done above with updating 4 times per frame, except in a smarter way.
Think of it like what fixedupdate does. When the framerate is low, it updates more times per frame. When our framerate is high, we dont want to be doing our update 4 times per frame since the framerate is already high enough to give nice results. So instead we do something like this…
Click for code
int timesteps = maxUpdateTimestep;
if(!alwaysUseMaxUpdateTimestep)
{
int safePhysicsIterator = Mathf.CeilToInt(Time.deltaTime / (1f / (float)targetPhysicsFramerate)); //If our framerate is low, we run our physics more times for more accuracy.
timesteps = Mathf.Clamp(safePhysicsIterator, 1, maxUpdateTimestep);
}
float deltaTime = Time.deltaTime / (float)timesteps;
if(deltaTime > 0f)
{
for(int i = 0; i < timesteps; i++)
{
UpdateMovementForces(deltaTime);
}
}
Some example code…
Click for example code
[Range(1,8)]
public int maxUpdateTimestep = 8; //higher = more movement accuracy, too high can = more loss of velocity(energy) over time (depending on your integration method I guess). 8 seems good for framerates 30+ with targetPhysicsFramerate being 240
public bool alwaysUseMaxUpdateTimestep; //not recommended as it is wasteful, but an option non the less.
[Range(30,480)]
public int targetPhysicsFramerate = 240; //If our framerate is low, we run our physics more times for more accuracy. This value is the desired physics framerate.
Vector3 velocity;
//My addforce method adds the forces to these instead of velocity directly
Vector3 currentForces; //ForceModes Impulse and VelocityChange are added to this.
Vector3 currentForcesWithDeltas; //ForceModes Force and Acceleration goes to this
void LateUpdate()
{
UpdateMovement();
}
void UpdateMovement()
{
velocity += currentForces;
int timesteps = maxUpdateTimestep;
if(!alwaysUseMaxUpdateTimestep)
{
int safePhysicsIterator = Mathf.CeilToInt(Time.deltaTime / (1f / (float)targetPhysicsFramerate)); //If our framerate is low, we run our physics more times for more accuracy.
timesteps = Mathf.Clamp(safePhysicsIterator, 1, maxUpdateTimestep);
}
float deltaTime = Time.deltaTime / (float)timesteps;
if(deltaTime > 0f)
{
for(int i = 0; i < timesteps; i++)
{
UpdateMovementForces(deltaTime);
}
}
currentForces = Vector3.zero;
currentForcesWithDeltas = Vector3.zero;
}
void UpdateMovementForces(float deltaTime)
{
Vector3 acceleration = velocity + (currentForcesWithDeltas * deltaTime); //Having currentForcesWithDeltas be added here with the subdivided deltaTime seems to give better results in regards to framerate independence.
acceleration = ApplyDrag(acceleration, drag, deltaTime);
CollisionInfo collisionInfo = new CollisionInfo();
//Symplectic Euler method (Our velocity is pretty much being set beforehand, even though it seems like its being set afterwards)
collisionInfo = TranslateAndHandleCollisions(acceleration * deltaTime);
velocity = collisionInfo.velocity / deltaTime;
}
With maxUpdateTimestep being 8 and targetPhysicsFramerate being 240, the lowest framerate we can get good framerate independent accuracy is at framerate 30 (since 240 / 8 = 30). The targetPhysicsFramerate is kinda like the framerate at which we think our physics will be good at and would want all our lower framerates to try and reach the same accuracy our targetPhysicsFramerate would give. (Im not sure if thats really what it is doing. All in all it might just be some number that is used to determine how many updates we are willing to do per frame.)
Edit- Its me way in the futuuuurree =), just wanted to say that the system I was using is basically how the Unreal Engine handles its physics. You can read about it here http://www.aclockworkberry.com/unreal-engine-substepping/
#################################################
I have been having an issue with creating my custom character controller when it comes to consistency.
Since I am moving in Update and not in FixedUpdate, I will have to rely on deltaTime for movement being “framerate independent”, however, it seems it might not be as framerate independent as I may have thought (at least in regards to inertia and what not).
My controller mimics a rigidbody in that it uses forces and velocities to move. This is so I can have momentum/inertia, outside forces pushing me, friction, etc…
To make the issue somewhat simpler to debug, I have been using the code unity gives on the character controller document page (altered a bit)
Click for code
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(CharacterController))]
public class TestConsistency : MonoBehaviour
{
public enum UpdateType {Update, FixedUpdate}
public UpdateType updateType = UpdateType.Update;
public float speed = 6.0F;
public float jumpSpeed = 40.0F;
public float gravity = 60.0F;
public float damping = 20f;
Vector3 moveDirection = Vector3.zero;
CharacterController controller;
void Awake()
{
if(GetComponent<CapsuleCollider>() != null) Destroy(GetComponent<CapsuleCollider>());
controller = GetComponent<CharacterController>();
}
void FixedUpdate() {if(updateType == UpdateType.FixedUpdate) UpdateCharacter();}
void Update() {if(updateType == UpdateType.Update) UpdateCharacter();}
void UpdateCharacter()
{
if(controller.isGrounded)
{
moveDirection += transform.TransformDirection(new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"))) * speed * Time.deltaTime;
if(Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
moveDirection.y -= ((gravity * Time.deltaTime) * .5f);
//moveDirection *= Mathf.Clamp01(1f - (damping * ExtTime.deltaTime));
//moveDirection *= Mathf.Pow(damping, ExtTime.deltaTime);
//moveDirection *= Mathf.Exp(-damping * Time.deltaTime);
//moveDirection -= (moveDirection * (damping * Time.deltaTime));
moveDirection *= (1f / (1f + (Time.deltaTime * damping)));
controller.Move(moveDirection * Time.deltaTime);
moveDirection.y -= ((gravity * Time.deltaTime) * .5f);
Debug.DrawRay(transform.position, transform.right, Color.red, 2);
}
}
My goal is to have decent consistency with my movements. I have been searching around for framerate independence and what not and am still confused on how things work.
One of those is how dividing the gravity in half and applying it before you move, and then after you move, somehow magically makes it framerate independent? Before I cut the gravity in half, it was just done before I applied my damping, and as the framerate got lower, the jump got lower. If I moved the code into FixedUpdate though, all was consistent.
Why does having the gravity in half and in two places make it framerate independent?
Since my controller script does not handle gravity separately and just takes in velocities and applies them all at once, do I need to make a special case or something? Maybe I just cut all velocities in half, use the first half to move, and then save the next half for the next frame?
I have also been having issues finding a way to apply a friction or damp to my controller as well (as seen by all the commented out formulas that I found online). The only one of those that seem to be framerate independent is the last uncommented out one, but I am not sure yet if it gives the feel I want (might just need to play with values).
Another issue which I have not got up to yet would be handling timers. I guess if the time ran out, I would need to grab the remaining time that would have ran if the framerate was higher and calculate how much I would have moved.
I am just very confused as to how to handle things and am wondering what others do to achieve more consistent movement in a variable timestep. I am not looking for pinpoint accuracy, but good enough to be competitive. I am also fine with the game not being so consistent less than 30fps since thats pretty much unplayable, but I am assuming fixing the inconsistency issues would make it pretty consistent at such low fps anyways.
I would use FixedUpdate, but I would probably have the timestep at max 120 per second, however, I am worried that the delay between checking for input in update, then waiting to move in fixedupdate + interpolation delays, might be to much for competitive players. Im also worried about situations where a player clicks space to jump, but they are still grounded since fixedupdate is waiting to run 10ms later, and then they click a button to do an action that if you are in the air, all is good, but if you are grounded, you get messed up. I would then need to run all code in fixedupdate or something, which would only add more things to being delayed.
When seeing what some say about framerate, Ive seen them say 300+ frames feels good and responsive, while lil ol non pro me thought 60fps was pretty good.
Telling me to just use FixedUpdate or that 10ms delay isnt much (I think it might be) isnt really what I am looking for, but If you feel strongly about it then please do tell with your reasoning. However, surely there should be ways without fixedupdate, otherwise why have a character controller?
I appreciate any help ^^