- Home /
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 :)
Unity's GUI system is crap and nobody uses it. Just get 2dtoolkit from the asset store, or one of its competitors.
Every $$anonymous$$ute you spend learning to use the GUI system is a waste of your life as you'll never use it in any real project or any commercial project
As of now I am not in a condition to buy any tool kits, as I just spent on buying a unity license. Do you know any free ones? Or possibly (and something I'd appreciate more) the alternative method to onGUI, and how to code it myself
For sure. All you have to do is make 2D sprites. So, at worst, just make a plane and sit your flat image on it. What you want is just a quad with a texture on it.
This is a few lines of code at worst. From there you can just build the game normally.
Urge you to post a new question saying "Free alternative to 2DToolkit" then "I want to use 2DToolkit but cannot afford it, what is the free alternative." You will find many questions on here explaining how to make flat 2D sprites and so on.
Never, ever use the "GUI" system for any reason. It's an utter waste of time. Also, it's utterly silly.
It's a game engine, you just want to make a normal 2.5D game.
Note - unity is releasing "unity 2d" soon (next year?) because they got sick of everyone using 2dtoolkit, so they are "doing it themselves". So at that point everyone will have to change to using that.
Anyway post a new question.
BTW just change your camera to "orthogonal" rather than "perspective" to make 2.5D games.
It's ironic that - I'd say - the very biggest (biggest selling, most popular) games done with Unity3D are not 3D, but rather flat games like yours (angry birds, ski safari, etc etc)
some code in here will probably help you, carefully exa$$anonymous$$e this long answer
http://answers.unity3d.com/questions/321762/how-to-assign-variable-to-a-prefabs-child.html
be sure to vote it up (thumb) as I only do this for the points :)
Answer by RyanZimmerman87 · Sep 22, 2013 at 02:18 AM
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);
}
Thanks Ryan! I'm going to definitely have another look at my code and assess it.
Let me know one thing though, using your method which I have just breezed over, how are you making the individual level selection boxes (like I have?) or is this code doing something else?
I'm going to have to make the for loops in the onGUI function, cause otherwise I won't be able to arrange them in terms of rows and columns dynamically..?
Another question is, I see you are directly using GUI textures whereas Im using boxes and adding textures to the boxes with style = none (in some of my other scripts though, not here) Is directly drawing the textures a better way to do it?
@Ryan - this is extremely admirable coding but ... (a) it's a 2.5D game he should be doing it as a 2.5D game. and (b) the GUI system is a total waste of time (will unity just delete it anyway when they release "unity 2d" ?)
The individual selection boxes are all Texture2D buttons.
I'll try to include some more code from that script that I didn't last time to hopefully explain it in further detail:
//this should go in any Script as early as possible if you are using the matrix to format OnGUI()
//I use it in a empty scene before the Start Screen and also do some other stuff like retrieving and setting the "Graphics Quality" prefab
void Awake()
{
Screen.SetResolution(1280, 720, true);
//example of setting quality settings if you want to do that
qualityLevel = PlayerPrefs.GetInt("Graphics Quality", 0);
if (qualityLevel == 0)
{
//graphicsQualityString = "Graphics Quality = Fastest";
QualitySettings.SetQualityLevel(0, true);
}
else if (qualityLevel == 1)
{
//graphicsQualityString = "Graphics Quality = Fast";
QualitySettings.SetQualityLevel(1, true);
}
//etc more settings
}
//The following code is for that same script from my last example
//This is VERY important to include for my example
//style lets you easily change font type, font allignment, etc
//more importantly it makes buttons automatically display correctly ins$$anonymous$$d of having strange padding or border like effects
public GUIStyle startGameStyle;
public Texture2D levelOneTexture;
public Texture2D levelTwoTexture;
public Texture2D levelThreeTexture;
//ins$$anonymous$$d of doing this like my last example:
if (GUI.Button (new Rect (0, 170, 300, 100), levelOneTexture, startGameStyle))
//It would be even better do this since all the buttons are same size
vector2 levelSelectButtonVectorSize;
vector2 levelOneVectorPosition;
vector2 levelTwoVectorPosition;
vector2 levelThreeVectorPosition;
void Start()
{
//OnGUI() size variables should be set at start to work properly with matrix
//from last example script did the matrix stuff:
float rx = Screen.width/native_width;
float ry = Screen.height / native_height;
//set button size BEFORE matrix resize preparation
levelSelectButtonVectorSize = new Vector2 (300,100);
//now use rx and ry to set the vector size for matrix proportions
levelSelectButtonVectorSize.x = levelSelectButtonVectorSize.x * rx;
levelSelectButtonVectorSize.y = levelSelectButtonVectorSize.y * ry;
//unlike size position does not need to be resized before matrix happens automatically in OnGUI()
levelOneVectorPosition = new Vector2 (0, 170);
levelTwoVectorPosition = new Vector2 (0, 320);
levelThreeVectorPosition = new Vector2 (0, 470);
}
//So then all those buttons would be like:
if (GUI.Button (new Rect (levelOneVectorPosition.x, levelOneVectorPosition.y, levelSelectButtonVectorSize.x, levelSelectButtonVectorSize.y), levelOneTexture, startGameStyle))
{
//code
}
if (GUI.Button (new Rect (levelTwoVectorPosition.x, levelTwoVectorPosition.y, levelTwoButtonVectorSize.x, levelSelectButtonVectorSize.y), levelOneTexture, startGameStyle))
{
//code
}
//more stuff
I'm kind of OCD about trying to get things set up right so I've been working on perfecting the GUI stuff quite a bit since I started my project. And after everything I've done I'm pretty sure this example above is the best way to do buttons and scale OnGUI()
I am not making each box dynamically which is another reason this code is so much faster. You already have all the sizes, positions, scaling, and textures for the button visuals ready to go on Start!
Then the matrix simply just slaps it all down for you and doesn't need to do any calculations it just draws it all out very fast.
I think OnGUI() is one place where you really shouldn't worry about having it layout the columns and rows dynamically, especially if it requires a For() loop. I think it's a lot better to just have everything laid out for size and position at Start()
Then you can just use simple variables like my example to deter$$anonymous$$e which buttons and textures you need to display currently. I think this will be much faster than doing for() loops every time!
Even if you have to make a ton of Vector2 locations for different stuff and it takes awhile to write it out in OnGUI() I think this is still the best way to do this. Even if the code looks long I think OnGUI() is really not a good place to perform logic whenever it's possible to avoid it.
You can also probably do all your mouse position stuff outside of OnGUI. I've never tried the mouse hover over stuff so maybe that is best in OnGUI() but for detecting positions of clicks to for example ignore a raycast while playing the game if it's over a button you can set up something like:
rect healthButtonHitCheckRect;
void Start()
{
healthButtonHitCheckRect = new Rect (healthPotionVectorPosition.x, healthPotionVectorPosition.y, vectorSize.x, vectorSize.y);
}
void Update()
{
if (Input.GetButtonDown ("Fire1"))
{
if (healthButtonHitCheckRect.Contains(Input.mousePosition))
{
rayBool = false;
return;
}
}
}
However it's worth noting that rects start at the bottom left of screen ins$$anonymous$$d of top left for the coordinates. Also the rect must be sized using the rx and ry type stuff which was used on healthPotionVectorPosition Vector2.
So you might be able to use this type of thing to do your hover over logic but I've only tried it on GetButtonDown or GetButton not hover.
I'm just trying to give some full examples of OnGUI() since when I was learning this stuff it seems nobody ever posted detailed examples it was all like 1 liners syntax similar to Unity documentation.
Answer by YoungDeveloper · Sep 21, 2013 at 06:34 PM
Maybe the problem isn't in function itself, but in how you are accessing and initializing data, textures and overall script structure.
The script structure is honestly very simple. Just 2 for loops to initialize the buttons and the lock/unlock box.
I've done quite some research before posting this question, and I'm not the only one who feels onGUI is too heavy to use.
So, I think its safe to assume its the problem with onGUI
Then any modern mobile should handle it without any problems.
Would you like to see my code for the image I posted above, and tell me what might be wrong?
I'd like to see your code if you wanna post it. You should be able to use a menu you like that no problem.
I am using OnGUI() for all sorts of stuff in my game like enemy health bars, all the buttons, floating text etc.
It's a bit laggy on older phones but it's a 3D adventure game so kind of expected. Runs great on S4 and Galaxy Nexus.
But if your GUI stuff is lagging even your computer something sounds wrong with that script to me.
Hopefully OnGUI() will be improved though, might have to start disabling GameObjects that aren't in use for it since it seems to be the most CPU heavy part of my game according to the Profiler, kinda surprising but it's easy to work with so I deal with it.
Even having the majority of the OnGUI() stuff in my scenes instantly return() unless the enemies are within 50 meters to the player it still seems to be a surprisingly big CPU hog.
@YoungDeveloper @RyanZimmerman87 Here is the script. And Ryan, you've got only a few elements running in onGUI at once and its giving you performance hiccups, my scene runs over 150 gui elements at once, possibly why it's giving me more problems. Have a look and see what can be done for me :)
I've attached the script as a text file, you can make a new JS file in unity and run it directly to see for yourself (add some random textures in the inspector).
Just did some calculations it takes about 3 seconds to detect a hover over a gui button
And I've used a Galaxy s2, a BB Z10 and some random lower end Samsung phone to test, and all 3 have given similar results.
Answer by Visual Programmer · Sep 25, 2013 at 11:54 PM
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.
To do so, I would have to make 30+ GUI textures and arrange them manually? I don't $$anonymous$$d using GUITextures, if there is a way to automate them
No, you can make a prefab that switches between 4 different GUI Textures (it'll pick a texture that corresponds to the star level or if it's locked) and holds a GUI Text that contains the number of the button. Then you arrange the prefabs across the screen.
I find it hard to believe there is no way to automate this
It's almost incomprehensible you wouldn't just use 2DToolkit for this. the whole job would be done, completely, in as much time as it takes to drag some PNGs to a folder.
You can't, realistically, use Unity's GUI system for actual program$$anonymous$$g, like to program a game. It's just for bringing up messages and buttons during development.
The whole question is very confusing.
2DToolkit must have used some feature in Unity, it hasn't come out of thin air. I would like to build my own GUI, and use similar methods incorporated by 2DToolkit, NGUI, etc. Right now I am not in a position to spend money on those assets, but need to work on my games GUI. Possibly for the next project I will consider buying it for sure
Answer by bpears · Sep 29, 2013 at 12:57 PM
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.
Currently the things are GUIskinned. The problem is making 30 such boxes, and 90 such stars is too heavy on the system. With onGUI.
And using gameobjects that look like level selection GUI is great, but I would have to manually place every single thing in the scene which would be too much work. Plus its not feasible and is worse than putting together a hack
bpears -- are you talking about "unity2d" which is co$$anonymous$$g soon, which is a replacement for 2DToolkit by Unity. it is a system for handling sprites in unity. so currently, all 2.5D games are done with 2dToolkit, presumably once unity releases unity2d, all 2.5D games will be done with unity2d
in contrast. yes, apparently unity is (in the far future) going to release a new GUI system. (since the current one is crap)
gui systems exist for the reason: bringing up messages on screen.
they have utterly no relation, at all, to making 2.5D games.
most of the world's 2.5D games are now made in unity - you need look no further than the new angry birds, for instance.
but this has utterly no connection, in any way, to a "gui" system. (whether unity's current gui system, which is crap, or the new one they are going to release maybe in a year or two.)
you don't make games with a gui system. you don't make 2.5D games with a gui system. the idea that angry birds is made with unity's gui (or ngui, or ezgui), is, risible.
there is no reason he would "wait until unity's new gui system" appears since, gui systems have utterly no connection, at all, in any way shape or form, to making 2.5D games.
you make 2.5d games in unity using SPRITES, which is a quad (small plane) with an image on it. then you set them up standing up, and you set your camera to orthographic
to do so, you can either use (1) 2dtoolkit, (2) wait for unity2d (which is a copy of 2dtoolkit, as it were) in a few months, or (3) "roll your own". To "roll your own do this
1) make a plane
2) sit an image on the plane
voila, you have "a sprite"
there is utterly no connection at all in any way, at all, to "gui". you don't use "gui" to make 2.5D games.
you just make "sprites" (ie a small plane with the image sitting on it, and then use an orthographic camera)
again, if you actually meant "wait for unity2d" - correct. you can see video presentations about unity2d on unity's site. no connection to current or future or any "gui" systems.
OP, you mention "manually place every single thing in the scene which would be too much work". To do that, use a for loop. Or, two nested for loops. it is only a line or two of code.
@Fattie - I did mean the new GUI we are eventually getting. But since I don't know if this is just a hobby project or whatever, I figured I'd mention it, in case waiting wouldn't be a big deal for him/her. It was more of a FYI in that part.
@Puneet$$anonymous$$ you could try maybe just using 1 skin element for all of those buttons plain, and 1 skin element for each of the numbers/play buttons combined, 1 skin element for the stars. When you make the texures for them, you could make it so that, for example the button changes from 1 to 3 stars, the UV coordinates offsets to another part of the texture; 1 texture has all the variations of stars. And same idea for other varied parts.
You could also do a separate skin element for each state of stars, each state of unlockedAndPlayable/locked, and so on.
You could also do something similar using GameObjects with the appropriate textures in front of the camera, and since they are unmoving, you could batch them to one draw call. That is if you used one material for all of them. When you need parts to appear, set their renderers to true, depending on player progress and such things.
Like I said, many ways to do it. Just remember to keep your code simple.
Your answer
![](https://koobas.hobune.stream/wayback/20220613114556im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
GUI not work after building 1 Answer
How to make a selection list using either GUI system? 0 Answers
Level select design approaches. 0 Answers
Free Gui solutions 2 Answers