Unity------Unity 脚本基类 MonoBehaviour 与 GameObject 的关系


版权声明:本文为博主原创文章,未经博主允许不得转载。欢迎指出文中错误之处!!!
一、MonoBehaviour 的生命周期
MonoBehaviour 是 Unity 中所有脚本的基类,如果你使用js的话,脚本会自动继承MonoBehaviour。如果使用C#的话,你需要显式继承MonoBehaviour。
在我们使用MonoBehaviour的时候,尤其需要注意的是它有哪些可重写函数,这些可重写函数会在游戏中发生某些事件的时候被调用。我们在Unity中最常用到的几个可重写函数是这几个:
Awake:当一个脚本被实例化时,Awake 被调用。我们大多在这个类中完成成员变量的初始化。
Start:仅在 Update 函数第一次被调用前调用。因为它是在 Awake 之后被调用的,我们可以把一些需要依赖 Awake 的变量放在Start里面初始化。 同时我们还大多在这个类中执行 StartCoroutine 进行一些协程的触发。要注意在用C#写脚本时,必须使用 StartCoroutine 开始一个协程,但是如果使用的是 JavaScript,则不需要这么做。
Update:当开始播放游戏帧时(此时,GameObject 已实例化完毕),其 Update 在 每一帧 被调用。
LateUpdate:LateUpdate 是在所有 Update 函数调用后被调用。
FixedUpdate:当 MonoBehaviour 启用时,其 FixedUpdate 在每一固定帧被调用。
OnEnable:当对象变为可用或激活状态时此函数被调用。
OnDisable:当对象变为不可用或非激活状态时此函数被调用。
OnDestroy:当 MonoBehaviour 将被销毁时,这个函数被调用。
下面用一张图来更形象地说明一下这几个类的在MonoBehaviour的生命周期中是如何被调用的:
二、MonoBehaviour 的那些坑
私有(private)和保护(protected)变量只能在专家模式中显示。属性不被序列化或显示在检视面板.
不要使用命名空间(namespace)
记得使用 缓存组件查找, 即在MonoBehaviour的长远方法中经常被访问的组件最好在把它当作一个私有成员变量存储起来。
在游戏里经常出现需要检测敌人和我方距离的问题,这时如果要寻找所有的敌人,显然要消耗的运算量太大了,所以最好的办法是将攻击范围使用Collider表示,然后将Collider的isTrigger设置为True。最后使用OnTriggerEnter来做攻击范围内的距离检测,这样会极大提升程序性能。
三、Monobehaviour 常用方法
不可重写函数:
Invoke
function Invoke (methodName : string, time : float) : void
在 time 秒之后,调用 methodName 方法;
public class example : MonoBehaviour {
public Rigidbody projectile;
void LaunchProjectile() {
Rigidbody instance = Instantiate(projectile);
instance.velocity = Random.insideUnitSphere * 5;
}
public void Awake() {
Invoke("LaunchProjectile", 2);
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
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
可重写函数:
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 将会在每一帧被调用。
四、脚本与GameObject的关系
被显式添加到 Hierarchy 中的 GameObject 会被最先实例化,GameObject 被实例化的顺序是从下往上。GameObject 被实例化的同时,加载其组件 component 并实例化,如果挂载了脚本组件,则实例化脚本组件时,将调用脚本的 Awake 方法,组件的实例化顺序是也是从下往上。在所有显式的 GameObject 及其组件被实例化完成之前,游戏不会开始播放帧。
当 GameObject 实例化工作完成之后,将开始播放游戏帧。每个脚本的第一帧都是调用 Start 方法,其后每一帧调用 Update,而且每个脚本在每一帧中的调用顺序是从下往上。
总结:被挂载到 GameObject 下面的脚本会被实例化成 GameObject 的一个成员。
4.1 脚本变量的引用
在脚本中声明另一个脚本的变量。在 ClassA 中建立一个 public 的变量类型是 ClassB。
// class A
public class classA : MonoBehaviour {
public classB b;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
// class B
public class classB : MonoBehaviour {
public classA a;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
4.1.1 非同一个 GameObject 的脚本引用
情况如下:
此时,如果 classA 中的成员 B 想要引用由 GameObjectB new 出来的 classB 对象,只需要将 GameObjectB 拖拽到 GameObjectA 中 classA 脚本即可。
4.1.2 同一个 GameObject 中互相引用
情况如下:
此时,发现没法通过拖拽的方式建立 classA 和 classB 的引用。因为 Unity 编辑器里面的拖拽绑定方式是 GameObject 级别的。
那么此时如何解决互相引用的问题呢?此时,需要用到 gameObject 这个变量。
被挂载到 GameObject 中的脚本,被实例化时,其内部继承自 Monobehavior 的 gameObject 成员会绑定所挂载的 GameObject 对象。可以注意到,在本例中,classA 和 classB 都是同一个 GameObject 下的组件,所以通过 GetComponent 便可以获得另一个脚本变量的引用。
// class A
public class classA : MonoBehaviour {
public classB b;
// Use this for initialization
void Start () {
b = gameObject.GetComponent ("ClassB") as ClassB;
}
// Update is called once per frame
void Update () {
}
}
// class B
public class classB : MonoBehaviour {
public classA a;
// Use this for initialization
void Start () {
a = gameObject.GetComponent ("ClassA") as ClassA;
}
// Update is called once per frame
void Update () {
}
}
1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
4.1.3 父子关系的 GameObject 中引用
把问题引申一步,还是那两个脚本ClassA,ClassB,不过这回不是绑在同一个GameObject上面,而是分辨绑定在两个GameObject:Parent(ClassA),Child(ClassB)
首先还是来尝试拖拽,虽然无法在Unity的编辑器中通过拖拽互相引用脚本(Componet),不过绑定 GameObject 是可以.所以只需要建立两个public的变量,然后类型都是 GameObject,在Unity里面互相拖拽引用,最后在 Start 函数时候通过已经绑定好的 gameObject 调用其 GetComponent 方法即可。
的确,这个方法是可行,不过有个更好的方法就是使用 Transform。Transform 是一个很特殊的Component,其内部保留着 GameObject 之间的显示树结构.所以就上面的例子来说,当要从 Child 访问到 Parent,只需要在 Child 对应的脚本里面写 transform.parent.gameObject.GetComponent() 即可
返过来就相对麻烦一点,因为无法保证一个parent只有一个child,所以无法简单的使用 transform.child.gameObject这样访问, 但是Unity给我们提供了一个很方便的函数,那就是Find。
需要注意的是Find只能查找其Child,举个复杂点的例子
Parent->ChildA->ChildB->ChildC
当在 Patent 中想要找到 ChildC中的一个Component时候,调用 transform.Find(“ChildA/ChildB/ChildC”).gameObject;
Unity------Unity 脚本基类 MonoBehaviour 与 GameObject 的关系的更多相关文章
- [Unity2D]脚本基类MonoBehaviour介绍
Unity中的脚本都是继承自MonoBehaviour. MonoBehaviour 表示一个单一的行为.Unity中用户对游戏对象的操作被分割成若干个单一行为.每个单一行为都作为一个MonoBeha ...
- Unity3D_02_基类MonoBehaviour/自带函数以及脚本执行的生命周期
导引: 其中Time,Input,Physics都是Unity中的全局变量.GameObject是游戏中的基本物件.GameObject是由Component组合而成的,GameObject本身必须有 ...
- 【Unity3D基础教程】给初学者看的Unity教程(二):所有脚本组件的基类 -- MonoBehaviour的前世今生
作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 上一次我们讲了GameObject,C ...
- 【Unity基础知识】基础游戏单位GameObject中常用的属性和API
一.GameObject中的成员变量 主要思想:得到该脚本依附的GameObject的相关信息 现有: Lesson4的代码: using System.Collections; using Syst ...
- C# 面向对象 , 抽象基类
抽象基类 关键字, abstract abstract class SSS { public void aaa() { } } 作为抽象基类, 只能在 继承关系 中 担任父类的角色,不能出现在其他地 ...
- why pure virtual function has definition 为什么可以在基类中实现纯虚函数
看了会音频,无意搜到一个frameworks/base/include/utils/Flattenable.h : virtual ~Flattenable() = 0; 所以查了下“纯虚函数定义实现 ...
- 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 在脚本中使用MonoBehaviour
继上次分析了热更新的Demo后,这次来介绍如何在热更新代码中使用MonoBehaviour. MonoBehaviour挂载到GameObject对象上的脚本的基类.平常Unity开发时,简单的做法就 ...
- 游戏编程之Unity常用脚本类的继承关系
前言学习Unity开发引擎的初学者会接触大量的脚本类,而这些类之间的关系往往容易被忽略.本文对Unity引擎开发中的一些常用类及其关系进行了简单的归纳总结. 博文首发地址:http://tieba.b ...
- Unity编辑器 - 资源批处理工具基类
Unity编辑器 - 资源批处理工具基类 经常要对资源进行批处理,很多时候都是一次性的需求,于是弄个通用脚本. 工具是个弹出面板,处理过程有进度条,如下: 如图,子类只需要重写几个方法: using ...
随机推荐
- 每天一个linux命令(6) ar命令
当我们的程序中有经常使用的模块,而且这种模块在其他程序中也会用到,这时按照软件重用的思想,我们应该将它们生成库,使得以后编程可以减少开发代码量.这里介绍命令ar,用来对库操作. ar命令可以用来创建. ...
- django rest_framework入门三-Requests和Responses
这一节,我们介绍rest_framework的Requests和Responses对象,来替代django.http的HttpRequest和HttpResponse对象 1.Requests和Res ...
- python(44):array和matrix的运算
在NumPy中,array用于表示通用的N维数组,matrix则特定用于线性代数计算.array和matrix都可以用来表示矩阵,二者在进行乘法操作时,有一些不同之处. 使用array时,运算符 * ...
- 运行Virtualbox去安装系统时出错:Failed to open a session for the virtual machine,Unable to load R3 module xxxx/VBoxDD.DLL(VBoxDD)
貌似看到不少人(1,2,3),在使用Virtualbox去安装系统时,都遇到这个错误: 比如这里遇到的: 截图: 和另外这里的截图: 加文字描述: Failed to open a session f ...
- 【Spring】Spring Session的简单搭建与源码阅读
搭建一个简单的Spring Session例子 引入依赖包 <dependencies> <dependency> <groupId>org.springframe ...
- 【ARM】2410裸机系列-流水灯
开发环境 1.硬件平台:FS2410(s3c2410) 2.主机:Ubuntu 12.04 LTS LED原理图 LED的GPIO的配置 配置GPFCON寄存器,设置GPF4-7为输出 配置GPF ...
- 8个超炫酷仿苹果应用的HTML5动画
苹果的产品一直以精美的UI著称,无论是软件应用还是硬件设备.本文主要分享了8个很不错的HTML5动画应用,这些动画正式模仿了苹果的各类应用,有焦点图.钟表.菜单等HTML5应用和jQuery插件,大家 ...
- Java中LinkedList实现原理
数据结构 LinkedList是基于链表结构实现,所以在LinkedList类中包含了first和last两个指针(类型为Node).Node中包含了对prev节点.next节点的引用,这样就构成了双 ...
- WPF自定义行为Behavior,实现双击控件复制文本
WPF引用xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity& ...
- Java编程的逻辑 (70) - 原子变量和CAS
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...