标签: unity脚本
2017-03-27 12:55 395人阅读 评论(0) 收藏 举报
 分类:
Unity3D(4) 

版权声明:本文为博主原创文章,未经博主允许不得转载。欢迎指出文中错误之处!!!

 

目录(?)[+]

 

一、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 的关系的更多相关文章

  1. [Unity2D]脚本基类MonoBehaviour介绍

    Unity中的脚本都是继承自MonoBehaviour. MonoBehaviour 表示一个单一的行为.Unity中用户对游戏对象的操作被分割成若干个单一行为.每个单一行为都作为一个MonoBeha ...

  2. Unity3D_02_基类MonoBehaviour/自带函数以及脚本执行的生命周期

    导引: 其中Time,Input,Physics都是Unity中的全局变量.GameObject是游戏中的基本物件.GameObject是由Component组合而成的,GameObject本身必须有 ...

  3. 【Unity3D基础教程】给初学者看的Unity教程(二):所有脚本组件的基类 -- MonoBehaviour的前世今生

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 上一次我们讲了GameObject,C ...

  4. 【Unity基础知识】基础游戏单位GameObject中常用的属性和API

    一.GameObject中的成员变量 主要思想:得到该脚本依附的GameObject的相关信息 现有: Lesson4的代码: using System.Collections; using Syst ...

  5. C# 面向对象 , 抽象基类

    抽象基类 关键字,  abstract abstract class SSS { public void aaa() { } } 作为抽象基类, 只能在 继承关系 中 担任父类的角色,不能出现在其他地 ...

  6. why pure virtual function has definition 为什么可以在基类中实现纯虚函数

    看了会音频,无意搜到一个frameworks/base/include/utils/Flattenable.h : virtual ~Flattenable() = 0; 所以查了下“纯虚函数定义实现 ...

  7. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 在脚本中使用MonoBehaviour

    继上次分析了热更新的Demo后,这次来介绍如何在热更新代码中使用MonoBehaviour. MonoBehaviour挂载到GameObject对象上的脚本的基类.平常Unity开发时,简单的做法就 ...

  8. 游戏编程之Unity常用脚本类的继承关系

    前言学习Unity开发引擎的初学者会接触大量的脚本类,而这些类之间的关系往往容易被忽略.本文对Unity引擎开发中的一些常用类及其关系进行了简单的归纳总结. 博文首发地址:http://tieba.b ...

  9. Unity编辑器 - 资源批处理工具基类

    Unity编辑器 - 资源批处理工具基类 经常要对资源进行批处理,很多时候都是一次性的需求,于是弄个通用脚本. 工具是个弹出面板,处理过程有进度条,如下: 如图,子类只需要重写几个方法: using ...

随机推荐

  1. (原创)c++11改进我们的模式之改进代理模式,实现通用的AOP框架

    c++11 boost技术交流群:296561497,欢迎大家来交流技术. 本次要讲的时候如何改进代理模式,具体来说是动态代理模式,动态代理模式一般实现AOP框架,不懂AOP的童鞋看这里.我前面的博文 ...

  2. Eclipse工程文件夹 红叹号

    问题产生: 重装系统后,换了个新版本的Eclipse,但是,使用以前的工程目录(工程目录重命名了)后,发现,一些工程上显示红叹号,仔细查看里面的代码,也没有错误 问题原因: 经过查看,是工程中,使用的 ...

  3. vue中的filters的用法

    1.效果 金额保留两位小数,并加上单位元 2.index.html <!DOCTYPE html> <html lang="en"> <head> ...

  4. u3d中的向量 vector3 vector2

    Vector3(x,y,z)x代表左右,y代表上下,z代表前后 Vector3.magnitude 长度 计算两点之间的距离  .如果只给了一点的话.算出的长度其实就是和Vector3.zero点之间 ...

  5. Android 编程下 TextView 添加链接的一种方式

    通过如下这种方式给 TextView 添加的链接支持链接样式.点击事件.href 样式,代码如下: package cn.sunzn.tlink; import android.app.Activit ...

  6. java命令执行jar包的方式

    http://www.cnblogs.com/adolfmc/archive/2012/10/07/2713562.html 大家都知道一个java应用项目可以打包成一个jar,当然你必须指定一个拥有 ...

  7. RFC 4627 JSON

    Network Working Group D. Crockford Request for Comments: 4627 JSON.org Category: Informational July ...

  8. 基于jQuery滑动分步式进度导航条代码

    分享一款基于jQuery滑动分步式进度导航条代码.这是一款基于jquery实现的网站注册动态步骤导航条代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div id=& ...

  9. 【Unity】(转)游戏辅(外)助(挂)开发

    转载自:https://myhloli.com/u3dgames-hook-superdsm.html 另外,在博客园搜外挂关键字,能找到不少干货: http://www.cnblogs.com/Ga ...

  10. <要做股市赢家:杨百万>读书笔记

    书在这里 和这里: 要注意的是,并不是政府每出台一个政策股价就要变.如果听到各种消息,市场却没有反应,就不要去做这个聪明人.有消息后应该密切关注市场反应,看成交量.价格的变化等等,再作决定.总之,关键 ...