In this use-case, you will see the difference between GUI and UI API. And why use the later in your game, for constancy between platforms and API long term support.
A lot of tutorials and feedbacks on Internet show code using GUI API. But it not a good approach to Unity3D.
Here si the official Unity3D documentation: “The IMGUI system is not generally intended to be used for normal in-game user interfaces … For that you should use Unity’s main GameObject-based UI system“.
https://docs.unity3d.com/Manual/GUIScriptingGuide.html
Steps
- GUI Example
- UI Example
- Pros / Cons
- Project Code
- Demos
GUI Example
The GUI is the fastest way to build UI, like on other platforms like webpage (HTML/JS/CSS), or Android (Java). But it’s not intended to be use in game code. It’s just for testing en Unity Editor.
https://docs.unity3d.com/Manual/GUIScriptingGuide.html
- Pros
- Productive (simple)
- Maintainable (less code, params)
- Cons
- GUI is deprecated since Unity3D 5.x!!!
- Limited (don’t work properly on other plateforme than Windows)
- coordinates start at top/left (like webpage/android, are absolute in pixel)
UI Example
Unity3d.UI is the actual UI API. It’s complex, but fully customizable. But there is no convention or default behavior (like size, colors, textures).
https://docs.unity3d.com/Manual/HOWTO-UIMultiResolution.html
- Pros
- relative position (to parent object)
- consistancy, responsive (same UI between plateformes)
- Cons
- Need an Event system (EventManager)
- very verbose (like WPF, GWT, or SWING)
- complex (you need lot of Canvas, GameObjects)
- coordinates start at bot/left
Project Code
You can download or code this example project.
- create empty 2D project
- create a Startup.cs script for the Unity3D editor to add Script to scene automatically.
- create three examples
- run it on windows
- run it on mobile
- compare the result
https://github.com/DamienFremont/blog/tree/master/20170602-unity3d-use-ui-instead-of-gui-or-imgui/
Assets/Startup.cs
using UnityEngine; using UnityEditor; // http://docs.unity3d.com/Manual/RunningEditorCodeOnLaunch.html [InitializeOnLoad] public class Startup { static Startup () { GameObject gameObject; gameObject = GameObject.Find("Main Camera"); Component script1 = gameObject.GetComponent<GUIExample>(); if (script1 == null) { gameObject.AddComponent<GUIExample> (); } Component script2 = gameObject.GetComponent<UIExample>(); if (script2 == null) { gameObject.AddComponent<UIExample> (); } } }
https://docs.unity3d.com/ScriptReference/GameObject.Find.html
Assets/Scripts/GUIExample.cs
using System; using UnityEngine; // https://docs.unity3d.com/Manual/GUIScriptingGuide.html public class GUIExample : MonoBehaviour { // Use this for initialization void OnGUI () { Rect rect = new Rect (10, 10, 100, 100); Texture2D tex = new Texture2D (1, 1); tex.SetPixels(new Color[]{Color.grey}); GUIStyle style = new GUIStyle (); style.normal.background = tex; // https://docs.unity3d.com/ScriptReference/GUILayout.BeginArea.html GUILayout.BeginArea (rect, tex, style); if (GUILayout.Button ("Click me")) action (); if (GUILayout.Button ("Or me")) action (); GUILayout.EndArea (); } private void action () { Debug.Log ("Hello!"); } }
Assets/Scripts/UIExample.cs
using System; using UnityEngine; using UnityEngine.UI; using UnityEngine.Events; using UnityEngine.EventSystems; public class UIExample : MonoBehaviour { // Use this for initialization void Start () { Rect rect = new Rect (0, 0, 100, 100); Texture2D tex = new Texture2D (1, 1); tex.SetPixels(new Color[]{Color.blue}); CreateEventSystem (this.transform); GameObject a = area (this.transform, rect, tex); GameObject b1 = button (a.transform, new Vector2(0,12), "Click me", delegate { TaskOnClick(); }); GameObject b2 = button (a.transform, new Vector2(0,-12), "Or me", delegate { TaskOnClick(); }); } public void TaskOnClick () { Debug.Log ("Hello!"); } // BOILER PLATE BELLOW... GameObject area (Transform parent, Rect rect, Texture2D tex) { // OBJECT GameObject canObj = new GameObject ("UI:Canvas"); canObj.transform.SetParent (parent); // OBJECT:CANVAS // http://docs.unity3d.com/Manual/UICanvas.html Canvas can = canObj.AddComponent<Canvas> (); can.renderMode = RenderMode.ScreenSpaceOverlay; can.pixelPerfect = true; // OBJECT:CANVAS:SCALER // http://docs.unity3d.com/ScriptReference/UI.CanvasScaler.html CanvasScaler canObjSca = canObj.AddComponent<CanvasScaler> (); canObjSca.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; canObjSca.referenceResolution = new Vector2(540, 480); // OBJECT:CANVAS:RAYCASTER // https://docs.unity3d.com/Manual/script-GraphicRaycaster.html GraphicRaycaster canvasRayc = canObj.AddComponent<GraphicRaycaster> (); // OBJECT:CANVAS:PANEL GameObject panObj = new GameObject ("UI:Panel"); panObj.transform.SetParent (canObj.transform); // https://docs.unity3d.com/Manual/UIBasicLayout.html RectTransform panTrs = panObj.AddComponent<RectTransform> (); panTrs.anchoredPosition = new Vector2 (rect.x, rect.y); panTrs.localScale = new Vector3 (1.0f, 1.0f, 1.0f); // SetSize(panTrs, new Vector2(rect.width, rect.height)); // OBJECT:CANVAS:PANEL:TEXTURE Image img = panObj.AddComponent<Image> (); img.sprite = Sprite.Create (tex, new Rect (0, 0, tex.width, tex.height), new Vector2 (1.0f, 1.0f)); return canObj; } GameObject button (Transform parent, Vector2 coord, string textStr, UnityAction eventListner) { Vector2 size = new Vector2 (90, 25); // OBJECT GameObject btnObj = new GameObject ("UI:Button"); btnObj.transform.SetParent (parent); RectTransform btnTrs = btnObj.AddComponent<RectTransform> (); btnTrs.anchoredPosition = coord; btnTrs.localScale = new Vector3 (1.0f, 1.0f, 1.0f); SetSize(btnTrs, size); // OBJECT:CANVAS:TEXTURE // http://docs.unity3d.com/ScriptReference/Sprite.Create.html Image img = btnObj.AddComponent<Image> (); Texture2D tex = Resources.Load<Texture2D> ("button_bkg"); img.type = Image.Type.Sliced; img.sprite = Sprite.Create (tex, new Rect (0, 0, tex.width, tex.height), new Vector2 (0.5f, 0.5f), 100.0f, 0, SpriteMeshType.Tight, new Vector4 (10, 10, 10, 10)); // OBJECT:BUTTON // https://docs.unity3d.com/ScriptReference/UI.Button-onClick.html Button btn = btnObj.AddComponent<Button> (); btn.interactable = true; btn.onClick.AddListener (eventListner); // https://docs.unity3d.com/ScriptReference/UI.Selectable-transition.html btn.targetGraphic = img; btn.transition = Selectable.Transition.ColorTint; // OBJECT:TEXT // https://docs.unity3d.com/ScriptReference/UI.Text.html GameObject btnTxtObj = new GameObject ("UI:Text"); btnTxtObj.transform.SetParent (btnObj.transform); RectTransform btnTxtTrs = btnTxtObj.AddComponent<RectTransform> (); btnTxtTrs.anchoredPosition = new Vector2(0,0); // SetSize(btnTxtTrs, size); Text txt = btnTxtObj.AddComponent<Text> (); txt.supportRichText = true; txt.text = textStr; txt.fontSize = 12; txt.font = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font; txt.alignment = TextAnchor.MiddleCenter; txt.horizontalOverflow = HorizontalWrapMode.Overflow; txt.color = Color.black; return btnObj; } public static void SetSize (RectTransform trans, Vector2 size) { Vector2 currSize = trans.rect.size; Vector2 sizeDiff = size - currSize; trans.offsetMin = trans.offsetMin - new Vector2 (sizeDiff.x * trans.pivot.x, sizeDiff.y * trans.pivot.y); trans.offsetMax = trans.offsetMax + new Vector2 (sizeDiff.x * (1.0f - trans.pivot.x), sizeDiff.y * (1.0f - trans.pivot.y)); } public static GameObject CreateEventSystem (Transform parent) { // https://docs.unity3d.com/Manual/EventSystem.html GameObject esObj = new GameObject ("EventSystem"); esObj.transform.SetParent (parent); EventSystem esClz = esObj.AddComponent<EventSystem> (); esClz.sendNavigationEvents = true; esClz.pixelDragThreshold = 5; StandaloneInputModule stdIn = esObj.AddComponent<StandaloneInputModule> (); stdIn.horizontalAxis = "Horizontal"; stdIn.verticalAxis = "Vertical"; TouchInputModule touchIn = esObj.AddComponent<TouchInputModule> (); return esObj; } }
Demo
In this demo, we will test the two API side by side.
- on UnityEditor Preview
- test onClick action
- test responsive
- in low and high screen resolution
- in portrait and landscape orientation
- on Android Mobile Device
Source
https://github.com/DamienFremont/blog/tree/master/20170602-unity3d-use-ui-instead-of-gui-or-imgui/
References
https://unity3d.com/fr/learn/tutorials/topics/user-interface-ui