0
\$\begingroup\$

I'm trying to get the position of items in the game world and render them onto the screen. I've managed to get this working, however I seem to be running into major performance issues when ever I enable this feature. I am losing about 40-50 fps. I have a feeling this is related to iterating through the array doing the transformation within the OnGUI() life cycle method which is called multiple times a frame, however I'm not entirely sure. Any pointers would be appreciated, I'm still very new to game development.

Code in question:

private void OnGUI()
{
    if (showItems)
    {
        DrawLoot();
    }

    if (showItems && Time.time >= itemNextUpdateTime)
    {
        lootItems = UnityEngine.Object.FindObjectsOfType<LootItem>();
        itemNextUpdateTime = Time.time + itemUpdateInterval;
    }
}

Draw Method:

public void DrawLoot()
{
    foreach (LootItem item in lootItems)
    {
        if (item == null || item.name == null || item.name == string.Empty)
        {
            continue;
        }

        var pos = Camera.main.WorldToScreenPoint(item.transform.position);
        float itemDistance = Vector3.Distance(Camera.main.transform.position, item.transform.position);
        Vector3 vector = new Vector3(pos.x, pos.y, pos.z);
        if (itemDistance <= maxLootDrawingDistance && vector.z > 0.01)
        {
            string itemLabel = $"{item.Item.ShortName.Localized()} - {itemDistance}";
            GUI.Label(new Rect(vector.x - 50f, Screen.height - vector.y, 100f, 50f), itemLabel);
        }
    }
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Don't use OnGUI — this is ancient. You'll likely get substantially better performance drawing these item markers with the modern UI system. Also, your guard clause should use ||, not && — an item cannot simultaneously be null and have a name field. \$\endgroup\$
    – DMGregory
    Feb 5, 2020 at 12:42
  • \$\begingroup\$ Hi, sorry recently refactored this code, will update to reflect this. With regards to to using a modern UI system, could you elaborate on that please? Thanks. \$\endgroup\$
    – dracog
    Feb 5, 2020 at 12:46
  • \$\begingroup\$ I can't give an intro to the UI system at present, but you can find lots of documentation and tutorials online to get you started. \$\endgroup\$
    – DMGregory
    Feb 5, 2020 at 12:48
  • 1
    \$\begingroup\$ I'm not looking for you to teach me necessarily, but just some more information so I can go and learn this on my own. So you mentioned I shouldn't use OnGUI? Can you elaborate on what I life cycle method I should be using in that case? Also using GUI to render stuff is outdated as well I imagine so I should look to use a more updated UI library? \$\endgroup\$
    – dracog
    Feb 5, 2020 at 12:54
  • \$\begingroup\$ See the manual as a good start. (Note, anything involving OnGUI is named IMGUI by Unity) \$\endgroup\$
    – troien
    Feb 5, 2020 at 15:18

1 Answer 1

0
\$\begingroup\$

I think you should abandon OnGUI completely.

You can use unity's UI system to achieve your desired outcome.OnGuı is an immediate method which is not performance friendly.You can think of OnGui as an unity's debugging toolkit,its great to have quick setup and feedback yes but it should not be an endgame for your game/project's UI.

Furthermore,if your goal to only see items on the screen,you can use simple sprites, If its only text you want to show then you can use textmesh component in unity.

Plus when i look at your code above i think there is more room to increase your FPS.

First,avoid immediate context.Try avoid updating stuff every time.Use unity's framework as long as you can,creating your own custom script with your custom solutions is often costly than you'd expect.So if you want to display the related graphics(text,sprite) of your items on your screen,display them when you're sure it's in the canvas of the camara.To achieve this you can use unity's physics to detect whenever the object is inside the camera's view,or you can use SpriteRenderer2D's isVisible property which indicates if an item visible to the camare.(Beware this isVisible property will be marked as true if there is an another camera rendering your sprite)

Second,avoid immediate context again.I see you collect your items' data everytime before you display them.UnityEngine.Object.FindObjectsOfType() is an expensive solution to this.FindObjectsOfType iterates every object in your scene and checking each if the type you looking for matches with them thus its pretty expensive,and more expensive when you have large scene.To avoid this you can use a pool.Try saving your each item to this pool,this pool may have basic interface like,add new item to pool,remove item from the pool,with something like this you can avoid collecting your items each frame.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .