1.脚本的生命周期

脚本的生命周期

目录

  1. 脚本生命周期图
  2. Update()、Start()、Awake()简介
  3. 脚本的协程

在这里插入图片描述

Update、Start、Awake
  1. FixedUpdate()
    固定更行
  2. Update()
    更新
  3. LateUpdate()
    晚于更新
    • 其中,FixedUpdate()和Update(),在MonoBehavior启用时,在每一帧都被调用,都是用来更新的。
    但是Update()每一帧的时间不固定,即第一帧与第二帧的时间t1和第三帧与第四帧的时间t2不一定相同。FixedUpdate()每帧与每帧之间相差的时间是固定的。Update受当前渲染的物体影响,这与当前场景中正在被渲染的物体有关(比如人物的面数,个数等),时快时慢,帧率会变化,所有Update被调用的时间间隔就会发生变化。但是FixedUpdate则不受帧率的变化影响,它以固定的时间间隔来被调用。
    所以一些物理属性的操作应该放在FIxedUpdate中进行操作,比如Force,collider,Rigidbody等,以及键盘鼠标的输入输出Input。这样可以让GameObject的物理表现更平滑,更加接近现实。其中FixedUpdate的时间间隔可以在Edit->Project Setting->time->Fixed timestep 中进行修改。
    • 其中Update和LateUpdate
    LateUpdate是在所有的Update函数调用完后被调用。可以用于调整脚本执行顺序。例如:当在Update中设置物体的移动时,就可以用LateUpdate来实现跟随物体的相机。因为Update的先后顺序是随机的,如果相机先Update而物体还未移动,则下一帧物体先Update时,就会出现瞬移的情况;以及物体之间跟随的情况,如果跟随的物体使用Update来更新的话,跟随的物体就容易出现抖动。如果是在LateUpdate中跟随的话就只会等所有的Update执行完成后的最后位置再进行更新,就防止了抖动。
    Update和LateUpdate不适合用于更新频率要求比较稳定的物理系统。
  4. Awake()
    在脚本实例化的时候就会被调用(不论是否enable),在脚本的生命周期中只会被调用一次。
  5. Start()
    Start是脚本第一次enable之后、在Update之前调用的,Start在脚本的生命周期中也只可能被调用一次。
    • Awake是在所有对象实例化之后,所以可以在Awake中给各个组件之间添加引用关系。但是不同对象之间的Awake的顺序是随机的。
    • Start需要在enable之后,所以通过Start和Awake的顺序关系,可以把初始化的操作放在Awake中,这样可以保证Start开始之前,所需要的初始化操作是已经完成的了。
脚本的协程

脚本更新
Unity只支持单线程,但是可以通过C#来模拟多线程。
举例来说:现在需要每1秒就创建一个游戏对象,可以通过协程的概念,使用for循环来写。使用StartCoroutine()方法即可启用一个协程任务。在循环中,使用yield return 来告诉unity需要等待多久才执行下一个循环。

//每隔一秒新建一个cube
public class Script_04_04 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(CreateCube());
    }
    IEnumerator CreateCube()
    {
        for(int i = 0; i < 10; i++)
        {
            GameObject.CreatePrimitive(PrimitiveType.Cube).transform.position = Vector3.one * i;
            yield return new WaitForSeconds(1f);
        }
   	 }
 }

但是协程代码在实际应用中容易出错,最好不要大量使用。

停止协程任务
在协程任务启动的过程中,如果需要重新启动它,必须停掉之前的协程。使用StartCoroutine()返回这个协程对象,需要停止的时候使用StopCoroutine()。

//每隔一秒新建一个cube
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Script_04_04 : MonoBehaviour
{
   
    IEnumerator CreateCube()
    {
        for(int i = 0; i < 10; i++)
        {
            GameObject.CreatePrimitive(PrimitiveType.Cube).transform.position = Vector3.one * i;
            yield return new WaitForSeconds(1f);
        }
    }
    private Coroutine m_Coroutine = null;
    private void OnGUI()
    {
        if (GUILayout.Button("startcoroutine"))
        {
            if (m_Coroutine != null)
            {
                StopCoroutine(m_Coroutine);
            }
            m_Coroutine = StartCoroutine(CreateCube());
        }
        if (GUILayout.Button("stopcoroutine"))
        {
            if (m_Coroutine != null)
            {
                StopCoroutine(m_Coroutine);
            }
        }
    }
}

使用OnGUI显示FPS
FPS的含义就是一秒钟Update被执行了多少次。所以只需要在Update()中获取每一秒所执行的次数,最终在OnG()方法中将FPS打印在平面左上角。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Script_04_06 : MonoBehaviour
{
    public float updateInterval = 0.5F;
    private float accum = 0;
    private int frames = 0;
    private float timeleft;
    private string stringFps; 
    void Start()
    {
        timeleft = updateInterval;
    }
    void Update()
    {
        timeleft -= Time.deltaTime;//deltaTime为运行一帧所需要的时间
        accum += Time.timeScale / Time.deltaTime;//timeScale为运行速度
        ++frames;
        if (timeleft <= 0.0)
        {
            float fps = accum / frames;
            string format = System.String.Format("{0:F2} FPS", fps);
            stringFps = format;
            timeleft = updateInterval;
            accum = 0.0f;
            frames = 0;
        }
    }
    private void OnGUI()
    {
        GUIStyle gUIStyle = GUIStyle.none;
        gUIStyle.fontSize = 30;
        gUIStyle.normal.textColor = Color.red;
        gUIStyle.alignment = TextAnchor.UpperLeft;
        Rect rt = new Rect(40, 0, 100, 100);
        GUI.Label(rt, stringFps, gUIStyle);
    }
}

在这里插入图片描述
tips:1:“timeScale不会影响Update和LateUpdate的执行速度”
2:“FixedUpdate是根据时间来的,所以timeScale只会影响FixedUpdate的速度”

参考文献 《Unity3D游戏开发 第二版》

脚本生命周期函数是指在Unity中,脚本对象依附的GameObject对象从出生到消亡的整个生命周期中会通过反射自动调用的一些特殊函数。这些函数按照特定的顺序执行,以完成不同的任务和功能。 在Unity中,脚本生命周期函数的执行顺序如下: 1. Awake函数:在脚本实例的生存期内,Unity仅调用一次Awake函数。这个函数用于初始化脚本和组件,并且可以在该函数中进行一些预处理的操作。需要注意的是,Unity调用每个GameObject的Awake函数的顺序是不确定的,可以通过人为干涉来保证程序的正确性和稳定性。 2. Start函数:Start函数在Awake函数之后调用,用于在脚本被启用时执行一次,通常用于初始化脚本的一些变量或资源。和Awake函数不同的是,Start函数在每次场景加载时都会被调用。 3. Update函数:Update函数在每一帧都会被调用,用于处理游戏逻辑的更新操作。在这个函数中,可以实现脚本的主要功能,例如控制游戏对象的移动、更新游戏状态等。 4. FixedUpdate函数:FixedUpdate函数和Update函数类似,也会在每一帧被调用,但不同之处在于FixedUpdate函数是固定的时间间隔被调用。这个函数适合处理物理相关的操作,例如应用力、更新刚体等。 5. LateUpdate函数:LateUpdate函数在所有Update函数执行完毕后调用,用于在场景更新完毕后执行一些后续操作。通常用于处理相机跟随、更新UI等。 6. OnEnable函数:当脚本组件被启用时调用一次。可以在这个函数中进行一些初始化操作,例如注册事件、开启协程等。 7. OnDisable函数:当脚本组件被禁用时调用一次。可以在这个函数中进行一些资源释放或清理的操作,例如取消注册事件、关闭协程等。 8. OnDestroy函数:当脚本对象被销毁时调用一次。可以在这个函数中进行一些最终的清理工作,例如释放资源、取消引用等。 需要注意的是,这些生命周期函数的执行顺序是固定的,并且可以通过重写这些函数来实现自定义的行为和逻辑。每个生命周期函数的执行次数和作用会根据具体的情况而有所不同,但上述提到的函数都是常用的生命周期函数,对于控制游戏对象的行为和状态具有重要的作用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值