unity基础简介(二)
monobehaviour是什么
前言
由于游戏的特殊性,多线程技术很难应用在游戏开发过程中,试想我们用另一个线程去控制物件,除非他们与其他事物没有任何交互,否则每一次交互都需要进行线程同步,即使你只是一个在背景里走来走去的无害NPC,与什么都不需要交互,但是为了避免玩家的显示中出现什么奇怪现象(比如步子迈大了),也必须要进行帧同步,让每一次update都需要线程同步,因此多线程技术大多无法用在游戏主体中,通常都是资源加载,网络通信等工作,游戏的大部分逻辑都运行在unity的主线程中,unity的主线程维持生命周期函数
unity生命周期
暂且不提动画,渲染和协程
Awake():在创建对象,比如实例化预制体后,Start函数之前执行(如果游戏对象在启动期间处于非活动状态,则在激活之后才会调用 Awake)
OnEnable():(仅在对象处于激活状态时调用)在启用对象后立即调用此函数。在创建 MonoBehaviour 实例时(例如加载关卡或实例化具有脚本组件的游戏对象时)会执行此调用。
Start:仅当启用脚本实例后,才会在第一次帧更新之前调用 Start。
当物体被实例化后,如果没有激活,则不调用函数,当实例化并激活后依次调用Awake,OnEnable,start,Awake和start只会被调用一次,但active和enable发生改变时OnEnable,OnDisEnable会被调用
在图中物理部分有自己的循环,它们的更新频率是一致的
FixedUpdate:调用 FixedUpdate 的频度常常超过 Update。如果帧率很低,可以每帧调用该函数多次;如果帧率很高,可能在帧之间完全不调用该函数。在 FixedUpdate 之后将立即进行所有物理计算和更新。在 FixedUpdate 内应用运动计算时,无需将值乘以 Time.deltaTime。这是因为 FixedUpdate 的调用基于可靠的计时器(独立于帧率)。
Update:每帧调用一次 Update。这是用于帧更新的主要函数。
LateUpdate:每帧调用一次 LateUpdate(在所有 Update 完成后)。LateUpdate 开始时,在 Update 中执行的所有计算便已完成。LateUpdate 的常见用途是跟随第三人称摄像机。如果在 Update 内让角色移动和转向,可以在 LateUpdate 中执行所有摄像机移动和旋转计算。这样可以确保角色在摄像机跟踪其位置之前已完全移动。
FixedUpdate与Update:
FixedUpdate:每帧调用而且每帧的时间间隔是固定的,不受帧率(FPS)影响。每一帧的时间是在Edit->Project Settings->Time面板中的Fixed Timestep设置,默认为0.02s,则0.02s为一帧也就是每帧之间的间隔是0.02s。
对于更新频率比较稳定的物理系统来说就合适放在FixedUpdate中处理
Update:每帧调用但是每帧的时间间隔不固定,受到帧率影响,而帧率(FPS)与电脑性能有关。
例如FPS是30,则每秒执行30帧,如果FPS是10,则每秒执行10帧。是不稳定的。
当有多个脚本时可以自定义相同周期函数的调用顺序,点击excution order
monobehaviour简介
可以看到monobehaviour的继承关系,继承自Object(这里是unity中的Object)可以让脚本被Destroy,Find或Instantiate,继承自Component可以让脚本被挂在游戏对象上,且可以获取游戏对象或其子对象的其他组件,也就是用的最多的GetComponent,还可以获取游戏对象的其他属性,具体可以F12查看声明,继承自MonoBehavior让脚本使用生命周期函数,并按照生命周期进行调用。
生命周期函数是如何被调用的
首先生命周期函数都是private,那么调用就需要使用反射,然而.net的反射机制开销很大,GetType需要搜寻类型,因此unity不可能使用这种方法,有人指出unity使用mono的api,它支持基于字符串查找方法,并将指针保存。
在unity源码中维护了一个PlayerLoop用于每帧循环,生命周期函数的调用依靠其中的延迟调用管理(DelayedCallManager),它提供计时能力,在一段时间后回调;提供顺序控制能力,在PlayerLoop其他阶段执行回调;提供取消回调功能
DelayedCallManager提供一下几种模式:
enum DelayedCallMode
{
kRunFixedFrameRate = 1 << 0,
kRunDynamicFram