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 ...
随机推荐
- [AWS vs Azure] 云计算里AWS和Azure的探究(2)
Amazon EC2是Elastic Compute Cloud的简称,翻译成中文就是弹性计算云.它是Amazon云里面最基础的内容,也是发展到今天最成熟的部分,通过EC2, 你可以在Amazon的云 ...
- running boot2docker -> error in run: Failed to get machine “boot2docker-vm”: machine does not exist
登陆和使用.详细请看.....https://github.com/boot2docker/boot2docker boot2docker start error in run: Failed to ...
- 根据ip查询经纬度的接口
http://ip-api.com/json/ 直接访问,结果如下 // 20180804140751 // http://ip-api.com/json/ { "as": &qu ...
- Python安装pycurl失败,及解决办法
Centos安装pycurl centos 安装pycurl yum install python-devel curl-devel pip3 install pycurl Mac(老版本)安装pyc ...
- C#学习笔记(5)——大项目查找
说明(2017-5-27 16:34:39): 1. 注意事项: (0)设计窗体,添加一个dgv,添加5个列名,修改名字和绑定数据. (1)添加引用,system.data.sqlclient (2) ...
- app测试初窥
要用到的两个神器:abd&drozer adb介绍 adb的全称为Android Debug Bridge,就是起到调试桥的作用,作为一名开发者倒是常用到这个工具.借助adb工具,我们可以管理 ...
- highcharts图表组件通过设置tooltip属性自定义数据提示信息
我们先来看看这样一个例子,全局配置好tooltip,数据点的提示信息能够自己根据数据点自身数据情况加以显示,代码如下所示: 01.$(function () { 02.$('#container'). ...
- nginx报502 bad GateWay错误的解决方法
nginx+php-fpm+mysql的网站,访问nginx的某个页面,报502 GateWay的错误,一般见到此错误,可以判断是php-fpm的问题,而不是nginx的问题.通过监控nginx的错误 ...
- centos7 安装oracle jdk 与openjdk 实现切换
1. 分别安装oraclejdk 与openjdk #下载安装oraclejdk rpm -ivh --prefix=/usr.java/java1.8 ***.rpm #安装openjdk su - ...
- Oracle 11gR2 ORA-12638 身份证明检索失败解决方法
1. 找到Oracle安装目录或者菜单栏,打开Oracle Net manager 2. 选择本地 ->概要文件 ->下拉选择Oracle高级安全性 -> 取消NTS 3. 菜单栏 ...