Creating a simple graphical FPS display.

I am trying to create a graphical display for the FPS count. It [should] draw(s) about 20 lines horizontally. The bigger the fps drop, the higher the lines. However, I don’t want all lines to move in unison. If the fps drops, the only line that should have a different height is the current one being drawn. Pretty much the same as the MineCraft fps counter:


Here is my current code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FPSCounter : MonoBehaviour {
    float deltaTime = 0.0f;

    int w = Screen.width, h = Screen.height;

    GUIStyle style = new GUIStyle ();

    bool notCalled = true;

    float OldFPS = 0;
    float diff = 0;
    int fCount;
    int wait;
    float[] pos = new float[20];

    void Update () {
        deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
    }

    void OnGUI () {
        FPStext ();
        DrawFPSLine ();
    }

    void FPStext () {
        Rect rect = new Rect (0, 0, w, h * 2 / 100);
        style.alignment = TextAnchor.UpperLeft;
        style.fontSize = h * 2 / 100;
        style.normal.textColor = new Color (0.0f, 0.0f, 0.5f, 1.0f);
        float msec = deltaTime * 1000.0f;
        float fps = 1.0f / deltaTime;
        string text = string.Format ("{0:0.0} ms ({1:0.} fps)", msec, fps);
        GUI.Label (rect, text, style);
    }

    void DrawFPSLine () {
        int maxW = 95;
        float NewFPS = 1.0f / deltaTime;

        diff = Mathf.Round (NewFPS - OldFPS * 10f) / 100f;
        for (int i = 0; i < pos.Length; i++) {
            pos[i] = 0 + diff;
        }
        while (fCount == 20) {
            foreach (float f in pos) {
                Drawing.DrawLine (new Vector2 (100, 400), new Vector2 (100, Mathf.Floor (300 - diff)), new Color (0.1f, 0.3f, 0.7f, 1.0f), 5);
            }
            fCount = 0;
        }
        OldFPS = NewFPS;
        fCount++;
    }
}

Is this possible to do?

Dream

FYI: The Drawing.DrawLine(); function is a simple 2D line drawer I found online. I had a search for it now, but can’t find it again. If I do, I will add it. Here is the premise though (taken from the script):

//****************************************************************************************************
    //  static function DrawLine(rect : Rect) : void
    //  static function DrawLine(rect : Rect, color : Color) : void
    //  static function DrawLine(rect : Rect, width : float) : void
    //  static function DrawLine(rect : Rect, color : Color, width : float) : void
    //  static function DrawLine(Vector2 pointA, Vector2 pointB) : void
    //  static function DrawLine(Vector2 pointA, Vector2 pointB, color : Color) : void
    //  static function DrawLine(Vector2 pointA, Vector2 pointB, width : float) : void
    //  static function DrawLine(Vector2 pointA, Vector2 pointB, color : Color, width : float) : void
    // 
    //  Draws a GUI line on the screen.
    // 
    //  DrawLine makes up for the severe lack of 2D line rendering in the Unity runtime GUI system.
    //  This function works by drawing a 1x1 texture filled with a color, which is then scaled
    //   and rotated by altering the GUI matrix.  The matrix is restored afterwards.
    //****************************************************************************************************

Of course it is possible to do. I would assume you are running into some kind of problem with your implementation. Why not mention what that problem is?

The main problem I seem to be having is that the lines don’t show up. I have a feeling that is because, I draw them every twentieth of a (second?) but as soon as they are drawn, they are cleared from the gui. Hence not being visible.
I searched but found no way to override the gui clearing system so I can add my own in (if that is the problem).

Dream

EDIT: Just looking through the line drawer script, I see that it creates an instance of the current gui matrix, draws the line, the restores it back to what it was. Could this be the problem?

Instead of drawing the line immediately, you probably want to store the data needed to create the lines in some collection, and then redraw the lines from the collection on every frame. As data gets to old you remove the old data from the collection.

That is what I was trying to do with the array. I have just had another idea. I will see if that works.

Dream

EDIT: I have gotten somewhere with this. However, they are all in unison.

void DrawFPSLine () {
        int maxW = 95;
        float NewFPS = 1.0f / deltaTime;
        diff = Mathf.Round (NewFPS - OldFPS * 10f) / 100f;
        for (int i = 0; i < pos.Length; i++) {
            pos[i] = 0 + diff;
        }
        if (pos.Length == 20) {
            foreach (float f in pos) {
                Drawing.DrawLine (new Vector2 (100 + width, 400), new Vector2 (100 + width, Mathf.Floor (300 - f)), new Color (0.1f, 0.3f, 0.7f, 1.0f), 5);
                width += 5;
            }
            width = 0;
            pos = new float[20];
        }
        OldFPS = NewFPS;
    }

Ok, I am very close - just one last problem.
My current code…

void DrawFPSLine () {
        int maxW = 95;
        float NewFPS = 1.0f / deltaTime;
        diff = Mathf.Round (NewFPS - OldFPS * 10f) / 100f;

        pos.Add (0 + diff);

        foreach (float f in pos) {
            Drawing.DrawLine (new Vector2 (100 + width, 400), new Vector2 (100 + width, Mathf.Floor (300 + Mathf.Abs (f) * 10)), new Color (0.1f, 0.3f, 0.7f, 1.0f), 5);
            width += 5;
        }

        if (pos.Count >= 20) {
            count = 0;
            pos = new List<float> ();
        }

        waitTime = 0;
        count++;
        OldFPS = NewFPS;
        width = 0;
    }

…is working how it should - the higher the lag spike, the higher the line and none are in unison. The only problem now is that with a List<> I can’t overwrite the old values like I can with a normal array (arr[0] = ‘whatever’), so I have to create a whole new list. This causes all the lines to disappear, so it starts to flash. I can’t just use a normal array as you have to specify how big it is, and with my method, the size changes every update.

Dream

You can just remove items from the list. Something I do often:

private List<WhateverType> myList = new List<WhateverType>();  //type isn't important, just have a list
private int maxListLength = 20;

//Call this whenever we want to add whatever to the list
//Automatically removes the item at index 0 if the list expands larger than maxListLength
public void AddWhateverToList(WhateverType whatever)
{
    myList.Add(whatever);
    if (myList.Count > maxListLength)
    {
        //Because the list has grown longer than we want the maximum, we remove the oldest member of the list
        //Which if the list is never reordered is the item at index 0
        myList.RemoveAt(0);
    }
}

Awesome, that works!

Thanks,
Dream

float NewFPS = 1.0f / deltaTime;

        diff = Mathf.Round (NewFPS - OldFPS * 10f) / 100f;
        pos.Add (0 + diff);

        //orange: rgb(242, 145, 55)
        //yellow: rgb(241, 217, 55)
        //red: rgb(240, 54, 54)

        foreach (float f in pos) {
            Color col = new Color (Mathf.Abs (f).map (0, 5, 240, 245).map(0,255,0,1), Mathf.Abs (f).map (0, 5, 50, 220).map(0,255,0,1), Mathf.Abs (f).map (0, 5, 50, 55).map(0,255,0,1), 1);
            Drawing.DrawLine (new Vector2 (0 + width, 200), new Vector2 (0 + width, Mathf.Floor (100 + Mathf.Abs (f) * 10)), col, 1);
            width += 1;
        }

        if (pos.Count >= 300) {
            count = 0;
            pos.RemoveAt(0);
        }

        waitTime = 0;
        count++;
        OldFPS = NewFPS;
        width = 0;
    }