Search Unity

Object oriented GUI

Discussion in 'Immediate Mode GUI (IMGUI)' started by CHPedersen, Mar 14, 2011.

  1. CHPedersen

    CHPedersen

    Joined:
    Mar 2, 2011
    Posts:
    63
    Dear all,

    This is not a bug report or anything, just my being curious about how the community feels about this, and whether others share my opinion. :)

    I'm relatively new to Unity and have just spent a little while designing my first GUI in it, and have some comments. I'm not new to programming in general, and I find that the way one has to use the static functions in the GUI namespace to declare GUI elements sort of breaks the object oriented paradigm today's programmers are taught to follow. Many programmers new to Unity have backgrounds in Winforms, XAML/WPF or even Java Swing, all of which are object oriented GUI systems. I feel that Unity's GUI system forces users into a more scripting-style approach which has a tendency to very quickly result in verbose, cluttered code with lots of conditionals for button clicks and variables for storing the output of textfields, etc.

    I'm struggling a little to find a way to keep things organized. I've decided to make my GUI class a partial class (I'm a C# programmer) so that I can separate code with clearly different behavior into different files without having to pass 10s of variables back and forth as method parameters, but I still get that unmistakable 'feeling' that I'm writing bad code. It's setting off my "code-smell"-detector, and I sorely miss C#'s usual event-driven GUI controls.

    So, what are your experiences? What do you do to minimize clutter? And if you're a Unity employee, are there any plans for something more object oriented in the future?
     
  2. KnifeFightBob

    KnifeFightBob

    Joined:
    Jan 22, 2009
    Posts:
    196
    First of a short disclaimer. Most of my heavier programming is restricted to Unity C# so I haven't done any normal platform programming except some Objective C. So, onwards.

    The GUI issue is pretty flamed already, and it seems Unity Tech are working with something, if I'm not entirely incorrect. No time has been given, mind you, for any updates on this.
    Personally I break the GUI system down into an enum with states and fire specific GUI actions (like displaying a menu or window complete with all it needs) via calling menu states. I've seen some more nicely-written things, but I usually revert to the enum version. That way I can always take all that ugly code out of my way when I need it and stuff it in another script if need be

    Regardless of specific method, the fact then remains that most everything that has to do with Unity GUI today is going to end up as ugly code.

    I'd love seeing something like the @synthesize and Interface Builder stuff in a coming Unity version.

    My two cents, hope they are worth something.
     
  3. appels

    appels

    Joined:
    Jun 25, 2010
    Posts:
    2,687
    An event-driven GUI would be awesome in Unity, they have started working on a visual design system fort the gui but they won't change how it's working i think.
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    They said they're working on a new GUI system; there hasn't been any mention of a visual design system for the current GUI that I know of.

    --Eric
     
  5. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    I suspect/I] the Unity GUI stuff is more stack based than OO based, and that is why it feels weird. Sorta feels like Apple's way of doing things in Objective-C in that way.

    Anyway, it is possible to wrap it to make it somewhat less cluttered, there are examples this forum (self promotion here)
    and also look around for 3rd party GUI managers like EZGUI and ColdGUI.
     
    Last edited: Mar 15, 2011
  6. CHPedersen

    CHPedersen

    Joined:
    Mar 2, 2011
    Posts:
    63
    That's actually precisely what I have. My GUI enum is kept in a static class called Config, so I can access them from anywhere, and the main GUI script simply switches over them. That approach was fine up until the point where I needed to code a menu with behavior similar to an installation wizard, that is to say, it has buttons for "next" and "backwards" that're supposed to return the user to previous windows if it turns out he needs to edit data entered there.

    This requirement introduces the need for window memory - I have to start keeping track of where the user just came from, so that the "Back"-button can return him to it if need be. In an object-oriented setting, this is most elegantly accomplished by storing window objects in a linked list; that data structure has build-in pointers to predecessor and successor elements. With the static GUI class unity has, however, it isn't possible without extensive seperate code for mapping the history of the states. And that's not very elegant.

    I'm super-happy to know the Unity folks are working on a different GUI system, however. :) The one they have right now isn't terrible, mind you... It's leagues ahead of what I've seen in other graphics systems. For instance, Microsoft didn't even bother to include a mainstream one with XNA. If you want a GUI there, you have to turn to 3rd party tools, and C++/OpenGL is even worse (C++ doesn't have events, further complicating GUI coding).
    I thoroughly appreciate Unity's idea of adopting a CSS-based mindset for controlling the skins/styles of a GUI, that harmonizes really well with my idea of elegance. :) I just hope they make a future version OO and event driven.
     
  7. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    I agree, the current GUI system is kind of a pain in the ass. One of it's advantages is clearly that it's pretty easy and quick to setup a button or two in your game and have them do some functions. However, everything that's more complex than that, makes the code pretty messy and hard to work with, especially if you need some kind of "modal dialog", which should make the buttons in the background of that new window unclickable/disabled, it's very hard to archive and manage this correctly with GUI.enabled = true/false, because for it to work one would have to write a complete system which manages all GUIs and windows and at any point in time know which dialog or button lies below another one to set the GUI.enable correctly.

    Something like Winforms would be great, where you can write your GUI code on one place and use delegates to subscribe to certain events to trigger functions such as click/mouseover etc. While it requires bit more of typing, it's clearly easier to manage and work with and much more flexible.

    I really have huge problems when I try to accomplish pretty easy things, like assign a different look/backgroundtexture or color to a button, when trying to do it with the current GUI System, as there is no easy way of having one button look change dynamically without creating multiple Skins or Styles. In my last game I was working on, I've created a skin for the UI and had to add new custom skins for each button I wanted to be designed differently (i.e. different color or button textures).
     
    Last edited: Mar 16, 2011
  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You don't need skins for each button, just different GUIStyles.

    --Eric
     
  9. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    Damn, you got me again. I should reread my posts before sending them.

    Yea, i actually mean the "custom style" within the skin, so I don't have to create additional assets. But it's a pain too, that for every little change you'd have to create an extra style and have additional management (and creating new constant to hold the index of that custom style). It's quite annoying when you only need a single attribute changed (font, color) but have to add a whole new style
     
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    That's true, though there is GUI.color (also .backgroundColor and .contentColor).

    --Eric
     
  11. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    Hi. I have no formal CS training so this seems a long shot but anyway...
    Do you guys really believe that object oriented programming is well suited on games like it is well suited on other projects ?
    I mean, one of the important factors in game programming is perfomance. I doubt the fact that perfomant games are written following the oo paradigm. Also, I doubt the fact that because oo programming is what people learn at universities, this makes it the holy grail of programming.
    This presentation (pdf link) demonstrates some reasons why oo is not so perfomant and how a more data - centric approach can prove more efficient. I don't suppose that no game can be written with oo. I suppose that no perfomant game can be written following the oo paradigm.
    As far I understand it, oo paradigm places objects in the central role, while Data Oriented Design programming places data.
    A funnier approach
    What is your opinion on this?
     
    Last edited: Mar 18, 2011
  12. KnifeFightBob

    KnifeFightBob

    Joined:
    Jan 22, 2009
    Posts:
    196
    Regardless of the current dogma I think general consensus is that the current GUI system is bad because of:
    1) Code easily becomes cluttered and thus hard to maintain
    2) Has extremely slow performance, especially on mobile platforms
    3) May be an off-shoot: Is (any many regards) difficult to "port" between platforms, at least I think so.

    I'd love seeing a rewrite for 3.4 or 3.5 together with 64-bit support. That would totally make my year, although that may not happen so soon.
     
  13. CHPedersen

    CHPedersen

    Joined:
    Mar 2, 2011
    Posts:
    63
    Yes, insofar as Unity is concerned. See further explanation below. :)

    It's true that OO shouldn't be considered the holy grail just for being heavily taught at universities. Actually, I don't think anything scientific should ever be considered a "holy grail". It's a bad idea to lull oneself into the belief that there won't, ever, be something better. Data oriented design might certainly benefit you in some stages of game programming because of its memory effeciency, but to suggest we completely replace OO by it is probably to overshoot the goal a little, at least initially. You see, you're sort of trying to improve in the wrong place - if you're that concerned about performance, you shouldn't be using Unity in the first place. I love Unity for its simplicity and for providing levels of abstraction around the more cumbersome areas of game programming, such as its associated math, but when you introduce levels of abstraction, you do so at the expense of performance. That's how it's always been. For starters, Unity is based on the opensource Mono implementation of .Net, which is JIT-compiled. As is stated on their own support site, (http://unity3d.com/support/documentation/ScriptReference/index.Script_compilation_28Advanced29.html) this in itself is about 50% slower than native C++ code.

    The point in Unity is not to provide the fastest programming framework in the world, it is to keep game programming user friendly. While OO might not necessarily be the fastest approach, it appears to be the more intuitive and thus, the more user friendly. Unity, as I see it, is for small scale, hobby/freelance/minor business productions. Not for major titles in extremely performance critical environments - they're made by major corporations who almost exclusively use C/C++.

    Besides, this suggestion is for an OO GUI framework. A GUI is composed of event driven 2D-stuff and doesn't need heavy calculations every frame. The performance hit we'd take by following an OO approach isn't going to be noticeable anyway.
     
  14. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    Thanks for the reply ! I write this post hoping that my view in programming will clarify more through discussion, not trying to convince you or anyone that my view is the only right view. "Dogma", at least in Greek, also has a seed of inflexibility in its meaning, but I do not "believe" in data oriented programming.
    I wish to develop perfomant games using Unity. I accept the perfomance trade-off for using Unity engine. I try to find a way to not add further decrease in perfomance using paradigms that further degrade it. The way memory is handled (or mishandled) can degrade seriously perfomance and is easily overlooked. Creating a List of 1000 objects vs creating 1000 objects makes a big difference in perfomance. A "shallow" inheritance model plus components is prefered vs "deep" inheritance. Delegates etc cost many CPU cycles. Those things become particularly evident in Update () and in mobile platforms.
    Well, this is why I responded :) I think the suggestion is wrong so I answered :) I think that in order to have a fast and responsive GUI we should not ask delegates, events deep object hierarchies etc.
    I am looking forward for your point of view.
     
  15. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    If you want to do performant OnGUI alike working with MVC model, then you might want to give GUIX a look

    For a gui without ongui and not the full set, EZGUI can be a good option as it is even based and works performantly on all platforms as it works with raw 3d, no UI functionality (which all do not batch)
     
  16. CHPedersen

    CHPedersen

    Joined:
    Mar 2, 2011
    Posts:
    63
    Ah, that's certainly true. Thanks a lot for bringing up data oriented design, by the way! It's a topic that isn't given the attention it deserves, and it's refreshing to have people like yourself be skeptical and make the rest of us think twice every once in a while. :) As I've understood it, a data-oriented design seeks to minimize memory reads and cache misses by focusing on keeping things sequential in memory, right? There's a post in a thread on Stack Overload, (http://stackoverflow.com/questions/1641580/what-is-data-oriented-design) that explains this very well using an example. It's possible an approach such as this might be beneficial in a lot of aspects, but once again, I'm not sure I agree with you about how it applies to this discussion.

    You see, the Unity GUI is already object-oriented. It's just OO in a really poor way. Take this example from the Unity documentation on GUI.Button:

    Code (csharp):
    1. if (GUI.Button(new Rect(10, 10, 50, 50), btnTexture))
    2. Debug.Log("Clicked the button with an image");
    That's the standard way of doing a button right now. This goes in OnGui, which gets called every time there's a Gui-event, which means possibly several times per frame, but at least once per frame, right? (Since redrawing the Gui elements is a Gui event). The button location and size are declared with a Rect object which is instantiated with the new operator on every single OnGui. This means you're basically asking the runtime system to allocate memory for a new (identical, in this case) Rect-object at least once every single frame, and since .Net is a managed framework, you're also asking the garbage collector to come destroy your identical Rect-objects when they go out of scope at the end of every single call to OnGui. From a memory standpoint, this is very, very silly. In addition to this, we must also consider the boolean value GUI.Button returns. It indicates whether the button was just clicked or not, so evidently, there's some hit-detection against the mouse pointer and left button going on inside the GUI.Button method. Since you have to check this bool on every call to OnGui in order to react to the click, you're basically asking, "Was the button clicked now? Was the button clicked now? No? How about now, then? Now?" continually, over and over again. This is similar to the criticism the Sony-article you linked to directed against the polling of a dirty-flag. Why would a time-critical application waste time continually polling a boolean when it doesn't have to?

    Well... Delegates and events solve precisely the problem described above. They may cost more CPU cycles when they occur than the polling of a boolean, but at least they occur only once - when the button is clicked, which is when you need it. One could also argue that the constant instantiation of Rect objects could be solved by creating a global Rect outside the scope of OnGui, and then pass that to GUI.Button instead. That would also be true, but then you're pretty much doing what I was originally suggesting - If one creates an object to represent the size and position of a button, one might as well create an object to represent the button...
     
  17. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    Thanks for the replies. I have some more thoughts that I would like to share and I would love to see your opinions.

    1. The input. User input is continuous as long game lasts. The amount of info per frame is small (bools for key/button press, int's for mouse / touch position) but continuous. There is no needth for long term persistance of this data. A small buffer can accumulate user input as a queue, first in first out (fifo) and replacement over time. This functionality is already implemented via Input runtime classes.

    2. The output. Game parameters change. User gets notified with sound / animation that a change took place.

    3. The processing of the data. Calling static methods.

    What player sees is lines, graphics and text.
    Vectrosity lines, custom textured quads, 3d text = lines, graphics and text.
    They are well handled from the engine, no needth to create / destroy, create at the beggining, place in a pool, use when needed. Animation, audio runtime classes are available. Modify existing vector lines, meshes, text meshes and let them persist at level changes
    = no object creation / destruction
    = no data fragmentation or unnecessary calls to garbage collector.
    So the new elements that are added are low polygon geometry, cheap (performance-wise) shaders and textures. Pack the textures in an atlas, create some quads and some lines in two pools ( arrays ? ). Data is packed continuously in memory and overhead is minimized.
    What else should one need to make a game gui ? What benefit could an object oriented approach bring ?
    This is not a rhetorical question. I will try to make a GUI soon for my game and I really wonder if I miss something. I have no experience and I don't wish to spend months doing things wrong. Feedback is really appreciated.

    One more thing. In c #, if you try to create a Monobehaviour as new Monobehaviour you get a warning. You should only add components. This and that makes me think that maybe unity engine might have some data oriented design in its guts. This is not relevant indeed :)
    Or is it ?
    And could this be related to its performance ?

    I would love to see your opinions. And I would really like to listen what am I missing by not adopting oo in my design.
     
    Last edited: Mar 24, 2011
  18. justinlloyd

    justinlloyd

    Joined:
    Aug 5, 2010
    Posts:
    1,680
    Rects are a value type. Moving the rect delcaration and setup out of the OnGUI handler would be considered a questionable micro-optimisation at best in the overall scheme of things. The cleanup of scoped value types when they go out of scope does not involve the GC.

    It would be, if that was what was happening, but it isn't.

    Sooo.... basically exactly how an event driven system does it. The only difference between Unity's GUI system and WinForms is that Unity's philosophy sort of expects you to stick your response code in the OnGUI (which is bad design) whereas WinForms will raise an event that you can respond to. That said, I see a lot of WinForms developers sticking their "do work" code directly in the event handler too, which is also a bad practice. Separation of concerns, MVC/MVP and all that, etc, etc.

    The only optimisation on the polling system is to run the mouse to input object collision detection at a different Hertz than the game, which is a reasonable optimisation when the game is running at a higher refresh rate than a user can perceive the response delay. Mouse button click detection on user interface objects between 10 Hz and 20 Hz is usually acceptable. Mouse button detection on an FPS is needs to be around 30 Hz to 120 Hz. Joystick response, depending on the game, usually needs 30 Hz for average "non-very-twitchy" games, and 120 Hz or 240 Hz for fighting games, though some very twitchy fighting games respond at even higher cycles.


    Which basically, every "frame", do the exact same thing as the polling method but only raise the event when a hit is detected. This is basic and understood as "current good practice" for anything like a GUI system. No "do work" should be placed in the GUI rendering and hit detection handler(s). When a user interaction is detected; mouse enter, mouse exit, mouse move, mouse click, mouse down, mouse up, mouse drag, then an event is fired to indicate what happened. You can add a filtering system so that common events, e.g. mouse move, do not fire more than a set rate per second.

    Other than the commonly known issue of draw performance with the Unity GUI, Unity managed to meld the draw, detection and "do" code in to a single handler, which frankly is a colossal paradigm F***-up on Unity's part but is also reasonably trivial to fix from a development point of view. I do not expect the same paradigm to be in place when the new Unity GUI sub-system is rolled out.
     
    Last edited: May 13, 2012
  19. dkozar

    dkozar

    Joined:
    Nov 30, 2009
    Posts:
    1,410
  20. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Ippokratis, I'm sorry, I just can't read that without responding...
    Writing everything in OO might be technically slower than other ways of doing it... but OO does result in "prettier" code ;) and the performance difference is going to be on such a small level I guarantee you won't be able to notice the difference. And as for the JIT / C# stuff... the differences between how .NET / Mono and how C++ are compiled would have made a huge performance difference years ago when computers were much slower, but these days again computers are so fast the speed of code execution isn't really an issue anymore (if it is, your computer is a dinosaur, no offense). Of course, to keep your game speedy you do have to optimize your code (basically, don't create new object instances every frame, that is going to trigger the GC), but this should come as no surprise, and in general it's much easier to optimize C# than it is to optimize C++ (there's something a programmer friend told me once, "in C++ it's harder to shoot yourself in the foot, but when you do you blow your entire leg off")
     
  21. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    And, by the way, some of the most well-known games use OO extensively. Crysis does. Unreal does (or at least most of it does). So do all Valve games. I know this because I've seen some source code. You think that slows them down? Sure as hell doesn't.
    You also don't seem to know what a delegate really is. Delegates are quite fast, and in a GUI situation they WILL NOT slow down your code. Essentially a delegate is a function pointer, and evaluating a delegate upon a button click, for example, is not going to be noticeable at all, at least not due to using a delegate instead of directly calling a function (whether the function itself is slow is another question, and has nothing to do with OO).
     
  22. dkozar

    dkozar

    Joined:
    Nov 30, 2009
    Posts:
    1,410
    I would agree.. Mouse clicks etc are "rare" events, so can't slow down anything. Benefits of decoupling with using event handlers are much much greater than performance losses.
     
  23. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    Hi,
    I had some discussions over #unity about this subject, where some nice people explained me this stuff, but I did not updated my points of view above. Of course you are right, both of you. Thanks for getting in trouble to answer.
    Kind regards,
    -Ippokratis
     
  24. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Yeah, besides being used for GUI, here's an example of the difference between using delegates and using straight functions.
    This code measures the length of time my test function takes to complete (6ms)
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class DelegatePerformance : MonoBehaviour
    6. {
    7.     public delegate void TestDelegate();
    8.  
    9.     void Start()
    10.     {
    11.         //TestDelegate del = new TestDelegate( TestFunction );
    12.         System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
    13.         watch.Start();
    14.         //del();
    15.         TestFunction();
    16.         watch.Stop();
    17.         Debug.Log( "Elapsed time: " + watch.ElapsedMilliseconds + "ms" );
    18.     }
    19.  
    20.     void TestFunction()
    21.     {
    22.         int x = 0;
    23.         for( int i = 0; i < 100; i++ )
    24.         {
    25.             x += 5;
    26.         }
    27.         Debug.Log( x );
    28.     }
    29. }
    30.  
    and this measures how long it takes to execute a delegate of that same function (it takes the same amount of time, 6ms on my machine)
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class DelegatePerformance : MonoBehaviour
    6. {
    7.     public delegate void TestDelegate();
    8.  
    9.     void Start()
    10.     {
    11.         TestDelegate del = new TestDelegate( TestFunction );
    12.         System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
    13.         watch.Start();
    14.         del();
    15.         watch.Stop();
    16.         Debug.Log( "Elapsed time: " + watch.ElapsedMilliseconds + "ms" );
    17.     }
    18.  
    19.     void TestFunction()
    20.     {
    21.         int x = 0;
    22.         for( int i = 0; i < 100; i++ )
    23.         {
    24.             x += 5;
    25.         }
    26.         Debug.Log( x );
    27.     }
    28. }
    29.  
    So, delegates themselves are in fact not any slower than just calling the function itself, but they are more flexible because now you can assign any function to be called, which is commonly used to subscribe to events (obviously)
     
  25. dkozar

    dkozar

    Joined:
    Nov 30, 2009
    Posts:
    1,410
    C'mon guys, it's 2012, and we are talking about OOP and performance :)

    There's a thing in programming called "Free lunch" - performance doubles every 1.5 years, meaning all your programs are 2 times faster every 1.5 years. That's what you get for free. So while we are talking, (non-existing) performance problems are solving by itself.. :)
     
  26. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Exactly. OOP these days will not slow your code by itself. Neither will JIT (JIT turns the virtual byte code into raw machine code, so it's actually directly executed on the CPU like any other machine code, unlike Java which - shudder - I'm not even going there). It's how you use it that affects the performance. If you do it right, you can get some fantastic performance out of a managed and OO engine like Unity ;)
     
  27. dkozar

    dkozar

    Joined:
    Nov 30, 2009
    Posts:
    1,410
    The immediate GUI kept screaming "I want the OOP wrapper!" since the first time I saw it :)

    Back to the first question on structuring things: since the immediate GUI has controls and containers (clippable and scrollable areas), it is somehow natural to extend it using the the composite pattern (google it). In essence:

    Code (csharp):
    1. public class Component{
    2.     public List<Component> Children {get;}
    3. }
     
  28. dkozar

    dkozar

    Joined:
    Nov 30, 2009
    Posts:
    1,410
    This dilemma reminds me of a team that I've been working for where the owner heard from a good friend that EntityFramework and similar stuff is there only for developers who don't know SQL and is terribly slow. Perhaps it is noticeable on few hard-core queries, but we ended up converting 100% of the DAL to stored procedures, event those of the "Insert new user" kind. :)

    The business of us engineers is to measure things and to make decisions based on a good reasoning.. most of the time in grey zones.. OOP versus raw immediate really isn't the angle we should worry about.