Alternate solution to onGUI for GUI?

Guys could you please tell me any other methods to make the GUI for my game other than using onGUI. The reason for this onGUI is putting too much load on the mobile, and is lagging badly, even on the computer. And the higher resolution of the device, the more the lag.

I want to make a level selection screen, which would look something like the image posted below (which is the current version, made with onGUI calls)

I know some people go about making GUIs with 3d objects but I really need guidance in that direction. Or any other solution will work for me, but I really need to get rid of onGUI as it really isn’t working out at all.

Thanks for your help really appreciate it :slight_smile:

I agree with YoungDeveloper that you are doing a lot of unnecessary calculations every frame. Almost all the variables in OnGUI can be stored in variables at Start() instead of calculated every OnGUI() call. Normally you can get away with doing a bit of that although it’s bad practice. In your case I would convert pretty much everything to preset variables if you really are lagging that bad.

Also I think an even bigger problem for you is that you are using those for() loops in your OnGUI(). I think that’s a REALLY bad idea and should be removed immediately from your code if at all possible. The reason why you’re getting such horrendous lag is that OnGUI() may be having a hard time keeping up with those For() loops.

I don’t know the details of onGUI() well enough but it’s quite possible it does not wait to complete one cycle before it starts the next one so you could have multiple identical for loops executing simultaneously? I don’t know if that’s even possible but if the game gets laggier the longer you have the menu open I think that’s the cause.

So I think the solution is to declare as many of those variables as possible into your Start() function. And get rid of all those For() loops. Your GUI should already know what to do with pre-existing variables whenever possible, keep the logic in there to a minimum.

I just counted the objects in one of my scenes which has the most enemies and there is over 60 objects in the scene all with unique and active OnGUI() included in their scripts. This also includes the biggest OnGUI script in my game that controls the majority of button logic, as well as the main menu which has options, inventory, player stats, displays all the GUI stuff in inventory and on a picture of the player and updates the stat numbers like Strength, Intelligence for each piece etc. This script is nearly 5000 lines of code long (but uses if statements to skip huge sections that are irrelevant to the current display). And I don’t lag at all from OnGUI() on either of my phones.

So my point is if you just have one script that is causing so many problems something is SERIOUSLY wrong I think it’s the for() loops. And doing that many calculations is makign the For Loops way worst. all those calculations every OnGUI().

Here’s an example of how I set up some of the level selection stuff that I think is a lot more performance friendly. I tried to just grab some code snippets directly from my project not really bothering to format it much and include every detail:

Vector3 matrixVector;

float native_width = 1280;
float native_height = 720;

float rx;
float ry;

void Start()
{
float rx = Screen.width/ native_width;
float ry = Screen.height / native_height;
		
//set matrix to format all GUI easy		
matrixVector = new Vector3 (rx, ry, 1);

//get certain playerprefs to avoid having to retrieve them excessively

levelsUnlockedInt = PlayerPrefs.GetInt ("Levels Unlocked");

if (PlayerPrefs.GetInt ("World Select Button", 1) == 1)
		{
			worldSelectInt = 1;
		}

audio.Play();
//etc more playerPrefs or bools variables whatever you need to reduce amount of stuff in OnGUI()
}



Void OnGUI()
{


//THIS MATRIX IS MOST IMPORTANT PART!!!
//ALLOWS YOU TO EASILY SET RESOLUTION TO ANY SCREEN SIZE
// CAN BE DONE ACCURATELY THROUGHOUT THE ENTIRE PROJECT IF SET UP RIGHT
GUI.matrix = Matrix4x4.TRS (new Vector3(0, 0, 0), Quaternion.identity, matrixVector);


//FUNCTION TO DISPLAY LOADING SCREEN AFTER THIS BOOL IS SET WHEN THEY HIT LEVEL
if (GlobalDataScript.loadingScreenImageBool == true)
			{
				GUI.DrawTexture (new Rect(0, 0, 1280, 720), loadingScreenTexture);
				
				//ONCE LOADING SCREEN SET LOAD LEVEL
				StartLoadingScreenReadyFunction();
			
				return;
			}




//code before getting to level select screen

else if (levelSelectBool == true)
		{
			//BACKGROUND TEXTURE
			GUI.DrawTexture (new Rect(0, 0, native_width, native_height), levelSelectBackgroundTexture);
		//}
		
		//notice how all buttons can be specific coordinates thanks to Matrix!
		//Even better if you set all those positions and sizes for buttons as Vector2 on Start()



		//exit the level Select Texture
		if (GUI.Button (new Rect (980, 620, 300, 100), returnTexture, startGameStyle))
			{
				
			
				SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
				otherObjectsScriptSoundPlayer.button1SoundFunction();

				levelSelectBool = false;
				
				//GlobalDataScript.loadingScreenImageBool = true;
				//loadingLevelInt = 1;
			}
		
		//example of optional details about player progress
		GUI.Label (new Rect (720, 80, 100, 100), "Tier 1 Armor Set Pieces Found: " + GlobalDataScript.tierOneArmorPiecesFound 
			+ "/5", levelMysteryStyle);
		
		
		
		
		//which world is selected
		//WORLD 1 button color and logic control
		if (worldSelectInt == 1)
		{
			 if (GUI.Button (new Rect (540, 0, 240, 80), worldOneTextureSelected, startGameStyle))
				{
					SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
					otherObjectsScriptSoundPlayer.button1SoundFunction();

				
					PlayerPrefs.SetInt ("World Select Button", 1);
					worldSelectInt = 1;	
				}	
		}
		
		else if (GUI.Button (new Rect (540, 0, 240, 80), worldOneTexture, startGameStyle))
		{
			SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
			otherObjectsScriptSoundPlayer.button1SoundFunction();

			
			PlayerPrefs.SetInt ("World Select Button", 1);
			worldSelectInt = 1;	
		}
		
		
		//WORLD 2 button color and logic control
		if ((levelsUnlockedInt >= 7) && (worldSelectInt == 2))
		{
			if (GUI.Button (new Rect (780, 0, 240, 80), worldTwoTextureSelected, startGameStyle))
				{
					SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
					otherObjectsScriptSoundPlayer.button1SoundFunction();

				
					PlayerPrefs.SetInt ("World Select Button", 2);
					worldSelectInt = 2;	
				}
		}
		
		else if (levelsUnlockedInt >= 7)
		{
		 if (GUI.Button (new Rect (780, 0, 240, 80), worldTwoTexture, startGameStyle))
				{
					
					SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
					otherObjectsScriptSoundPlayer.button1SoundFunction();

					PlayerPrefs.SetInt ("World Select Button", 2);
					worldSelectInt = 2;	
				}
		}


		//etc more worlds
		
		
		
		
		}
		
		//WORLD 1 level buttons
		if (worldSelectInt == 1)
		{
			if (GUI.Button (new Rect (0, 170, 300, 100), levelOneTexture, startGameStyle))
			{
				GlobalDataScript.playerAtStoreInt = 0;
				
				GlobalDataScript.currentLevelInt = 1;
				
				
				GlobalDataScript.loadingScreenImageBool = true;
				loadingLevelInt = 4;
				
				SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
				otherObjectsScriptSoundPlayer.button2SoundFunction();
			}


		
			
			if (levelsUnlockedInt >= 1)
			{
				if (GUI.Button (new Rect (0, 320, 300, 100), levelTwoTexture, startGameStyle))
				{
					SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
					otherObjectsScriptSoundPlayer.button2SoundFunction();

					GlobalDataScript.playerAtStoreInt = 0;
					GlobalDataScript.currentLevelInt = 2;
					
					
					GlobalDataScript.loadingScreenImageBool = true;
					loadingLevelInt = 5;
				}
			}
			
			
			
			if (levelsUnlockedInt >= 2)
			{
				if (GUI.Button (new Rect (0, 470, 300, 100), levelThreeTexture, startGameStyle))
				{
					SoundPlayerScript otherObjectsScriptSoundPlayer = soundObject.GetComponent<SoundPlayerScript>();
					otherObjectsScriptSoundPlayer.button2SoundFunction();
					
					GlobalDataScript.playerAtStoreInt = 0;
					GlobalDataScript.currentLevelInt = 3;
					
							
				
					GlobalDataScript.loadingScreenImageBool = true;
					loadingLevelInt = 6;
				}
			}

		//etc buttons for all other levels on that world..

	}

//any other displays that should be visible on any world
}


//loads the level after the loading screen is set in OnGUI() and this function is called
void StartLoadingScreenReadyFunction()
	{
		Application.LoadLevel(loadingLevelInt);
	}

Maybe the problem isn’t in function itself, but in how you are accessing and initializing data, textures and overall script structure.

Instead of using OnGui, you could use guiTextures. As far as I know, they don’t make a call to OnGui and you can change them out at runtime by modifying the texture variable of the component.

If you are able to, hold out for Unity GUI system that they are working on. It will make life easier as far as GUI. If you can’t wait, then study GUI skins and how to implement them. And keep it simple. You don’t need to code every bit of the GUI, GUI artwork can make things appear more complex than they really are. There are several ways to go about the same thing as always. I believe the new GUI Unity is working on will treat the GUI elements all as GameObjects - just food for thought.