MonoBehaviour Lifecycle(生命周期/腳本執行順序)


腳本執行順序

前言

搭建一個示例來驗證Unity腳本的執行順序,大概測試以下部分:

  • 物理方面(Physics)
  • 渲染(Scene rendering)
  • 輸入事件(InputEvent)

流程圖

Unity文檔:https://docs.unity3d.com/Manual/ExecutionOrder.html

原圖地址:https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg

測試場景

搭建場景

示例下載:https://github.com/zhaoqingqing/blog_samplecode/raw/master/unity-framework/monobehaviour_lifecycle/monobehaviour_lifecycle.unitypackage

根據上圖中的腳本生命周期,我編寫三個腳本來測試部分階段的生命周期:

  • Logs.cs 輸出日志(可選)
  • TestInputEvent.cs(Input輸入事件)
  • TestPhysicOrder.cs(物理事件執行順序)
  • TestSceneRender.cs(Render順序)

創建一個空的場景,創建三個Gameobject,每個gameobject上分別綁上要測試的腳本。每次測試不同的功能,分別激活不同的gameobject

打印調用堆棧腳本

可以打印調用方法的堆棧,包括方法名,文件名

github:https://github.com/zhaoqingqing/blog_samplecode/blob/master/unity-framework/monobehaviour_lifecycle/Logs.cs

using System;
using System.Diagnostics;

public class Logs  {

    /// <summary>
    /// 打印調用者的方法名
    /// </summary>
    public static void DoLog()
    {
        StackTrace st = new StackTrace(true);
        //獲取當前調用的方法名
        StackFrame stackFrame = st.GetFrame(1);
        //var callInfo = string.Format("{0}:{1}.{2}",stackFrame.GetFileName(),stackFrame.GetFileLineNumber(),stackFrame.GetMethod().Name);
        var callInfo = stackFrame.GetMethod().Name.ToString();
        DoLog(callInfo);
    }

    public static void DoLog(string szMsg, params object[] args)
    {
        string log = string.Format("[{0}]{1}", DateTime.Now.ToString("HH:mm:ss.ffff"), string.Format(szMsg, args));
        UnityEngine.Debug.Log(log);
    }
}

物理測試

測試腳本

測試腳本中寫了Unity的各個腳本函數,大致內容如下:

github:https://github.com/zhaoqingqing/blog_samplecode/blob/master/unity-framework/monobehaviour_lifecycle/TestPhysicOrder.cs

using System;
using UnityEngine;
using System.Collections;

public class TestPhysicOrder : MonoBehaviour
{
    // Reset to default values
    public void Reset()
    {
        Logs.DoLog();
    }

    // Awake is called when the script instance is being loaded
    public void Awake()
    {
        StartCoroutine(YieldOneFrame());
        StartCoroutine(YieldEndOfFrame());
        StartCoroutine(YieldWaitForFixedUpdate());
        Logs.DoLog();
    }

    // This function is called when the object becomes enabled and active
    public void OnEnable()
    {
        Logs.DoLog();
    }

    // Use this for initialization
    void Start()
    {
        Logs.DoLog();
    }

    // This function is called every fixed framerate frame, if the MonoBehaviour is enabled
    public void FixedUpdate()
    {
        Logs.DoLog();
    }

    // Update is called once per frame
    void Update()
    {
        Logs.DoLog();
    }

    IEnumerator YieldWaitForFixedUpdate()
    {
        yield return new WaitForFixedUpdate();
        Logs.DoLog("WaitForFixedUpdate");
    }

    IEnumerator YieldOneFrame()
    {
        yield return 1;
        Logs.DoLog("YieldOneFrame");
    }

    IEnumerator YieldEndOfFrame()
    {
        yield return new WaitForEndOfFrame();
        Logs.DoLog("YieldEndOfFrame");
    }

    // LateUpdate is called every frame, if the Behaviour is enabled
    public void LateUpdate()
    {
        Logs.DoLog();
    }

    // This function is called when the behaviour becomes disabled or inactive
    public void OnDisable()
    {
        Logs.DoLog();
    }

    // This function is called when the MonoBehaviour will be destroyed
    public void OnDestroy()
    {
        Logs.DoLog();
    }

    // Sent to all game objects when the player gets or looses focus
    public void OnApplicationFocus(bool focus)
    {
        Logs.DoLog();
    }

    // Sent to all game objects when the player pauses
    public void OnApplicationPause(bool pause)
    {
        Logs.DoLog();
    }

    // Sent to all game objects before the application is quit
    public void OnApplicationQuit()
    {
        Logs.DoLog();
    }

}

測試結果

開始部分截圖

結束部分截圖

Render測試

測試腳本

github:https://github.com/zhaoqingqing/blog_samplecode/blob/master/unity-framework/monobehaviour_lifecycle/TestSceneRender.cs

using System;
using UnityEngine;
public class TestSceneRender : MonoBehaviour
{

    // OnPreCull is called before a camera culls the scene
    public void OnPreCull()
    {
        Logs.DoLog();
    }

    // OnPreRender is called before a camera starts rendering the scene
    public void OnPreRender()
    {
        Logs.DoLog();

    }

    // Callback that is sent if an associated RectTransform has it's dimensions changed
    public void OnRectTransformDimensionsChange()
    {
        Logs.DoLog();
    }

    // Callback that is sent if an associated RectTransform is removed
    public void OnRectTransformRemoved()
    {
        Logs.DoLog();
    }

    // OnRenderImage is called after all rendering is complete to render image
    public void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Logs.DoLog();
    }

    // OnRenderObject is called after camera has rendered the scene
    public void OnRenderObject()
    {
        Logs.DoLog();
    }


    // OnWillRenderObject is called once for each camera if the object is visible
    public void OnWillRenderObject()
    {
        Logs.DoLog();
    }

    // Implement this OnDrawGizmosSelected if you want to draw gizmos only if the object is selected
    public void OnDrawGizmos()
    {
        Logs.DoLog();
    }

    // OnGUI is called for rendering and handling GUI events
    public void OnGUI()
    {
        Logs.DoLog();
    }
}

測試結果

當把測試腳掛在Cube或者Camera上,會執行的函數是不相同的。

綁在Camera上

綁在Cube上


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM