[Unity3D] 03 - Component of UI

时间:2022-03-04 15:04:19

还需进一步整理!

ing...

博客参考


Unity 相关博客:Unity游戏开发爱好者

功能归类  


按钮:

Unity 5 UI Tutorial - Button and event handlers

输入框:

Unity 5 UI Tutorial - Input field and event handlers

  • 控件信息获取:点击按钮,获取另一个控件的属性。
using UnityEngine;
using UnityEngine.UI; public class Button_event_test : MonoBehaviour { public void Button_Click()
{
string str_inputField1 = "Hello world - test123";
Debug.Log(str_inputField1);
     // 获取这个对象
GameObject inputObj = GameObject.Find("Canvas/Panel/InputField1");
// 拨开这个对象的真正面目
InputField input = (InputField)inputObj.GetComponent<InputField>();
// 得到这个对象的属性
str_inputField1 = input.text.ToString();
Debug.Log(str_inputField1);
}
}
  • 登陆界面设计的重要事项
  1. 密码
  2. 字符规则判定(正则表达式)

Ref:Unity-3D 简单登陆界面,在此基础上做修改。

using UnityEngine;
using System.Collections; public class Label : MonoBehaviour {
private string userName;
private string passWord;
private string username;
private string password;
private string message;
private string info;
public Texture img;
void OnGUI()
{
GUIStyle sty = new GUIStyle();
GUIStyle sty1 = new GUIStyle();
sty.fontSize = ;
sty1.fontSize = ;
GUI.Label(new Rect(, , , ), "登录界面", sty1);
GUI.Label(new Rect(, , , ), "用户名:", sty);
userName = GUI.TextField(new Rect(, , , ),userName,);
GUI.Label(new Rect(, , , ), "密码:",sty);
passWord = GUI.PasswordField(new Rect(, , , ), passWord, '*', );
message = GUI.TextArea(new Rect(, , , ), message, sty);
if (GUI.Button(new Rect(, , , ), "login"))
{
if (username == userName && password == passWord)
{
info = "success!"; message = "床前明月光,\n疑是地上霜。\n举头望明月,\n低头思故乡。\n";
}
else
info = "failed!";
}
sty.fontSize = ;
GUI.Label(new Rect(, , , ), info,sty); }
// Use this for initialization
void Start () {
userName = "";
passWord = "";
message = "";
info = "";
username = "wonameshuai";  # default
password = "nishuodedui";  # default
} // Update is called once per frame
void Update () { }
}

Canvas

  • 大小,inspector
  • 加图片:Canvas 本身是个框架,没有背景图案也就没有Texture。--> 内部添加panel

Panel

加图片:

[Unity3D] 03 - Component of UI

//用户名
private var editUsername : String;
//密码
private var editPassword : String;
//提示信息
private var editShow : String; function Start()
{
editShow = "请您输入正确的用户名与密码";
editUsername = "请输入用户名";
editPassword = "请输入密码";
} function OnGUI ()
{ //显示提示信息内容
GUI.Label(Rect(, , Screen.width, ), editShow); if (GUI.Button(Rect(,,,),"登录"))
{
//点击按钮修改提示信息
editShow = "您输入的用户名为 :" + editUsername + " 您输入的密码为:"+ editPassword;
}
//编辑框提示信息
GUI.Label(Rect(, , , ), "用户名"); GUI.Label(Rect(, , , ), "密码:"); //获取输入框输入的内容
editUsername = GUI.TextField (Rect (, , , ), editUsername, );
editPassword = GUI.PasswordField (Rect (, , , ), editPassword, "*"[],);
}

代码研究


Panel加载图片:

那是因为你没把图片设置为Sprite (小精灵),图片只是Texture而已,只能作为贴图使用。

Goto: Unity3D在UI中加入Image图片

点击事件配置:

Goto: Unity 4.6 uGUI的点击事件

发送消息,发送给谁? 如何控制?

[Unity3D] 03 - Component of UI

using UnityEngine;
using System.Collections;
using UnityEngine.UI; public class testclick : MonoBehaviour
{ // Use this for initialization
void Start ()
{ Button btn = gameObject.GetComponent<Button>();
btn.onClick.AddListener(click);
} void click()
{
Debug.Log ("Mouse Click");
}
}

对应代码

Unity 3种message消息管理使用

Ref: http://blog.csdn.net/u011484013/article/details/51487936

  1. BroadcastMessage 广播消息
  2. SendMessage 发送消息
  3. SendMessageUpwards 向上发送消息

MonoBehaviour 是 Unity 中所有脚本的基类,

  • 如果你使用JS的话,脚本会自动继承MonoBehaviour。
  • 如果使用C#的话,你需要显式继承MonoBehaviour。
  • 发送消息
using UnityEngine;
using System.Collections; public class xx1 : MonoBehaviour
{
void OnGUI()
{
if (GUI.Button(new Rect(, , , ), "发送1"))  
{//this gameobjec
SendMessage("myTest");      # <-- button 1 向当前对象挂载的所有脚本上面发送消息
    }
if (GUI.Button(new Rect(, , , ), "发送2"))
{//this gameobjec and it's childs
BroadcastMessage("myTest");   # <-- button 2 朝物体和所有子物体发送消息
} if (GUI.Button(new Rect(, , , ), "发送3"))
{//this gameobjec‘parent
SendMessageUpwards("myTest");  # <-- button 3 朝物体和上级父物体发送信息
}
}
}
  • 接收消息
using UnityEngine;
using System.Collections; public class XXX : MonoBehaviour { // Use this for initialization
void Start () { } // Update is called once per frame
void Update () { } void OnDrag(Vector2 delta)
{
Debug.Log("-------OnDrag--------");
}  public void myTest() {
Debug.Log("this is a methord:" + gameObject.name);
 }
}

游戏对象 (GameObject)是所有其他组件 (Component) 的容器。游戏中的所有对象本质上都是游戏对象 (GameObject)。

Ref: http://blog.csdn.net/linuxheik/article/details/37956243

创建游戏对象 (GameObject)

游戏对象 (GameObject) 自身不会向游戏添加任何特性。而是容纳实现实际功能的组件 (Component) 的容器。

例如,光 (Light) 是一个附加到游戏对象 (GameObject) 的组件 (Component)。

附加到游戏对象 (GameObject)组件 (Component)

# 注意先后顺序

如果要从脚本创建组件 (Component),则应

  1. 创建空游戏对象 (GameObject),
  2. 然后使用 gameObject.AddComponent(ClassName) 函数添加所需组件 (Component)。  

在脚本中,组件 (Component) 可以方便地通过消息发送或 GetComponent(TypeName) 函数相互通信。这使您可以编写可重复使用的小脚本,这些脚本可以附加到多个游戏对象 (GameObject) 并重复用于不同用途。

除了作为组件 (Component) 的容器之外,游戏对象 (GameObject) 还具有标记 (Tag)、层 (Layer) 和名称 (Name)。

  • 标记 (Tag) 用于通过标记 (Tag) 名称来快速查找对象。
  • 层 (Layer) 可用于仅对某些特定的对象组投射光线、渲染或应用光照。
  • 名称 (Name)

标记 (Tag) 和层 (Layer) 可以使用标记管理器 (Tag Manager)(在编辑 (Edit) ->项目设置 (Project Settings) -> 标记 (Tags) 中)进行设置。

 
 

实例 ( GameObject and GetComponent )

-- Object --

套路:获得object,顶层结构,然后再按照它本来的面貌GetComponent出来。  
//获取按钮游戏对象
GameObject btnObj = GameObject.Find ("Canvas/Button");
//获取按钮脚本组件
Button btn = (Button) btnObj.GetComponent<Button>();

--  MonoBehaviour --

using UnityEngine;
using UnityEngine.UI;
[Unity3D] 03 - Component of UI  
public class Button_event_test : MonoBehaviour {

    public void Button_Click()
{
...
}
}

MonoBehaviour 与 GameObject 的关系

Ref: Unity 脚本基类 MonoBehaviour 与 GameObject 的关系

一、MonoBehaviour 生命周期

1.1. 内置函数列表

Awake:当一个脚本被实例化时,Awake 被调用。我们大多在这个类中完成成员变量的初始化。

Start:仅在 Update 函数第一次被调用前调用。因为它是在 Awake 之后被调用的,我们可以把一些需要依赖 Awake 的变量放在Start里面初始化。 同时我们还大多在这个类中执行 StartCoroutine 进行一些协程的触发。要注意在用C#写脚本时,必须使用 StartCoroutine 开始一个协程,但是如果使用的是 JavaScript,则不需要这么做。

Update:当开始播放游戏帧时(此时,GameObject 已实例化完毕),其 Update 在 每一帧 被调用。

LateUpdate:LateUpdate 是在所有 Update 函数调用后被调用。

FixedUpdate:当 MonoBehaviour 启用时,其 FixedUpdate 在每一固定帧被调用。

OnEnable:当对象变为可用或激活状态时此函数被调用。

OnDisable:当对象变为不可用或非激活状态时此函数被调用。

OnDestroy:当 MonoBehaviour 将被销毁时,这个函数被调用。

详见图:生命周期示意图

接下来,做出一下讲解:

最先执行的方法是Awake,这是生命周期的开始,用于进行激活时的初始化代码。

  一般可以在这个地方将当前脚本禁用:this.enable=false,如果这样做了,则会直接跳转到OnDisable方法执行一次,然后其它的任何方法,都将不再被执行。

如果当前脚本处于可用状态,则正常的执行顺序是继续向下执行OnEnable。

  当然我们可以在另外一个脚本中实现这个脚本组件的启动:this.enable=true;

再向下执行,会进行一个判断,如果Start方法还没有被执行,则会被执行一次,如果已经被执行了,则不会再被执行。

  这是个什么意思呢?我们可以在某个脚本中将组件禁用this.enable=false,再启用时会转到OnEnable处执行,这时继续向下走,发现Start执行过了,将不再被执行。

  比如说:第一次启用时,将怪物的初始位置定在了(0,0,0)点,然后怪物可能会发生了位置的变换,后来被禁用了,再次启用时,不会让怪物又回到初始的(0,0,0)位置。

继续向后执行,就是Update了,然后是FixUpdate,再然后是LateUpdate,如果后面写了Reset,则会又回到Update,在这4个事件间可以进行循环流动

再向后执行,就进入了渲染模块(Rendering),非常重要的一个方法就是OnGUI,用于绘制图形界面。【当然,如果你使用了NGUI,这个生命周期的事情你就不用考虑了】

首先我们说说GUI与NGUI的区别,

GUI是Unity自带的绘制界面工具,它的成像原理是基于表层的,所以执行效率非常的低,并且没有提供复杂的UI的接口,就算开发者硬着头皮写上去只能让UI的执行效率更低。

NGUI 完全依赖于3D就好比在游戏世界中的摄像机直直的照射在一个平面中,在平面之上再去绘制自己的UI,所以它的执行效率会非常高。

NGUI是一款收费的插件,在Asset Store中大家可以看到价格。在未购买正版的前提下我们可以通过两种方法来使用NGUI,

  • 第一种:使用官方提供的免费版本,但是这个版本中有NGUI的水印,无法正式发布不过完全可以作为学习使用。
  • 第二种:使用别人购买过的正版插件,在互联网中有朋友放出NGUI的插件。

再向后,就是卸载模块(TearDown),这里主要有两个方法OnDisable与OnDestroy。当被禁用(enable=false)时,会执行OnDisable方法,但是这个时候,脚本并不会被销毁,在这个状态下,可以重新回到OnEnable状态(enable=true)。

当手动销毁或附属的游戏对象被销毁时,OnDestroy才会被执行,当前脚本的生命周期结束。

特别要强调的是:这里虽然可以使用C#来写代码,但是这个类构造对象的生命周期,与MonoBehaviour的生命周期,是完全不同的。

二、MonoBehaviour 的那些坑

  • 私有(private)和保护(protected)变量只能在专家模式中显示。属性不被序列化或显示在检视面板。
  • 不要使用命名空间(namespace)
  • 记得使用 缓存组件查找, 即在MonoBehaviour的长远方法中经常被访问的组件最好在把它当作一个私有成员变量存储起来。
  • 在游戏里经常出现需要检测敌人和我方距离的问题,这时如果要寻找所有的敌人,显然要消耗的运算量太大了,
    • 所以最好的办法是将攻击范围使用Collider表示,然后将Collider的isTrigger设置为True。
    • 最后使用OnTriggerEnter来做攻击范围内的距离检测,这样会极大提升程序性能。

三、Monobehaviour 常用方法

Update

当 MonoBehaviour 实例化完成之后,Update 在每一帧被调用。

LateUpdate

LateUpdate 是在所有 Update 函数调用后被调用。这可用于调整脚本执行顺序。例如:当物体在Update里移动时,跟随物体的相机可以在LateUpdate里实现。

FixedUpdate

处理 Rigidbody 时,需要用FixedUpdate代替Update。例如:给刚体加一个作用力时,你必须应用作用力在FixedUpdate里的固定帧,而不是Update中的帧。(两者帧长不同)

Awake

Awake 用于在游戏开始之前初始化变量或游戏状态。在脚本整个生命周期内它仅被调用一次。Awake 在所有对象被初始化之后调用,所以你可以安全的与其他对象对话或用诸如 GameObject.FindWithTag 这样的函数搜索它们。每个游戏物体上的Awke以随机的顺序被调用。因此,你应该用Awake来设置脚本间的引用,并用Start来传递信息Awake总是在Start之前被调用。它不能用来执行协同程序。

C#和Boo用户注意:Awake 不同于构造函数,物体被构造时并没有定义组件的序列化状态。Awake像构造函数一样只被调用一次。

Start

Start在behaviour的生命周期中只被调用一次。它和 Awake 的不同是,Start 只在脚本实例被启用时调用。你可以按需调整延迟初始化代码。Awake 总是在Start之前执行。

OnMouseEnter /OnMouseOver / OnMouseExit / OnMouseDown / OnMouseUp / OnMouseDrag

当鼠标进入 / 悬浮 / 移出 / 点击 / 释放 / 拖拽GUIElement(GUI元素)或Collider(碰撞体)中时调用OnMouseEnter。

OnTriggerEnter / OnTriggerExit / OnTriggerStay

当Collider(碰撞体)进入 / 退出 / 停留在 trigger(触发器)时调用OnTriggerEnter。OnTriggerStay 将会在每一帧被调用。

OnCollisionEnter / OnCollisionExit / OnCollisionStay

当此collider/rigidbody触发另一个rigidbody/collider时,被调用。OnCollisionStay 将会在每一帧被调用。

可重写函数

Invoke

function Invoke (methodName : string, time : float) : void
在 time 秒之后,调用 methodName 方法; InvokeRepeating function InvokeRepeating (methodName : string, time : float, repeatRate : float) : void
从第一次调用开始,每隔repeatRate时间调用一次. CancelInvoke function CancelInvoke () : void
取消这个MonoBehaviour上的所有调用Invoke。 IsInvoking function IsInvoking (methodName : string) : bool
某指定函数是否在等候调用。 StartCoroutine function StartCoroutine (routine : IEnumerator) : Coroutine
一个协同程序在执行过程中,可以在任意位置使用 yield 语句。yield 的返回值控制何时恢复协同程序向下执行。协同程序在对象自有帧执行过程中堪称优秀。协同程序在性能上没有更多的开销。StartCoroutine函数是立刻返回的,但是yield可以延迟结果。直到协同程序执行完毕。 StopCoroutine / StopAllCoroutines

不可重写函数

四、脚本与GameObject的关系

* 实例化

被显式添加到 Hierarchy 中的 GameObject 会被最先实例化,GameObject 被实例化的顺序是从下往上。

GameObject 被实例化的同时,加载其组件 component 并实例化,

如果挂载了脚本组件,则实例化脚本组件时,将调用脚本的 Awake 方法,组件的实例化顺序是也是从下往上。

在所有显式的 GameObject 及其组件被实例化完成之前,游戏不会开始播放帧。

* 实例化后

当 GameObject 实例化工作完成之后,将开始播放游戏帧。每个脚本的第一帧都是调用 Start 方法,其后每一帧调用 Update,而且每个脚本在每一帧中的调用顺序是从下往上。

* 总结

被挂载到 GameObject 下面的脚本会被实例化成 GameObject 的一个成员。

* 脚本与GameObject的关系

详见链接内容

NB: Unity 编辑器里面的拖拽绑定方式是 GameObject 级别的。