一、了解幀的概念
游戲的本質就是一個死回圈
每一次回圈都會處理游戲邏輯 并 更新一次游戲畫面
之所以能看到畫面在動 是因為
切換畫面速度達到一定速度時
人眼就會認為畫面是動態且流暢的
一幀就是執行了一次回圈
Unity底層已經封裝好了這個死回圈
我們只需要利用Unity的生命周期函式的規則來執行游戲邏輯即可
FPS(Frames Per Second)
即每秒鐘幀數
一般我們說60幀30幀
意思是1秒更新60次、30次畫面
1s = 1000ms
60幀:1幀為 1000ms/60 ≈ 16.66ms
30幀:1幀為 1000ms/30 ≈ 33.33ms
游戲卡頓的原因:
跑1幀游戲邏輯的計算量過大,或者硬體性能過低,無法在一幀的時間內處理完所有游戲邏輯
二、生命周期函式的概念
所有繼承MonoBehavior的腳本 最終都會掛載到GameObject游戲物件上
生命周期函式就是該腳本物件依附的GameObject物件從出生到消亡整個生命周期中
會通過反射自動呼叫的一些特殊函式
Unity幫助我們記錄了一個GameObject物件依附了哪些腳本
會自動地得到這些物件,通過反射去執行一些固定名字的函式(就是生命周期函式)
三、生命周期函式
注意:
生命周期函式的訪問修飾符一般為private和protected
因為不需要在外部手動呼叫生命周期函式,都是Unity自動幫我們呼叫

3-1.Awake
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//當一個物件(自己這個類物件 而不是依附的GameObject)被創建時,會呼叫該生命周期函式
//作用:Awake是類似建構式的存在,我們可以在一個類物件剛被創建時,進行一些初始化操作
//Awake只會被執行一次
private void Awake()
{
//補充知識點:在Unity中列印資訊的兩種方式
//1.如果沒有繼承MonoBehaviour,可以使用debug.Log();
Debug.Log("我是列印的資訊");
Debug.LogWarning("警告!");
Debug.LogError("出錯了!");
//2.如果繼承了MonoBehaviour 有一個現成的方法可以實作列印
print("我是列印的資訊");
}
}
3-2.OnEnable
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//依附的GameObject物件每次被激活時 會被呼叫
//作用:想要當一個物件被激活時 進行一些邏輯處理,就可以寫在本函式中
private void OnEnable()
{
print("我依附的GameObject被激活了");
}
}

3-2.Start
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//從自己被創建出來后,第一次幀更新之前被呼叫
//作用:還是用于初始化資訊的,但是它相對Awake來說,要執行的晚一些
// 因為它是在物件進行幀更新之前才會被執行
//一個物件只會呼叫一次
private void Start()
{
print("我在第1幀更新前被執行");
}
}
3-4.FixedUpdate
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//固定間隔時間執行,間隔的時間可以設定
//作用:用于進行物理相關的更新(如碰撞檢測)
// 它是每一幀都會執行的,但是這里的幀和游戲幀有點不同
private void FixedUpdate()
{
print("我會固定間隔時間回圈執行");
}
}


3-5.Update
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//邏輯幀更新
//每秒更新多少次是可以設定的,如果不設定 默認會以最快的速度更新
//作用:用于處理游戲核心邏輯更新
private void Update()
{
print("我一幀被執行一次");
}
}
3-6.LateUpdate
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//每幀執行 于Update之后執行
//作用:一般用來處理攝像機位置更新相關內容
// 在Update和LateUpdate之間,Unity進行了一些處理,處理影片相關的更新
private void LateUpdate()
{
print("我每針都會被執行,但晚于Update");
}
}
3-7.OnDisable
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//依附的GameObject物件每次失活時被呼叫(物件被銷毀時也會被呼叫)
//作用:想要當一個物件失活時 進行一些邏輯處理,就可以寫在本函式中
private void OnDisable()
{
print("我依附的GameObject失活了");
}
}

3-8.OnDestroy
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//物件被銷毀時被呼叫(依附的GameObject物件被洗掉時)
private void OnDestroy()
{
print("我被銷毀了");
}
}
四、生命周期函式支持繼承和多型

Lesson1的腳本如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1 : MonoBehaviour
{
//把Awake寫成一個虛函式
protected virtual void Awake()
{
print("父類的Awake");
}
}
Lesson1Son的腳本如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson1Son : Lesson1
{
//可以重寫父類Lesson1的虛函式
protected override void Awake()
{
base.Awake();
print("子類的Awake");
}
}

運行:可以看到,父類的Awake和子類的Awake都被執行了,所以生命周期函式支持繼承和多型

五、補充:關于繼承Mono的類的建構式
要知道,雖然不建議在繼承MonoBehavior的類中寫建構式
但是不意味著不能寫,當在繼承MonoBehavior的類中寫無參建構式時
會發現在編輯模式下或者運行后,只要該腳本掛載在場景中,那么該無參建構式是會被自動執行
因為Unity的作業原理中提到的反射機制,實際上Unity通過反射幫助我們實體化了該腳本物件
既然要實體化那么肯定是需要new的,只不過Unity中不需要我們自己new繼承了MonoBehavior的類,只要掛載后Unity就幫助我們做了這件事
那么為什么不建議繼承MonoBehavior的類寫建構式呢?
1.Unity的規則就是,繼承MonoBehavior的腳本不能new只能掛載
2.生命周期函式的Awake是類似建構式的存在,當物件出生就會自動呼叫
3.寫建構式反而在結構上會破壞Unity設計上的規范
總結:
如果繼承MonoBehavior的腳本想要進行初始化相關,可以在Awake或者Start中進行,搞清這兩個生命周期函式的執行時機,根據需求選擇在哪里進行初始化,
切記!!繼承MonoBehavior的腳本不要new,不要new,不要new!!
六、補充:不同物件的宣告周期函式是在同一個執行緒中執行的嗎?
Unity中所有物件上掛載的生命周期函式都是在一個主執行緒中按先后執行的
Unity會主動把場景上的物件,物件上掛載的腳本都統統記錄下來,
在主執行緒的死回圈中,按順序按時機的通過反射,執行記錄的物件身上掛載的腳本的對應生命周期函式
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/499771.html
標籤:其他
上一篇:快速排序及優化
