When calculating FPS in Unity, why does it count like this? [duplicate] - unity3d

When I start up my game it stays around 95-101 rapidly changing, in between all of those numbers.. but when I open up the stats bar I'm getting upper 200's low 300's
so wondering why that is still new to c# so be easy on me lol. heres the code
thanks in advance as always ^_^.
float deltaTime = 0.0f;
void Update()
{
deltaTime += (Time.deltaTime - deltaTime) * 0.1f;
}
void OnGUI()
{
int w = Screen.width, h = Screen.height;
GUIStyle style = new GUIStyle ();
Rect rect = new Rect (0, 0, w, h * 2 / 100);
style.alignment = TextAnchor.UpperRight;
style.fontSize = h * 2 / 100;
style.normal.textColor = new Color (255.0f, 255.0f, 255.0f, 1.0f);
float msec = deltaTime * 1000.0f;
float fps = 1f / deltaTime;
string text = string.Format ("({1:0.} fps)", msec, fps);
GUI.Label (rect, text, style);
}
}

In order to display a meaningful FPS rate you need to measure how many frames were rendered over a constant period of time, for example one second. Then only after that period do you display the calculated value on screen. This will provide for an average frames per second as opposed to an instantaneous frames per second, the latter of which is not particularly useful in most cases as it leads to widely fluctuating values.
Code
First define some fields:
DateTime _lastTime; // marks the beginning the measurement began
int _framesRendered; // an increasing count
int _fps; // the FPS calculated from the last measurement
Then in your render method you increment the _framesRendered. You also check to see if one second has elapsed since the start of the period:
void Update()
{
_framesRendered++;
if ((DateTime.Now - _lastTime).TotalSeconds >= 1)
{
// one second has elapsed
_fps = _framesRendered;
_framesRendered = 0;
_lastTime = DateTime.Now;
}
// draw FPS on screen here using current value of _fps
}
Cross-technology
It should be pointed out that the above code makes no particular use of Unity whilst still being reasonably accurate and is compatible with many frameworks and APIs such as DirectX; OpenGL; XNA; WPF or even WinForms.
When I start up my game it stays around 95-101 rapidly changing, in between all of those numbers.. but when I open up the stats bar I'm getting upper 200's low 300's
The ASUS VG248QE is 1ms and the max it can do is 144Hz so it is unlikely you are getting "upper 200's low 300's". FPS is meaningless when VSYNC is turned off on a non-GSYNC monitor. Is your VSYNC turned on?

In Unity, FPS is equivalent to number of Updates that occur in 1 second. This is because Update() is called every Time.deltaTime seconds.
InvokeRepeating method
You can also use InvokeRepeating to implement your own FPS counter while using only integers, like this:
private int FrameCounter = 0;
private int Fps = 0;
void Start()
{
InvokeRepeating("CountFps", 0f, 1f);
}
void Update()
{
FrameCounter++;
}
private void CountFps()
{
Fps = FrameCounter;
FrameCounter = 0;
}
Then just display the Fps variable in the OnGUI() method. Using this method, your Fps value will get updated every second; if you want more frequent updates, change the last argument of InvokeRepeating call and then adjust the Fps calculation accordingly.
Note, however, that InvokeRepeating takes Time.timeScale into account, so e.g. if you pause the game with Time.timeScale = 0f; the counter will stop updating until you unpause the game.
FixedUpdate method
Another approach is to count the FPS in FixedUpdate() method instead of OnGUI() or Update(). This gets called every Time.fixedDeltaTime seconds which is always the same, no matter what. The value of Time.fixedDeltaTime can be set globally for the project via menu Edit->Project Settings->Time, item Fixed Timestep.
In this case, you would count frames the same way (in Update), but update your FPS counter in FixedUpdate - which is basically the same as calling you own method with InvokeRepeating("CountFps", 0f, 0.02f) (0.02f being a typical Time.fixedDeltaTime value, but this depends on your project settings as per above).
Conclusion
Most of the time, you won't need to update the displayed FPS that often, so I personally like to use the InvokeRepeating method and 1 second intervals.

OnGUI function is called at las twice per frame (sometimes more). You are calculating your "FPS" inside OnGUI so it will almost never be accurate.
Defining :
deltaTime += (Time.deltaTime - deltaTime) * 0.05f;
will bring your FPS values closest to real but it will not be accurate if you calc it on OnGUI method.
I guess (not sure) that you should use FixedUpdate() instead of OnGUI() to calc your FPS. (also you don't need to change your deltaTime to multiply by 0.05f if you use FixedUpdate)

Related

Unity rope swinging physics algorithm: Player stuck mid-swing

I have implemented the following tutorial in Unity (2D) attempting to create a rope swinging platformer: https://gamedevelopment.tutsplus.com/tutorials/swinging-physics-for-player-movement-as-seen-in-spider-man-2-and-energy-hook--gamedev-8782
void FixedUpdate()
{
Vector2 testPosition = playerRigidbody.position + playerRigidbody.velocity * Time.deltaTime;
Hooked(testPosition);
}
private void Hooked(Vector2 testPosition)
{
Vector2 t = new Vector2(tetherPoint.position.x, tetherPoint.position.y);
Debug.DrawLine(tetherPoint.position, playerRigidbody.position);
float currentLength = (testPosition - t).magnitude;
if (currentLength < tetherLength)
{
currentLength = (playerRigidbody.position - t).magnitude * Time.deltaTime;
}
else
currentLength = tetherLength;
if ((testPosition - t).magnitude > tetherLength)
{
Vector2 x = (testPosition - t).normalized;
testPosition = new Vector2(x.x * currentLength, x.y * currentLength);
playerRigidbody.velocity = (testPosition - playerRigidbody.position) * Time.deltaTime;
playerRigidbody.position = testPosition;
}
}
It seems to function correctly on the downward swing but when the player begins to travel upwards they become stuck floating in the air and don't drop to the middle of the arc. The swing also does not propel them very high on the other side even when dropped from height.
EDIT (Further clarification): Interestingly When the player is dropped from the other side of the tetherPoint it stops in the same spot, this time only half-way down. It's as if the player is being pulled toward a single position even when manually moved in the editor while playing no matter the direction.
EDIT: User John cleared up my concerns about deltaTime.
I've tried examining the change in variables during play but I just can't figure out why it's not working correctly. I think the issue lies somewhere in my interpretation of the original psudeo-code to C#.
Another question on the same tutorial has been asked previously but unfortunately that users implementation was very different than mine: Game rope swing physics acting weird
EDIT: Since posting I've updated the code to use AddForce and MovePosition instead but it's still the same.
playerRigidbody.AddForce((testPosition - playerRigidbody.position) * Time.deltaTime);
playerRigidbody.MovePosition(testPosition);
It looks like you're using Time.deltaTime from a method that is called from FixedUpdate. What you want to use instead is Time.fixedDeltaTime.
FixedUpdate is called at a set interval (eg. 50fps) for physics updates, but regular Update is called at a different varying frequency (up to hundreds of times a second if you've got a fast computer/simple game).
Time.deltaTime is used for the Update method, and so the value of it can be different each time Update is called, as the time between Update calls varies.
However, because FixedUpdate is called at the same interval each time, Time.fixedDeltaTime is constant and (normally) much larger than Time.deltaTime. Your code doesn't work well with Time.deltaTime, as it doesn't represent the actual difference in time between each FixedUpdate call, but Time.fixedDeltaTime should work.
As a side note, you're correct that you should be multiplying by the time delta rather than dividing. the time delta should be multiplied when calculating positions (eg. for the Vector2 testPosition assignment and the currentLength calculation), but for calculating the velocity you should be dividing the time delta (because velocity = distance/time).

Unity3D Input.GetAxis for Mouse not consistent

i am working on camera rotations based on mouseInput and i want it to have consistent sensitivity across all framerates. According to the unity documentation, the Input.GetAxis should be inherently framerate independent for the mouse movement.
What I am finding is that when i use the code below and change the framerate from 200+ to 30, the Input.GetAxis is returning very different outputs. For 200+ fps the GetAxis is low around like 2-5 where for 30 fps it is returning around 10-15 for the same mouse movements. Its causes a very drastic sensitivity difference in-game. Am i missing something? Thanks
public Rigidbody _playerRigidBody;
private Vector2 _lookInput;
private void Start()
{
//Application.targetFrameRate = 30;
}
private void Update()
{
_lookInput.x = Input.GetAxis("Mouse X");
}
void FixedUpdate()
{
var sensitivity = 300f;
var newPlayerRotation = _playerRigidBody.rotation * Quaternion.Euler(_lookInput.x * sensitivity * Vector3.up * Time.deltaTime);
_playerRigidBody.MoveRotation(newPlayerRotation);
}
}
I have tested everything in this little function and the only thing that causes the issue is the Input.GetAxis. Its inconsistent. Any ideas or solutions or workarounds?
"framerate independent" means the value is depend on the movement of the mouse, it doesn't mean the value is consistent.
For framerate = 200, value = 2-5 means the mouse move 2-5 points in 1/200 seconds.
So to get the move distance during 1 second use:
_lookInput.x = Input.GetAxis("Mouse X") / Time.deltaTime;

How to move an object by a certain angle over a period of time in a circle [duplicate]

I a new here and i try to start working with Unity Engine.
Could somebody explain me, how works Quaternion.Slerp? Because I want to rotate some object in different angles 90, 180 and 270. My code you can see below. Unfortunately when I add 180 degrees, object make crazy things and than put rotation to (0, 180, 180) for this game object. I would like to get (180,0,0)
public float speed = 0.1F;
private float rotation_x;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
rotation_x = transform.rotation.eulerAngles.x;
rotation_x += 180;
}
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(rotation_x, transform.eulerAngles.y, transform.eulerAngles.z), Time.time * speed);
}
Most examples out there including Unity examples from their official website are using Lerp in the wrong way. They didn't even bother to describe how it works in the API documentation. They just starch it in the Update() function and call it a day.
Mathf.Lerp, Vector3.Lerp, and Quaternion.Slerp work by changing from one position/rotation to another with the t value(last parameter) being passed in.That t value is also know as time.
The min of the t value is 0f and the max is 1f.
I will explain this with Mathf.Lerp to make it easier to understand. The Lerp functions are all the-same for both Mathf.Lerp, Vector and Quaternion.
Remember that Lerp takes two values and returns values between them. If we have a value of 1 and 10 and we do Lerp on them:
float x = Mathf.Lerp(1f, 10f, 0f); will return 1.
float x = Mathf.Lerp(1f, 10f, 0.5f); will return 5.5
float x = Mathf.Lerp(1f, 10f, 1f); will return 10
As you can see, the t(0) returns the min of the number passed in, t(1) returns the max value passed in and t(0.5) will return mid point between the min and the max value. You are doing it wrong when you pass any t value that is < 0 or > 1. That code in you Update() function is doing just that. Time.time will increase every second and will be > 1 in a second, so you have problems with that.
It recommended to use Lerp in another function/Coroutine instead of the Updated function.
Note:
Using Lerp has a bad side of it when it comes to rotation. Lerp does not know how to rotate Object with the shortest path. So bear that in mind. For example, you have an Object with 0,0,90 position. Lets say you want to move the rotation from that to 0,0,120 Lerp can sometimes rotate left instead of right to reach that new position which means it take longer to reach that distance.
Let's say we want to make the rotation (0,0,90) from whatever the current rotation is. The code below will change the rotation to 0,0,90 in 3 seconds.
ROTATION OVER TIME:
void Start()
{
Quaternion rotation2 = Quaternion.Euler(new Vector3(0, 0, 90));
StartCoroutine(rotateObject(objectToRotate, rotation2, 3f));
}
bool rotating = false;
public GameObject objectToRotate;
IEnumerator rotateObject(GameObject gameObjectToMove, Quaternion newRot, float duration)
{
if (rotating)
{
yield break;
}
rotating = true;
Quaternion currentRot = gameObjectToMove.transform.rotation;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
gameObjectToMove.transform.rotation = Quaternion.Lerp(currentRot, newRot, counter / duration);
yield return null;
}
rotating = false;
}
INCREMENTAL ANGULAR ROTATION OVER TIME:
And to just rotate the Object to 90 in z axis, the code below is a great example of that. Please understand there is a difference between moving Object to new rotational point and just rotating it.
void Start()
{
StartCoroutine(rotateObject(objectToRotate, new Vector3(0, 0, 90), 3f));
}
bool rotating = false;
public GameObject objectToRotate;
IEnumerator rotateObject(GameObject gameObjectToMove, Vector3 eulerAngles, float duration)
{
if (rotating)
{
yield break;
}
rotating = true;
Vector3 newRot = gameObjectToMove.transform.eulerAngles + eulerAngles;
Vector3 currentRot = gameObjectToMove.transform.eulerAngles;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
gameObjectToMove.transform.eulerAngles = Vector3.Lerp(currentRot, newRot, counter / duration);
yield return null;
}
rotating = false;
}
All my examples are based on frame-rate of the device. You can use real-time by replacing Time.deltaTime with Time.delta but more calculation is required.
Before anything, you can't add 180 on euler angles like that, and that's mainly what is causing your problem. You'd better use quaternion directly instead, or work on the transform itself.
You can think of a quaternion as an orientation in space. In contrary to what have been said, I do recommend learning how to use them if you can. However, I don't recommend using euler angles at all... as they're suject to different writing conventions, and will fail sometimes. You can look at 'gimbal lock' if you want details about that.
Simply a slerp or lerp (standing for spherical linear interpolation, or linear interpolation respectively) is a way to interpolate (go from one orientation to another, by increasing t from 0 to 1, in a coroutine or anywhere else) between orientation A and B. The difference between the two is that the slerp is giving you the shortest path from A to B.
In the end, when t = 1, lerp(A,B,t) and slerp(A,B,t) will give you B.
In your case, if you want to instantly rotate an object in space to a specific orientation, I suggest you use Quaternion.AngleAxis which is the most forward way to describe mathematically a quaternion.
If you want to add a rotation, say 90° to you actual orientation (without animation between the two), you can do something like this :
transform.rotation *= Quaternion.AngleAxis(axis_of_rotation, angle)
or use transform.rotate (depending on the parameters, it can be a right multiply, or left : local, or world transform).
Programmers' answer is detailling how to animate your transform. But I do suggest you to investigate quaternion themselves, as it will give you global understanding of space transforms.

Unity coroutine movement over time is not consistent/accurate?

I have a coroutine that moves my Camera upwards each time the player reaches a certain point in the game. I used a coroutine so that the camera will move smoothly over time.
Here's a snippet of my code:
private IEnumerator MoveCameraUpCoroutine(Vector3 startPos, Vector3 endPos, float duration)
{
float elapsedTime = 0;
while(elapsedTime < duration)
{
transform.position = Vector3.Lerp(startPos, endPos, (elapsedTime/duration));
elapsedTime += Time.deltaTime;
yield return null;
}
}
public void MoveCameraUp(Vector3 startPos, Vector3 endPos, float duration)
{
StartCoroutine(MoveCameraUpCoroutine(startPos, endPos, duration));
}
In my controller script, I just call my coroutine like this:
cam.GetComponent<CameraMovement>().MoveCameraUp(cam.transform.position,
new Vector3(cam.transform.position.x, cam.transform.position.y + setupLevel.heightOfBlock, cam.transform.position.z),
0.1f);
The problem with this is that the camera's movement is not always consistent in terms of where it's supposed to stop. I did some debugging. On the first run, the camera moved to the 0.7864508 yPos. On the second run, the camera moved to the 0.7789915 yPos. etc. It's not consistent.
But when I simply use Translate instead of my coroutine:
cam.transform.Translate(0, setupLevel.heightOfBlock, 0);
I get consistent end values for the camera's yPos at 0.7876318, which is what I need. But this code does not move the camera smoothly over time which is not what I want.
Does anyone know how to fix this coroutine issue? I don't know but I think there's something wrong with my coroutine code. Any help is greatly appreciated.
The result is actually quite consistent with what's expected. There's absolutely nothing wrong with your code, rather it's because of of differences in frame rates.
The reason you're seeing the minor differences is because there's no guarantee that two frames will take the exact amount of time to render.
Take a look at this line
elapsedTime += Time.deltaTime;
What you're doing here is adding an inconsistent value to your elapsed time. (i.e. Time.deltaTime is different every frame).
One partial fix could be to use Time.smoothDeltaTime instead, which is a smoothed out value for deltaTime over several frames. This, however is not going to be perfect.
A second approach, (not entirely an answer per se, but I'm leaving this here for others as well) is to use a tweening engine such as DoTweenor iTween.
These engines have methods that essentially do what you're trying to.
float elapsedTime = 0;
float ratio = elapsedTime / duration;
while(ratio < 1f)
{
elapsedTime += Time.deltaTime;
ratio = elapsedTime / duration;
transform.position = Vector3.Lerp(startPos, endPos, ratio);
yield return null;
}
With this setup, your loop will run until ratio is 1. When 1, endPos is returned and the loop exits next round.
I think the issue was that you compare elapsedTime to duration. So on the last run, you move then you increase and you compare. As a result, the last increase is not considered and you end up somewhere near the end but not at the end.

Quaternion rotation in coroutine does not work properly?

Alright, I'm trying to make an object called 'pathblock' rotate 90 degrees clockwise every time the player presses 'E'. The player should be able to spam the button, with the block turning 360 degrees without fail.
I want to see the rotation animation, so I am using coroutine in combination with a slerp function. The coroutine is called in update, if E is pressed.
//Rotates the selected pathblock by 90 degrees over a specified time. A coroutine is necessary to render each slerp() result per seperate frame
IEnumerator RotatePathblock()
{
Debug.Log("Start rotation!");
Quaternion start = Quaternion.Euler(new Vector3(pathblock.transform.rotation.x, pathblock.transform.rotation.y, pathblock.transform.rotation.z)); //Set start variable for Slerp(), the current rotation of the pathblock
Quaternion end = Quaternion.Euler(new Vector3(start.x, start.y, start.z-90.0f));
Debug.Log(string.Format("Target Angle: {0}", end.eulerAngles.z));
float normalizationFactor = 1.0f / pathblockRotationTime; //We need to normalize time since slerp() works with values between 0-1; we can convert values by multiplying with this factor
float timePassed = 0.0f; //Time passed since the start of the linear interpolation. Starting at 0, it increases until it reaches 1. All values are rendered.
while(timePassed < 1.0f) //While the time passes is less than 1 (the maximum of a linear interpolation)
{
timePassed += Time.deltaTime * normalizationFactor; //Increase the timePassed with the time passed since the last frame; the time is first normalized
pathblock.transform.rotation = Quaternion.Slerp(start, end, timePassed); //Set the pathblock rotation to a new value defined by linear interpolation
yield return null; //Stop the function, finish Update() and return to this while loop; this will cause all slerp() values to render, resulting in a smooth animation
}
}
The first press turns the pathblock 90 degrees, as expected.
The second press sets the pathblock back to its original rotation, and turns it 90 degrees again.
This leads me to believe that the 'start' variable never changes, even though it should set itself to the new pathblock.transform.rotation when the function is called, getting the new rotation.
If anyone could look at what's wrong, I'd appreciate it.
Any other critique on my code, comments etc. would also be appreciated!
Quaternion start = Quaternion.Euler(new Vector3(pathblock.transform.rotation.x, pathblock.transform.rotation.y, pathblock.transform.rotation.z)); //Set start variable for Slerp(), the current rotation of the pathblock
Should be:
Quaternion start = Quaternion.Euler(new Vector3(pathblock.transform.eulerAngles.x, pathblock.transform.eulerAngles.y, pathblock.transform.eulerAngles.z)); //Set start variable for Slerp(), the current rotation of the pathblock