I have made myself this simple fps counter script that display’s the current frame count in a simple ui text. So my question is kind of weird, but does this script display’s accurate frame rate? Or are there any better ways checking the current frame rate? I just want to make sure I’m not seeing false thing on my screen. Cause sometimes I see pretty high fps and I just want to make sure it’s actually true or not. Thank you.
The Script:
using UnityEngine;
using UnityEngine.UI;
public class FPSDisplay : MonoBehaviour
{
public int avgFrameRate;
public Text display_Text;
public void Update ()
{
float current = 0;
current = Time.frameCount / Time.time;
avgFrameRate = (int)current;
display_Text.text = avgFrameRate.ToString() + " FPS";
}
}
Here’s a full script. Just drag in your own Text (Legacy) component.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FPSCounter : MonoBehaviour
{
public Text Text;
private Dictionary<int, string> CachedNumberStrings = new();
private int[] _frameRateSamples;
private int _cacheNumbersAmount = 300;
private int _averageFromAmount = 30;
private int _averageCounter = 0;
private int _currentAveraged;
void Awake()
{
// Cache strings and create array
{
for (int i = 0; i < _cacheNumbersAmount; i++) {
CachedNumberStrings[i] = i.ToString();
}
_frameRateSamples = new int[_averageFromAmount];
}
}
void Update()
{
// Sample
{
var currentFrame = (int)Math.Round(1f / Time.smoothDeltaTime); // If your game modifies Time.timeScale, use unscaledDeltaTime and smooth manually (or not).
_frameRateSamples[_averageCounter] = currentFrame;
}
// Average
{
var average = 0f;
foreach (var frameRate in _frameRateSamples) {
average += frameRate;
}
_currentAveraged = (int)Math.Round(average / _averageFromAmount);
_averageCounter = (_averageCounter + 1) % _averageFromAmount;
}
// Assign to UI
{
Text.text = _currentAveraged switch
{
var x when x >= 0 && x < _cacheNumbersAmount => CachedNumberStrings[x],
var x when x >= _cacheNumbersAmount => $"> {_cacheNumbersAmount}",
var x when x < 0 => "< 0",
_ => "?"
};
}
}
}
This one’s similar to the others with a minor difference in format. I feel like any of these work really well, lots of great coders out there! This one in particular allows an easy edit to string format, refresh rate, and time-lapse lets you switch between deltaTime, smoothDeltaTime of fixedDeltaTime to see the difference. It’s not any better than other examples, just another fun option with more to play around with.
public class FPSCounter : MonoBehaviour
{
public float timer, refresh, avgFramerate;
string display = "{0} FPS";
private Text m_Text;
private void Start()
{
m_Text = GetComponent<Text>();
}
private void Update()
{
//Change smoothDeltaTime to deltaTime or fixedDeltaTime to see the difference
float timelapse = Time.smoothDeltaTime;
timer = timer <= 0 ? refresh : timer -= timelapse;
if(timer <= 0) avgFramerate = (int) (1f / timelapse);
m_Text.text = string.Format(display,avgFramerate.ToString());
}
}
Editor shows “fake” FPS because it subtracts editor overhead time, this script shows actual FPS in editor window. But your FPS in build will be closer to the stats window FPS.
This script shows it accurately, it works on mobile, it uses the GUI.
It divides the framecount by the time passed, it can be configure to update at any interval.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShowFPSMobile : MonoBehaviour
{
// provided by Niter88
private string fps = "";
private WaitForSecondsRealtime waitForFrequency;
GUIStyle style = new GUIStyle();
Rect rect;
bool isInicialized = false;
private void Awake()
{
//float fraction = 0.5f; // Render at half the resolution of current screen
//float fraction = 0.8f;
//float fraction = 1f;
//Screen.SetResolution((int)(Screen.currentResolution.width * fraction), (int)(Screen.currentResolution.height * fraction), true);
//don't use vsync on mobile, limit fps instead
// Sync framerate to monitors refresh rate
//Use 'Don't Sync' (0) to not wait for VSync. Value must be 0, 1, 2, 3, or 4
QualitySettings.vSyncCount = 0;
// Disable screen dimming
Screen.sleepTimeout = SleepTimeout.NeverSleep;
//Inicialize(true); //use for testing on editor
}
private IEnumerator FPS()
{
int lastFrameCount;
float lastTime;
float timeSpan;
int frameCount;
for (; ; )
{
// Capture frame-per-second
lastFrameCount = Time.frameCount;
lastTime = Time.realtimeSinceStartup;
yield return waitForFrequency;
timeSpan = Time.realtimeSinceStartup - lastTime;
frameCount = Time.frameCount - lastFrameCount;
fps = string.Format("FPS: {0}", Mathf.RoundToInt(frameCount / timeSpan));
}
}
void OnGUI()
{
// Display
GUI.Label(rect, fps, style);
//GUI.Label(new Rect(Screen.width - 110, 5, 0, Screen.height * 2 / 100), fps, style);
//GUI.Label(new Rect(10, 10, Screen.width, Screen.height * 2 / 100), fps, style);
//GUI.Label(new Rect(Screen.width - 100, 10, 150, 20), fps, style);
}
private void Inicialize(bool showFps)
{
isInicialized = true;
style.alignment = TextAnchor.UpperLeft;
style.fontSize = Screen.height * 3 / 100;
style.normal.textColor = new Color32(0, 200, 0, 255);
rect = new Rect(Screen.width * 90 / 100, 5, 0, Screen.height * 2 / 100);
if(showFps)
StartCoroutine(FPS());
}
public void SetNewConfig(GraphicSettingsMB gSettings)
{
Application.targetFrameRate = gSettings.targetFrameRate;
waitForFrequency = new WaitForSecondsRealtime(gSettings.testFpsFrequency);
if (!isInicialized) Inicialize(gSettings.showFps);
if (!gSettings.showFps)
Destroy(this.gameObject);
}
}
[SerializeField]
public class GraphicSettingsMB
{
public byte targetFrameRate = 30;
public byte testFpsFrequency = 1;
public bool showFps = false;
}
How do i acutally use any of those scripts? I created a new one but what component of my scene should i add the script to? Or does this work differently?
Here’s the script from the top, but i modified the text to work with TextMeshPro. Just add the script to an empty gameobject or whatever you’d like honestly, then drag a UI text from your canvas ( edit: I added an additional text indicator which will now read as, “FPS: (however many frames)” ) ( another edit: I added a space to “FPS: " … I missed that somehow)” )
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class FPSCounter : MonoBehaviour
{
private TextMeshProUGUI Text;
public TextMeshProUGUI FPS_Text;
private Dictionary<int, string> CachedNumberStrings = new();
private int[] _frameRateSamples;
private int _cacheNumbersAmount = 300;
private int _averageFromAmount = 30;
private int _averageCounter = 0;
private int _currentAveraged;
void Awake()
{
// Cache strings and create array
{
for (int i = 0; i < _cacheNumbersAmount; i++)
{
CachedNumberStrings[i] = i.ToString();
}
_frameRateSamples = new int[_averageFromAmount];
}
}
void Update()
{
// Sample
{
var currentFrame = (int)Math.Round(1f / Time.smoothDeltaTime); // If your game modifies Time.timeScale, use unscaledDeltaTime and smooth manually (or not).
_frameRateSamples[_averageCounter] = currentFrame;
}
// Average
{
var average = 0f;
foreach (var frameRate in _frameRateSamples)
{
average += frameRate;
}
_currentAveraged = (int)Math.Round(average / _averageFromAmount);
_averageCounter = (_averageCounter + 1) % _averageFromAmount;
}
// Assign to Private Text value
{
Text.text = _currentAveraged < _cacheNumbersAmount && _currentAveraged > 0
? CachedNumberStrings[_currentAveraged]
: _currentAveraged < 0
? "< 0"
: _currentAveraged > _cacheNumbersAmount
? $"> {_cacheNumbersAmount}"
: "-1";
}
// Assign to UI with additional text indicator
{
FPS_Text.text = "FPS: " + Text.text;
}
}
}
}