I started using Unity right around when uGUI first being released, so I spent too much time with it predecessor. As an Asset Store publisher, I do still work with IMGUI occasionally, and really loved its simplicity.
With UI Toolkits on the horizon, I wonder why IMGUI is being completely phased out. I understand it have no GUI builder, and how it can be performance intensive for complex UIs. However, in other software engineering circle, I heard nothing but praise for imgui as a concept.
Those who has worked with any kind of imgui in the past, Unity’s or any other, what problems has the paradigm gave you personally?
I actually thought the idea was really clever and really convenient, as you can make complex dynamic layouts this way, and it resembles functional programming somewhat.
Defining layout with code is not human readable. You cant look at the code and in realtime transform it into visuals like you can html/css or XAML/styles.
MVVM and MVC fixes these problems. You abstract the code from the view in a clever way
uGUI isnt perfect either, they should have gone with a MVVM approuch
I have worked with both. Well, mostly my colleague who is the UI designer but some for me too. Our entire UI is made in uGUI. The old crap we only use for our internal editor tools
Most of the issues I had with it were in the implementation, not the concept. Stuff like some info being hard to access in certain contexts, or some accessible info being highly context dependent in unclear and sometimes inconsistent ways.
Still, you mention performance and… yeah… that’s a big one, even in the Editor. I’ve got a few objects in my current project which make the game noticably slower just from showing in the Inspector while testing.
Huh? HTML defines the content, not visuals. That’s what CSS is for, unless you’re working with really old stuff or ignoring best practices.
I worked with all kind of XML based retained mode UI. They all get extremely complex very fast. In fact, nowaday retained mode UI are being written in a more immediate mode like syntax, see Flutter or Swift UI.
A what you see is what you get editor can be nice, maybe, I don’t use it for web or app work. But I know some do, none of the pro web deisgner or web app UI guys I worked with though.
Another is that the whole GUI is re-run every time something might have changed. I change something in a text field and the whole GUI it’s a part of gets re-run, including all of the serialisation and/or reflection stuff going on to populate it. And the result of that might be one extra character appearing in a text box.
I have one UI that basically shows a table of data from a SerializedObject. It’s pretty simple stuff. Alas, when imeplemented the way the docs say, after there are more than a few dozen rows it gets to the point where I can type faster than the input can be handled.
I’ve only said bad things, so it sounds like I’m really sour on it.
For the most part it’s a nice and quick way that I can throw simple custom inetrfaces together, and in that regard it works pretty well. It’s only when things get complicated that it runs into issues. And some of those issues I could probably overcome by not using the *GUILayout classes, because they (reasonably enough) come with a bunch of assumptions.
Immediate mode GUI is a great way for making relatively useable UI very quickly, with very little code. Unity’s implementation does just that, but it’s
very hard to make it look good
very poorly performing
very, very buggy
has a poorly designed API full of inconsistencies and holes.
It’s very good for adding a few buttons to an editor UI in a situation where it’s fine that it looks just like any other Unity editor control. An alternative is needed when you either need to make something that looks good, are doing something complicated, or have very much data to edit.
So getting rid of it for in-game uses isn’t a big deal, since if we want to make any UI that looks decent, it’s a no-go. It allows Unity to strip out some code from the engine, which speeds things up for us (and for their iteration speed).
It’s going to stay there in the editor, which is good - while UI Toolkit gives better results, it takes longer to get things done, and you often don’t need that good results when what you’re doing is adding a readout of some data or a button that does a debug thing.
UGUI can go die in a fire, it should never have been shipped, it’s never been production ready, God it’s so bad.
To MaKe A tExTbOx FiT iTs CoNtEnT, FiRsT aDd A HoRiZoNtAlLaYoUtGrOuP.
???
foreach(var item in items) {
EditorGUILayout.LabelField(item.name);
}
I don’t think you can be performant at scale - at least by default - with any imgui approach.
Say you’re drawing some thousands of elements in a list with a scroll view. In an immediate approach, you don’t know anything upfront about how many elements there are, or how large they are, so you have to (by default) run the code for every element every time you want to update anything on the screen.
So what you end up having to do is for the developer to manually roll their own thing to handle that performance issue, or some other workaround.
In a retain mode you by definition have the elements and their sizes upfront, so culling the list ends up being based on data you already have.
But for the other things, yeah. GUIStyle could’ve been good, the API could have been well designed, and the bugs could have not been there.
Example, still pretty trivial UI but its a pain to read, this is a real world example of a editro tool we have made for our game. Code is not perfect, just quick made for use in editor
GUILayout.BeginHorizontal("box");
if (session.Instance)
if (GUILayout.Button("Revert"))
{
PrefabUtility.RevertPrefabInstance(session.Instance.gameObject);
}
if (session.Instance)
if (GUILayout.Button("Apply"))
{
ApplyPrefab(session.Instance);
}
if (GUILayout.Button("Refresh session"))
{
RefreshSession();
Next(0);
}
if (GUILayout.Button("Toggle hands"))
{
HandIKRigger.ToggleHandConfig();
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal("box");
if (GUILayout.Button("Prev. rigg"))
{
Next(-1);
}
if (GUILayout.Button("Next rigg"))
{
Next(1);
}
if (Selection.gameObjects.Length != 0)
if (GUILayout.Button("Highlighted as secondary"))
{
SetupSecondary();
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal("box");
if (session.Rigg)
if (GUILayout.Button("Highlight rigg"))
{
Selection.objects = new[] {session.Rigg.gameObject};
}
if (session.Item && Selection.gameObjects.Length != 0 && GetEndTrigger())
if (GUILayout.Button("Copy trigger to end point"))
{
CopyTriggerStart();
}
GUILayout.EndHorizontal();
if (HasRigError())
{
GUILayout.BeginHorizontal("box");
if (GUILayout.Button("Correct finger tip rotation errors"))
{
var errors = new List<Transform>();
GetErrorBones(session.Rigg, errors);
foreach (var error in errors)
{
error.localEulerAngles = new Vector3(0, 0, error.localEulerAngles.z);
}
}
if (GUILayout.Button("Highlight finger tip rotation errors"))
{
var errors = new List<Transform>();
GetErrorBones(session.Rigg, errors);
Selection.objects = errors.Select(t => t.gameObject).ToArray();
}
GUILayout.EndHorizontal();
}
var prefab = EditorGUILayout.ObjectField("Jump to", null, typeof(Transform), true) as Transform;
if (prefab)
{
Jump(prefab);
}
var template = EditorGUILayout.ObjectField ("Rig from", null, typeof(Transform), true) as Transform;
if(template)
{
CopyRig (template);
}
if (Selection.gameObjects.Length != 0)
{
EditorGUILayout.LabelField("Selected transform");
var trans = Selection.gameObjects[0].transform;
var pos = EditorGUILayout.Vector3Field("Position", trans.transform.localPosition);
if (trans.localPosition != pos)
{
trans.localPosition = pos;
}
var rot = EditorGUILayout.Vector3Field("Rotation", trans.transform.localEulerAngles);
if (trans.localEulerAngles != rot)
{
trans.localEulerAngles = rot;
}
var scale = EditorGUILayout.Vector3Field("Scale", trans.transform.localScale);
if (trans.localScale != scale)
{
trans.localScale = scale;
}
}
, by convention if a button is bound to method HighlightAsSecondary a property bool CanHighlightAsSecondary can be used to determin if button can be pressed, etc. Works very well for Caliburn Micro in WPF