脚本生命周期

﹥>﹥吖頭↗ 提交于 2019-11-26 03:11:09

Reset方法的调用机制
Reset方法可以重设为默认值。当用户点击监视面板上的内容按钮或者首次添加组件时被调用。这个函数只在编辑器模式下被调用。通常用于给定监视面板很好的默认值。

脚本生命周期

接下来,做出一下讲解:最先执行的方法是Awake,这是生命周期的开始,用于进行激活时的初始化代码,一般可以在这个地方将当前脚本禁用:this.enable=false,如果这样做了,则会直接跳转到OnDisable方法执行一次,然后其它的任何方法,都将不再被执行。
如果当前脚本处于可用状态,则正常的执行顺序是继续向下执行OnEnable,当然我们可以在另外一个脚本中实现这个脚本组件的启动:this.enab=true;
再向下执行,会进行一个判断,如果Start方法还没有被执行,则会被执行一次,如果已经被执行了,则不会再被执行。这是个什么意思呢?我们可以在某个脚本中将组件禁用this.enable=false,再启用时会转到OnEnable处执行,这时继续向下走,发现Start执行过了,将不再被执行。比如说:第一次启用时,将怪物的初始位置定在了(0,0,0)点,然后怪物可能会发生了位置的变换,后来被禁用了,再次启用时,不会让怪物又回到初始的(0,0,0)位置。
继续向后执行,就是Update了,然后是FixUpdate,再然后是LateUpdate,如果后面写了Reset,则会又回到Update,在这4个事件间可以进行循环流动。
再向后执行,就进入了渲染模块(Rendering),非常重要的一个方法就是OnGUI,用于绘制图形界面。当然,如果你使用了NGUI,这个生命周期的事情你就不用考虑了。
再向后,就是卸载模块(TearDown),这里主要有两个方法OnDisable与OnDestroy。当被禁用(enable=false)时,会执行OnDisable方法,但是这个时候,脚本并不会被销毁,在这个状态下,可以重新回到OnEnable状态(enable=true)。当手动销毁或附属的游戏对象被销毁时,OnDestroy才会被执行,当前脚本的生命周期结束。
 
特别要强调的是:这里虽然可以使用C#来写代码,但是这个类构造对象的生命周期,与MonoBehaviour的生命周期,是完全不同的。
 
可以通过如下示例:对脚本进行验证(两个脚本添加到同一个游戏对象上):
脚本1Monster1:
void OnBecameInvisible()
    {
        Debug.Log("invisible");
}

    void OnBecameVisible()
    {
        Debug.Log("visible");
    }
脚本2MonsterController:
    void Awake()
    {
        Debug.Log("awake");
        }

    void OnEnable()
    {
        Debug.Log("enable");
    }

    void Start()
    {
        Debug.Log("start");
    }

    void Update()
    {
        Debug.Log("update");
    }

    void OnGUI()
    {
        Debug.Log("gui");
    }
    void OnDisable()
    {
        Debug.Log("disable");
    }

    void OnDestroy()
    {
        Debug.Log("destroy");
    }
 
事件函数的执行顺序
Unity 脚本中有许多按预设顺序以脚本身份运行的事件函数。其执行顺序如下:
 
加载第一个场景
启动场景时调用这些函数(为场景中的每个对象调用一次)。
Awake: 始终在调用任何 Start 函数之前和实例化预设之后调用此函数。(如果游戏对象 (GameObject) 在启动期间处于非活动状态,则直到其处于活动状态时或调用添加至其本身的任何脚本中的函数时,再调用 Awake 函数。)红字部分是图中没有提到的,特别需要注意!!!绿色的部分通关测试是不正确的
OnEnable: (仅当对象 (Object) 处于活动状态时调用此函数):程序会在启用该对象后立即调用此函数。上述现象会在创建了实例化的 MonoBehaviour 后发生,例如加载了级别或对含脚本组件的游戏对象 (GameObject) 进行实例化后。
 
第一帧更新之前
Start: 只要启用脚本实例,即可在更新第一帧之前调用 Start 函数。
 
插值帧
OnApplicationPause: 程序检测到暂停时,会在帧的结尾处调用此函数,这在常规帧更新期间很有效。调用 OnApplicationPause后,程序将运行另一帧来显示提示暂停状态的图形。
 
更新顺序
有几个不同的事件有助于追踪游戏逻辑与交互、动画、相机位置等内容。常用的方法是运行Update() 函数中的大部分任务,但也可使用其他函数。.
 
FixedUpdate: 通常,FixedUpdate() 的调用频率高于 Update()。如果帧速率较低,则可在一帧中多次调用此函数,如果帧速率较高,则可能完全无法在帧间调用此函数。程序调用 FixedUpdate() 后将立即执行所有物理计算和更新。在 FixedUpdate() 中应用移动计算时,无需将您的值与 Time.deltaTime 相乘。这是因为,程序是在可靠的计时器上调用FixedUpdate(),与帧速率无关。
Update: 在每帧上调用一次 Update() 函数。它是用于帧更新的主要 workhorse 函数。
LateUpdate: 完成 Update() 调用后,在每帧上调用 LateUpdate()。Update() 中执行的所有计算都将在 LateUpdate() 开始之前结束。LateUpdate() 的常规使用记录由第三人称相机跟踪。如果在 Update() 中移动和旋转角色,则可在 LateUpdate() 中计算所有相机移动和旋转。这将确保在相机跟踪其位置之前完整移动该角色。
 
渲染
OnPreCull: 在相机剔除场景之前调用此函数。相机可见的对象取决于剔除。OnPreCull 函数调用发生在剔除之前。
OnBecameVisible/OnBecameInvisible: 在对象对于相机可见/不可见时调用此函数。
OnWillRenderObject: 如果对象可见,则为每个相机调用一次此函数。
OnPreRender: 在相机开始渲染场景之前调用此函数。
OnRenderObject: 在完成所有常规场景渲染后调用此函数。此时,可使用 GL 类或 Graphics.DrawMeshNow 绘制自定义几何图形。
OnPostRender: 在相机完成场景渲染后调用此函数。
OnRenderImage(仅限专业版): 在完成场景渲染后调用此函数,以便对屏幕图像进行后处理。
OnGUI: 在每帧上多次调用此函数,以响应 GUI 事件。程序首先将处理 Layout 和 Repaint 事件,然后再处理每个输入事件的 Layout 和 keyboard/鼠标事件。
OnDrawGizmos 用于在场景视图中绘制小图示 (Gizmos),以实现可视化目的。
 
协同程序
正常的协同程序更新是在返回 Update 函数之后运行。协同程序是可自行停止运行 (yield),直到给定的 YieldInstruction 结束再继续运行的函数。 协同程序 (Coroutines) 的不同用途:
yield; 在下一帧上调用所有 Update 函数后,协同程序将继续运行。
yield WaitForSeconds(2); 在指定的时间延迟之后,为此帧调用所有 Update 函数之后继续运行
yield WaitForFixedUpdate(); 在所有脚本上调用所有 FixedUpdate 后继续运行
yield WWW 完成 WWW 下载后继续运行。
yield StartCoroutine(MyFunc); 连接协同程序,并等待 MyFunc coroutine 首先结束。
 
对象 (Object) 被销毁时
OnDestroy: 完成所有帧更新后,在当前对象的最后一帧上调用此函数(可能为响应 Object.Destroy 或在关闭场景时销毁此对象)。
 
退出时
程序将在场景的所有活动对象上调用这些函数:
OnApplicationQuit: 在退出应用程序之前,程序会在所有游戏对象上调用此函数。在编辑器中,用户停止播放模式时,程序将调用此函数。在网页播放器中,此函数会在网页视图关闭时调用。
OnDisable: 此函数会在行为被禁用或不活动时调用。
 
综上所述,任何给定脚本的执行顺序为:
调用所有 Awake
调用所有 Start
同时进行(朝向可变增量时间)
所有 FixedUpdate 函数
物理模拟
OnEnter/Exit/Stay 触发函数
OnEnter/Exit/Stay 碰撞函数
 
刚体插值应用 transform.position 和旋转
OnMouseDown/OnMouseUp 等事件
所有 Update 函数
将动画优化为高级、混合并应用动画,以进行变换
所有 LateUpdate 函数
渲染
 
提示
协同程序在所有 Update 函数结束后运行。

第5单元: 核心类继承关系(4课时)
GameObject 游戏物体:是Unity场景中所有实体的基类。
常用变量方法等注释如下截图:

重点函数:课题批注。

Component 组件:是一切附加到游戏物体的基类。

重点方法:课堂批注。
Transform 变换:物体的位置、旋转和缩放。场景中的每一个物体都有一个Transform。用于储存并操控物体的位置、旋转和缩放。每一个Transform可以有一个父级,允许你分层次应用位置、旋转和缩放。可以在Hierarchy面板查看层次关系。他们也支持计数器(enumerator),因此你可以使用循环遍历子物体。

Rigidbody 刚体:通过物理模拟控制一个物体的位置。Rigidbody组件控制物体的位置 - 它使物体在重力影响下下落,并可计算物体将怎样响应碰撞。当操作刚体参数的时候,你应该在FixedUpdate函数中使用它,物理模拟以离散的时间步执行。FixedUpdate函数在每一步之前被立即调用。
使用刚体注意事项:
如果你的模拟看起来像慢动作并且不真实: 这是缩放的问题。如果你的游戏世界非常大,所以的东西将显示移动非常慢,确保你所有的模型为真实世界大小。例如,一个汽车应该有4米长,一个角色约2米高。物体以相同的加速度下落,不论大或小,重或轻。如果你的游戏世界有较大的缩放,物体仍以相同的加速度下落,但是因为所有的物体都比较大,物体的下落显得就比较慢。
Collider 碰撞器:所有碰撞器的基类。

Behavior:是可以被启用或禁用的组件。

Renderer 渲染器:所有渲染器的一般功能。渲染器是使物体显示在屏幕上。对于任何游戏物体或组件它的渲染器可以通过渲染器属性来访问。使用这个类可访问任意物体,网格或粒子系统的渲染器。渲染器可以禁用,使物体不可见(见enabled)。并且材质可以通过它访问和修改(见material)。

Component派生类Transform、Rigidbody、Collider、Behavior、Renderer都继承了组件的成员和方法。
Mesh类:一个允许通过脚本来创建和修改meshes的类。网格(meshes)包括顶点和多个三角形数组。三角形数组仅仅是顶点的索引数组,每个三角形包含三个索引。每个顶点可以有一条法线,两个纹理坐标,及颜色和切线。虽然这些是可选的,但是也可以去掉。所有的顶点信息是被储存在单独的同等规格的数组中,所以如果你的网格(mesh)有10个顶点,你同样应该有大小为10的数组来存储法线和其它属性。

大概有3件事情是你想要使用可修改的网格。

  1. 新建立一个网格 :应该总是按照这个顺序来做:
    1)为顶点数组赋值
    2)为三角形数组赋值
    代码如下:
    using UnityEngine;
    using System.Collections;

public class example : MonoBehaviour {
public Vector3[] newVertices;
public Vector2[] newUV;
public int[] newTriangles;
void Start() {
Mesh mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
}
}

  1. 每帧修改定点属性
    1)获取顶点数组
    2)修改它们
    3)把它们放回网格
    代码如下:
    using UnityEngine;
    using System.Collections;

public class example : MonoBehaviour {
void Update() {
Mesh mesh = GetComponent<MeshFilter>().mesh;
Vector3[] vertices = mesh.vertices;
Vector3[] normals = mesh.normals;
int i = 0;
while (i < vertices.Length) {
vertices[i] += normals[i] * Mathf.Sin(Time.time);
i++;
}
mesh.vertices = vertices;
}
}

  1. 连续的改变网格的三角形数组值和顶点值
    1)使用Clean刷新
    2)赋予顶点值和其他属性
    3)赋予索引值
    代码如下:
    using UnityEngine;
    using System.Collections;

public class example : MonoBehaviour {
public Vector3[] newVertices;
public Vector2[] newUV;
public int[] newTriangles;
void Update() {
Mesh mesh = GetComponent<MeshFilter>().mesh;
mesh.Clear();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
}
}
注意:调用Clean函数在赋予新的顶点值和三角形索引值之前是非常重要的,Unity总是检查三角形的索引值,判断它们是否超出边界。调用Clear函数后,给顶点赋值,再给三角形数组赋值,以确保没有超出数组的边界。

Material 材质:材质类。此类暴露了一个材质的所有属性,允许对他们进行动画处理,也可以用它来设置自定义Shader属性,但是无法通过监视面板访问属性。
为了获得一个对象使用的材质,可以使用 Renderer.material 属性:

Light类:用于灯光组件的脚本接口。使用这个控制Unity灯光的各个方面。这个属性完全匹配显示在检视面板中的值。通常灯光是在编辑器中被创建,但是有时通过脚本创建灯光。

Resources类:允许你按照它们的路径名查找并加载物体。所有位于Assets文件夹下名为"Resources"的文件夹中的资源,都可以Resources.Load 函数访问。
在Unity中通常不需要使用路径名来访问资源,相反你可以通过声明一个成员变量来暴露一个资源的引用,然后在检视面板中指定它。使用这个技巧的时候Unity可以在构建的时候自动计算哪个资源被使用。这从根本上最大限度地减少了实际用于游戏的资源的尺寸。当你放资源在"Resources"文件夹中时这个不会这么做,因此所有在"Resources"文件夹中的资源都将被包含在游戏中。
老版本API VS 新版本API

Time 时间:从Unity获取时间信息的接口。

Application 应用程序:访问应用程序的运行时数据。

脚本生命周期

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!