OnGUI方法应用与生命周期

编程入门 行业动态 更新时间:2024-10-26 22:17:33

OnGUI方法应用与<a href=https://www.elefans.com/category/jswz/34/1766643.html style=生命周期"/>

OnGUI方法应用与生命周期

 Why

主要用来创建调试工具、创建自定义属性面板、创建新的Editor窗口和工具达到扩展编辑器效果。

OnGUI不建议使用在项目UI中。因为效率的问题现在已经很少使用了,但在Editor脚本中,如果你需要扩展一下Unity编辑器的功能,那掌握该GUI的编写还是非常必要的。

官方给出了三种该UI的用途:

1.游戏中Debug时需要显示一些简单的UI;

2.给Component脚本创建一个自定义的Inspector;

3.创建一个Editor Window,扩展Unity本身。

 

有时候想要输出一些数据到屏幕上方便查看,新建一个UI对象又挺麻烦,用OnGUI()在屏幕上直接绘制UI比较方便。

GUI.Label(new Rect(100, 100, 200, 80), “aaa", style);

这条语句在屏幕中绘制了一个Label,第一个参数给出了位置和大小,第二个参数是要显示的内容,第三个参数可以省略,是所绘制Label的样式。

GUI.Label(new Rect(100, 100, 200, 80),"<color=#00ff00><size=30>"+"aaa"+"</size></color>", style);  

在要显示的内容前后加上标签同样也是支持的,但只支持color,size,b和i。

完整代码如下:

    private void OnGUI(){GUIStyle style = new GUIStyle{border = new RectOffset(10, 10, 10, 10),fontSize = 50,fontStyle = FontStyle.BoldAndItalic,};// normal:Rendering settings for when the component is displayed normally.style.normal.textColor = new Color(200/255f, 180/255f, 150/255f);    // 需要除以255,因为范围是0-1GUI.Label(new Rect(100, 100, 200, 80), “aaa", style);GUI.Label(new Rect(Screen.width - 100, Screen.height - 100, 200, 80),"<color=#00ff00><size=30>"+"aaa"+"</size></color>", style);    // 支持标记语言(什么富文本?// 只支持color,size,b,i}

OnGUI()函数生命周期

OnGUI()函数是每帧执行一次吗

Update()和OnGUI()有什么区别?

OnGUI() 会在渲染和处理GUI时间时调用,

简单理解就是分线程执行,执行先后顺序是:Awake线程->Start线程->FixedUpdate线程->Update线程->LateUpdate线程->OnGUI线程.
(注意:OnGUI 可以每帧调用多次,小心使用 , )

 



可以做個實驗:

public class GuiTest : MonoBehaviour
{
        private int gui_counter = 0;
        private int update_counter = 0;

        void OnGUI()
        {
                gui_counter++;
                Debug.Log ("OnGUI.." + gui_counter + "," + update_counter);
        }

        void Update()
        {
                update_counter++;
                Debug.Log ("Update.." + gui_counter + "," + update_counter);
        }
}

就可以發現,OnGUI 雖然會不斷被調用,但是並不是每一幀調用一次,而是會調用多次,這是因為有多次GUI Event的原因。

你操作越多次產生GUI Event 有關的行為(例如在屏幕上操作滑鼠),OnGUI 就會被調用越多次。

造成的影響就是,每一次 OnGUI (  )  被調用時,Time.deltaTime 並不是每次 OnGUI 的間隔時間,這點要小心。

 

也就是如果OnGUI()里面事件方法一直在调用的话,OnGUI就会被重复调用

發生時可能一幀執行多次。它是依據事件,與幀無關。
.html
.OnGUI.html


此題 題目是: OnGUI()函数是每帧执行一次吗

答案是:否。因為不止一次。


 

 

OnGUI() 会在渲染和处理GUI时间时调用

这意味着你的OnGUI程序将会在每一帧被调用。要得到更多的GUI事件的信息查阅Event。如果Monobehaviour的enabled属性设为false,OnGUI()将不会被调用。(MonoBehaviour 是每个脚本派生的类的基类。)

 

OnGUI()每帧至少调用两次,以下程序可以证实。(update执行一次,OnGUI执行两次)

private int a=1;

    // Update is called once per frame

    void Update () {

        a++;

    }

 

    void OnGUI(){

        Debug.Log(a);

    }

 

 What

OnGUI是Unity中通过代码驱动的GUI系统
在脚本中添加OnGUI方法后,UI可以使用代码进行完全控制.

以下是一个OnGUI使用的小例子:

    void OnGUI()

    {

        if (GUILayout.Button("点我"))

            Debug.Log("Hello!");

    }

把上面的方法放到任意一个脚本中,然后挂到场景中,运行后就能看到左上角一个按钮,点击就会执行if中的方法。

 

How

 

布局上,坐标系原点在屏幕左上角。

.html

Box矩形框

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TestOnGUI : MonoBehaviour
{void OnGUI(){GUI.Box(new Rect(10,10,100,90),"看这里!");}
}

 

Button按钮

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TestOnGUI : MonoBehaviour
{void OnGUI(){if (GUI.Button(new Rect(20, 40, 80, 20), "点这里!")){Debug.Log("OK");}}
}

 

Label标签

 标签是非交互式的。只供展览。无法单击或以其他方式移动。最好只显示信息。 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TestOnGUI : MonoBehaviour
{void OnGUI(){GUI.Label(new Rect(25, 25, 100, 30), "Label");}
}

 

RepeatButton按住后会重复执行单击操作的按钮

点击按钮时,每帧执行一次。 

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. void OnGUI()

  8. {

  9. if (GUI.RepeatButton(new Rect(25, 25, 100, 30), "RepeatButton"))

  10. {

  11. Debug.Log("OK");

  12. }

  13. }

  14. }

 

TextField单行输入框

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private string textFieldString = "text field";

  8. void OnGUI()

  9. {

  10. textFieldString = GUI.TextField(new Rect(25, 25, 100, 30), textFieldString);

  11. }

  12. }

 

 TextArea多行输入框

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private string textAreaString = "text area \ntext area";

  8.  
  9. void OnGUI()

  10. {

  11. textAreaString = GUI.TextArea(new Rect(25, 25, 100, 60), textAreaString);

  12. }

  13. }

 

Toggle单选框

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private bool toggleBool = true;

  8.  
  9. void OnGUI()

  10. {

  11. toggleBool = GUI.Toggle(new Rect(25, 25, 100, 30), toggleBool, "Toggle");

  12. }

  13. }

 

Toolbar工具栏

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private int toolbarInt = 0;

  8. private string[] toolbarStrings = { "Toolbar1", "Toolbar2", "Toolbar3" };

  9.  
  10. void OnGUI()

  11. {

  12. toolbarInt = GUI.Toolbar(new Rect(25, 25, 250, 30), toolbarInt, toolbarStrings);

  13. }

  14. }

 

SelectionGrid网格选择形式

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private int selectionGridInt = 0;

  8. private string[] selectionStrings = { "Grid 1", "Grid 2", "Grid 3", "Grid 4" };

  9.  
  10. void OnGUI()

  11. {

  12. selectionGridInt = GUI.SelectionGrid(new Rect(25, 25, 300, 60), selectionGridInt, selectionStrings, 2);

  13. }

  14. }

 

HorizontalSlider水平滑动条

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private float hSliderValue = 0.0f;

  8.  
  9. void OnGUI()

  10. {

  11. hSliderValue = GUI.HorizontalSlider(new Rect(25, 25, 100, 30), hSliderValue, 0.0f, 10.0f);

  12. }

  13. }

 

VerticalSlider垂直滑动条

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private float vSliderValue = 0.0f;

  8.  
  9. void OnGUI()

  10. {

  11. vSliderValue = GUI.VerticalSlider(new Rect(25, 25, 100, 30), vSliderValue, 10.0f, 0.0f);

  12. }

  13. }

 

 HorizontalScrollbar水平滚动条

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private float hScrollbarValue;

  8.  
  9. void OnGUI()

  10. {

  11. hScrollbarValue = GUI.HorizontalScrollbar(new Rect(25, 25, 100, 30), hScrollbarValue, 1.0f, 0.0f, 10.0f);

  12. }

  13. }

 

VerticalScrollbar垂直滚动条

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private float vScrollbarValue;

  8.  
  9. void OnGUI()

  10. {

  11. vScrollbarValue = GUI.VerticalScrollbar(new Rect(25, 25, 100, 30), vScrollbarValue, 1.0f, 10.0f, 0.0f);

  12. }

  13. }

 

ScrollView滚动视图

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private Vector2 scrollViewVector = Vector2.zero;

  8. private string innerText = "I am inside the ScrollView";

  9.  
  10. void OnGUI()

  11. {

  12. // Begin the ScrollView

  13. scrollViewVector = GUI.BeginScrollView(new Rect(25, 25, 100, 100), scrollViewVector, new Rect(0, 0, 400, 400));

  14.  
  15. // Put something inside the ScrollView

  16. innerText = GUI.TextArea(new Rect(0, 0, 400, 400), innerText);

  17.  
  18. // End the ScrollView

  19. GUI.EndScrollView();

  20.  
  21. }

  22. }

 

Window窗口,控件的可拖动容器

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private Rect windowRect = new Rect(20, 20, 120, 50);

  8.  
  9. void OnGUI()

  10. {

  11. windowRect = GUI.Window(0, windowRect, WindowFunction, "My Window");

  12. }

  13.  
  14. void WindowFunction(int windowID)

  15. {

  16. // Draw any Controls inside the window here

  17. Debug.Log("WindowFunction");

  18. }

  19.  
  20. }

 

changed判断数据变化

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. private float hSliderValue = 0.0f;

  8.  
  9. void OnGUI()

  10. {

  11. hSliderValue = GUI.HorizontalSlider(new Rect(25, 25, 100, 30), hSliderValue, 0.0f, 10.0f);

  12.  
  13. if (GUI.changed)

  14. {

  15. Debug.Log(hSliderValue);

  16. }

  17. }

  18. }

BeginGroup/EndGroup

分组

组内成员坐标相对于组的坐标。 

 
  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4.  
  5. public class TestOnGUI : MonoBehaviour

  6. {

  7. void OnGUI()

  8. {

  9. GUI.BeginGroup(new Rect(Screen.width/2-50,Screen.height/2-50,300,300));

  10. GUI.Box(new Rect(0,0,200,200),"我的界面");

  11. GUI.Button(new Rect(20, 50, 100, 30),"我是个按钮!");

  12. GUI.EndGroup();

  13. }

  14. }

.html

 

一些基本使用:

GUI.Button可以创建一个按钮、GUI.Box则能创建一些简单的信息,其中Box的第一个参数Rect需要四个int参数,前两个是对锚点的偏移,而后两个是Box本身的宽高。

在UGUI中,大家一开始就会接触锚点和轴点以保证UI的适配,而在OnGUI中没有那么明显的设置,需要通过Screen.Width和Screen.height获取当前屏幕的宽高来手动调节锚点。

 

举两个例子:

1.右上:new Rect(Screen.width - 100, 0, 100, 50);

2.中央:new Rect((Screen.width - 100) / 2 , (Screen.heigth - 50) / 2, 100, 50)。

 

通常GUI的第一个参数就是上面的Rect,而第二个参数能控制显示具体的内容:string、Texture2D。

 

如果需要string和Texture2D同时显示,则可以使用GUIContent类,不过提供的显示效果有限,只能图片后面跟着文字。

 

显示控制:

这边介绍一些GUI常用的方法,比如GUI.Label可以创建一个文字标签。

 

当然比起GUI,更常用的是GUILayout,因为GUILayout可以自动进行布局,而GUI的所有控件的显示必须指定Rect,不过除了是否自动布局这点,其他的都是一样的。

 

♦ Label

单纯的显示一些文字图片,不能被点击。

 

♦ Button

按钮,在点击释放的时候就会触发if内的代码。

 

♦ RepeatButton

同样是按钮,不同的是,按住的时候每帧都会触发if中的事件。我们可以通过下图看到差别:

        

♦ TextField

提供了可交互功能的Label,用户可以输入文字,返回值是文本框内的文字,用法:tmpStr = GUILayout.TextField(tmpStr)。

 

♦ TextArea

文本区域,类似TextField,但是他提供了多行显示。

 

♦ Toggle

复选框,返回值是当前选项的bool值,当然功能没有UGUI的Toggle可以控制显示很多效果。

 

♦ Toolbar

Toolbar是一组按钮,在同一情况下只能被选中一个,返回值是当前选中的int。UGUI提供的组件比这边的少很多,原因是很多都能进行替代,比如这个Toolbar就可以使用UGUI中的Toggle实现。

 

♦ SelectionGrid

类似Toolbar,但可以显示多行按钮。

 

♦ HorizontalSlider

水平的滑动条,最小值和最大值需要自己指定。

 

♦ VerticalSlider

垂直的滑动条。

 

♦ HorizontalScrollbar

水平滚动条,其实跟Slider差不多,只是显示效果不太一样。

 

♦ VerticalScrollbar

垂直滚动条。

 

♦ ScrollView

滚动视图,自带两个滚动条,返回值是Vector2,指明当前滚动到的位置。参数中第二个Rect指明里面内容的大小。

 

♦ Window

一个可以拖动的窗口,这个可以看作是一个独立的UI页,需要单独显示在一起的UI组可以放到其中,并且在其回调方法中可以指定被拖动的范围。

    // 位置大小设定

    Rect rect = new Rect(20, 20, 120, 50);

    void OnGUI()

    {

        rect = GUI.Window(0, rect, WindowFunction, "window");

    }

 

    // 拖动时执行的方法

    void WindowFunction(int windowID)

    {

        // 窗口内部按钮

        if (GUILayout.Button("btn"))

            print("click");

 

        // 指定可以拖动,该Rect并不是想象中的一个拖动范围,只是指定点窗口的哪个区域可以拖动

        // 而且可拖动区域不会超过该窗口

        GUI.DragWindow(new Rect(0, 0, 120, 50));

}

 

♦ GUI.changed

当前UI是否变化,可以通过该值来处理值变化后的一些情况。

 

OK,内容不算多

 

 

讨论OnGUI的剩下的内容,包括Skin和Style、Layout自动布局等。OnGUI的研究会对这套系统更加的了解。

 

Customization 皮肤定制:

这边讲到了GUIStyle和GUISkin,功能是对GUI的界面皮肤进行定制,当然只使用默认皮肤根本也不会影响代码的功能。

 

可以通过在Project窗口下右键新建一个GUISkin:

这边的GUISkin就包括了一套皮肤,包括Box、Button、Toggle等,而所谓GUIStyle是指某个组件的皮肤,比如点开上图的Box就是一个Style,Button又是另一个Style。

 

以下是应用一个GUIStyle的代码,只需要添加最后一个参数就OK了:

    public GUIStyle customButton;

    void OnGUI()

    {

        GUI.Button(new Rect(10, 10, 150, 20), "I am a Custom Button", customButton);

  }

 

GUISkin的用法是修改当前环境中的皮肤,也很方便:

    public GUISkin mySkin;

    void OnGUI()

    {

        GUI.skin = mySkin;

        GUI.Button(new Rect(10, 10, 150, 20), "Skinned Button");

  }

 

*需要注意的是别图省事直接修改默认的皮肤了,这样会导致Unity自己本身自带的窗口显示异常,修改皮肤就使用以上两种方法就够了。

 

自动布局 Layout:

再次强调一遍,GUI类下的组件都是固定摆放的,而GUILayout类是自动布局的,两者功能上是完全相同,区别仅仅是是否自动布局这点。

 

GUI.BeginGroup(Rect)和GUI.EndGroup()成对使用时,可以改变其中的组件的相对位置,相当于是放在了其父物体下:

    void OnGUI()

    {

        GUI.BeginGroup(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 50, 100, 100));

        GUI.Box(new Rect(0, 0, 100, 100), "Group is here");

        GUI.Button(new Rect(10, 40, 80, 30), "Click me");

        GUI.EndGroup();

  }

 

以上的代码下,虽然Box的位置是(0, 0),但因为使用到了Group放在了中间,所以Box的位置也是在中间。

 

下面开始讲自动布局。

 

GUILayout.BeginArea(Rect)和GUILayout.EndArea()成对使用,效果类似于GUI的Group,不多说。

 

GUILayout中最重要的两个组是BeginHorizontal()和EndHorizontal()、BeginVertical()和EndVertical(),可以自动进行水平和垂直布局:

    float sliderValue = 1.0f;

    float maxSliderValue = 10.0f;

    void OnGUI()

    {

        GUILayout.BeginHorizontal();

        if (GUILayout.RepeatButton("Increase max\nSlider Value"))

        {

            maxSliderValue += 3.0f * Time.deltaTime;

        }

        GUILayout.BeginVertical();

        GUILayout.Box("Slider Value: " + Mathf.Round(sliderValue));

        sliderValue = GUILayout.HorizontalSlider(sliderValue, 0.0f, maxSliderValue);

        GUILayout.EndVertical();

        GUILayout.EndHorizontal();

  }

 

布局之间的嵌套应用完全也是没有问题的。

 

一、Label

  #region 四个角定位

        GUI.Label(new Rect(30, 10, 100, 200), "zzzzzz");
        GUI.Label(new Rect(30, Screen.height - 50, 100, 200), "zzzzzz");
        GUI.Label(new Rect(Screen.width - 50, Screen.height - 50, 100, 200), "zzzzzz");
        GUI.Label(new Rect(Screen.width - 50, 10, 100, 200), "zzzzzz");

        #endregion

 

二、Button

  GUI.Label(new Rect(30, 30, 100, 200), "Button");
        GUI.Button(new Rect(30, 50, 50, 50), "这个是一个按钮");
        GUI.Button(new Rect(90, 50, 50, 50), text);
        //带图片带文字的按钮
        GUIContent guic = new GUIContent("按钮", text);
        GUI.Button(new Rect(150, 50, 50, 50), guic);
        //按键从上往下排 自动排序
        if (GUILayout.Button("1"))
            Debug.Log("1");
        if (GUILayout.Button("2"))
            Debug.Log("2");
        if (GUILayout.Button("3"))
            Debug.Log("3");
        if (GUILayout.Button("4"))
            Debug.Log("4");
        if (GUILayout.Button("5"))
            Debug.Log("5");
        if (GUILayout.Button("6"))
            Debug.Log("6");
        if (GUILayout.Button("7"))
            Debug.Log("7");
        if (GUILayout.Button("8"))
            Debug.Log("8");

 

三、Toggle控件

      GUI.Label(new Rect(30, 100, 100, 200), "Toggle");
      toggle1 = GUI.Toggle(new Rect(30, 120, 100, 30), toggle1, "Toggle");
      toggle2 = GUI.Toggle(new Rect(30, 150, 100, 30), toggle2, text);

 

四、滑动条

 

    GUI.Label(new Rect(30, 180, 100, 200), "滑动条");
        hSliderValue = GUI.HorizontalSlider(new Rect(30, 200, 100, 30), hSliderValue, 0, 10);
        Show("水平滑动条:" + hSliderValue);
        vSliderVaule = GUI.VerticalSlider(new Rect(0, 200, 30, 100), vSliderVaule, 0, 10);

 

五、Toolbar

  toolbarInt = GUI.Toolbar(new Rect(30, 250, 250, 30), toolbarInt, new string[] { "功能一", "功能二", "功能 三" });
        if (lastValue != toolbarInt)
        {
            if (toolbarInt == 0)
                Debug.Log(1111);
            if (toolbarInt == 1)
                Debug.Log(2222);
            if (toolbarInt == 2)
                Debug.Log(3333);
            lastValue = toolbarInt;
        }

 

六、Scrollbar

  GUI.Label(new Rect(30, 300, 100, 200), "Scrollbar");
        hSbarValue = GUI.HorizontalScrollbar(new Rect(30, 320, 100, 30), hSbarValue, 1.0f, 0.0f, 10.0f);
        vSbarValue = GUI.VerticalScrollbar(new Rect(0, 320, 30, 100), vSbarValue, 1.0f, 0.0f, 10.0f);

 

七、菜单

        GUI.Box(new Rect(30, 350, 100, 100), "Menu");
        if (GUI.Button(new Rect(40, 370, 80, 20), "1"))

 

八、TextField

  useNmae = GUI.TextField(new Rect(Screen.width / 2, Screen.height / 2 - 200, 150, 30), useNmae);
        //*****密码字符的掩码字符
        passWord = GUI.PasswordField(new Rect(Screen.width / 2, Screen.height / 2 - 150, 150, 30), passWord, '*', 25);
        if (GUI.Button(new Rect(Screen.width / 2, Screen.height / 2 - 50, 150, 30), "登录"))
        {
            isBntLogin = true;
            Debug.Log(isBntLogin+ "isBntLogin");
            if (useNmae.Equals("admin") && passWord.Equals("123"))
            {
                isSuccess = true;
                GUI.Label(new Rect(500, 350, 150, 30), "登录成功");
            }
            else
            {
                isSuccess = false;
                GUI.Label(new Rect(500, 350, 150, 30), "登录失败");
            }


        }
        if (isBntLogin)
        {
            if (isSuccess)
                GUI.Label(new Rect(Screen.width / 2, Screen.height / 2 + 50, 150, 30), "登录成功");
            else
            {
                GUI.Label(new Rect(Screen.width / 2, Screen.height / 2 + 50, 150, 30), "登录失败");
            }
        }

 

 

Unity的官方文档中下一篇讲到了对原本的OnGUI进行扩展,其实就是将几个组件封装到一个方法里,不多说了,但是在真正写一个窗口时很重要,比如说Vector3的三个水平的输入框,可以封装成一个方法,以后要调用到类似的就可以直接使用。

 

 

引用: 

.html

.html

 

更多推荐

OnGUI方法应用与生命周期

本文发布于:2024-03-13 13:15:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1734069.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:生命周期   方法   OnGUI

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!