Unity 快速進入運行模式( Fast Enter Play Mode)

介紹

你是否會覺得有時候進入運行模式的時候非常慢壶谒,這是因為 Unity 需要保證你每次進入游戲的時候都是一樣的膳沽,即使在退出游戲的時候你沒有進行還原操作。當(dāng)然這只是一部分原因陨界,還有 Start 內(nèi)邏輯復(fù)雜或者腳本過多等原因痛阻。下面介紹如果減少 Unity 自己的初始化操作阱当,下面內(nèi)容基本翻譯于 Configurable Enter Play ModeDomain Reloading

進入運行模式的配置

??運行模式可以讓你的項目直接在編輯器中運行录淡,運行效果跟你將它打包出來之后的運行效果一樣油坝,在運行模式你所做的修改在退出該模式之后都會被還原(這里只包括場景中的修改,如果你在代碼中修改了一個資源彼水,比如一個材質(zhì)球的基色凤覆,那么不會被還原)。
??這是因為在開始運行之后慈俯,Unity 做了兩件事情來保證它看起來是跟打包之后運行的效果一樣:

  • 它重置了所有的腳本狀態(tài)(也叫作域重載)
  • 它重新加載了這個場景

??這兩個操作會消耗一些時間拥峦,并且當(dāng)你的腳本和場景更復(fù)雜的時候略号,它們耗時也更長。
??提高快速進入突梦、退出運行模式的能力在開發(fā)中是非常重要的羽利。更快的進入、退出運行模式也意味著快速的測試項目中的改動娃闲。
??因為在開發(fā)中快速迭代是非常重要的匾浪,但這種重置有可能成為速度的瓶頸蛋辈,所以 Unity 提供了一種方式可以讓開發(fā)者自己選擇在進入運行模式的時候要不要域重載或者場景重載。
??下面一張圖描述了禁用域重載或者場景重載的影響:


禁用域重載或者場景重載的影響

如何配置

在 2019.3 (或許更低也可以,我試過 2018.4挂洛,是沒有這個選項的)以上的 Unity 版本中眠砾,找到 Edit->Project Settings->Editor->Enter Play Mode Settings

Enter Play Mode Settings

  • 三個選擇框都不勾励堡,其實相當(dāng)于將三個都勾堡掏,也就是會啟用域重載和場景重載
  • 只勾選第一個泉唁,則代表不啟用域重載和場景重載
  • 勾選第一個,下面兩個二選一則代表只啟用一種重載

這個功能還在試驗階段扮休,后面還有可能會進行改動拴鸵。

域重載

??域重載重置你的腳本狀態(tài),它默認(rèn)是啟用的(上面三個勾默認(rèn)是都不勾)八堡。它會提供一個完全干凈的腳本初始化狀態(tài)秕重,會重置所有的靜態(tài)變量厉膀,將所有 Handler 里面注冊的方法都清空。這樣可以保證在編輯器中每一次運行都跟將項目打包出來后第一次運行一樣凳兵。
??這會耗費一定時間企软,隨著場景和腳本的復(fù)雜程度增加仗哨,時間也會增加,不利于項目的快速迭代萨醒,所以 Unity 提供了關(guān)閉域重載的方法苇倡。
??當(dāng)關(guān)閉了域重載之后,進入運行模式的速度會變快晓褪,因為 Unity 不會再做初始化操作涣仿。這時就需要你自己手動完成初始化,你需要自己添加一些代碼來保證腳本中某些狀態(tài)在運行時會被還原埃元。
??當(dāng)域重載被禁用時媚狰,當(dāng)你更新腳本或者重新導(dǎo)入時 Unity 依然會根據(jù)你的 auto-refresh settings 刷新腳本狀態(tài)崭孤。

在禁用域重載之后該做什么?

??你需要調(diào)整腳本中的靜態(tài)變量和靜態(tài)事件 Handler 來保證在剛進入運行模式的時候腳本狀態(tài)是正確的遗锣。

靜態(tài)變量

??當(dāng)域重載被禁用的時候嗤形,靜態(tài)變量的值將不會自動恢復(fù)成原來的值,你需要明確的寫出讓它恢復(fù)的代碼笔咽。
??以下面的代碼為例叶组,其中有一個靜態(tài)的變量 counter历造,當(dāng)用戶按下了 Jump 鍵的時候它會自增。當(dāng)沒有禁用域重載的時候侣监,每次運行它的值都是 0橄霉;當(dāng)禁用域重載的時候荒典,每次運行時它的值都是上一次運行結(jié)束時的值。

using UnityEngine;

public class StaticCounterExample : MonoBehaviour
{
// this counter will not reset to zero when Domain Reloading is disabled
    static int counter = 0; 

    // Update is called once per frame
    void Update()
    {
            if (Input.GetButtonDown("Jump"))
            {
                    counter++;
                    Debug.Log("Counter: " + counter);
            }
    }
}

?? 為了保證即使在禁用了域重載的時候覆糟,counter 依然能被正確的歸零滩字,我們要使用 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] 標(biāo)簽來明確的對 counter 初始化御吞。

using UnityEngine;

public class StaticCounterExampleFixed : MonoBehaviour
{
    static int counter = 0;

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
    static void Init()
    {
            Debug.Log("Counter reset.");
            counter = 0;   
    }

    // Update is called once per frame
    void Update()
    {
            if (Input.GetButtonDown("Jump"))
            {
                counter++;
                Debug.Log("Counter: " + counter);
            }
    }
}

靜態(tài)事件處理器

??這里的靜態(tài)事件處理器是由 Static event handlers 翻譯而來的陶珠。舉個例子,就是 public static event Action TestActionHandler;
??當(dāng)禁用域重載的時候诀蓉,Unity 不會在運行模式退出的時候把靜態(tài)事件處理器里面已經(jīng)注冊的方法刪除渠啤。這會導(dǎo)致回調(diào)函數(shù)的多次執(zhí)行添吗,比如在第一次運行的時候碟联,回調(diào)函數(shù)被正常注冊,第二次運行的時候玄帕,處理器(Handler)里面已經(jīng)有這個回調(diào)函數(shù)了裤纹,但它又被注冊了一遍,所以當(dāng)處理器去廣播的時候(也就是 Handler?.Invoke()的時候)锡移,該回調(diào)函數(shù)會被執(zhí)行兩遍漆际。
??以下面的代碼為例奸汇,我們在 Start 里面給 Application.quitting 注冊了一個回調(diào)函數(shù)往声,注意這里的 Application.quitting 是靜態(tài)的浩销,它的聲明如下:

public static event Action quitting;

??當(dāng)域重載沒被禁用的時候听哭,Unity 會在運行的時候自動清空 Application.quitting陆盘,所以每次運行回調(diào)函數(shù)都只會被注冊一次普筹。
??當(dāng)域重載被禁用的時候,Application.quitting 將不會被自動清空隘马√溃看下面的例子,第一次運行結(jié)束的時候祟霍,Quitting 會被打印一次杏头;第二次運行結(jié)束的時候 Quitting 會被打印兩次......但實際上我們都希望每次運行結(jié)束后, Quitting 都只會被打印一次沸呐。

using UnityEngine;
public class StaticEventExample : MonoBehaviour
{
    void Start()
    {
            Debug.Log("Registering quit function");
            Application.quitting += Quit;
    }


    static void Quit()
    {
        Debug.Log("Quitting!");
    }
}

??為了保證即使在域重載被禁用的情況下醇王,我們也能正確的使用靜態(tài)事件處理器,我們需要使用 [RuntimeInitializeOnLoadMethod] 標(biāo)簽崭添,并且明確的寫出要刪除已經(jīng)被注冊的方法。用法如下:

using UnityEngine;
public class StaticEventExampleFixed : MonoBehaviour
{
    [RuntimeInitializeOnLoadMethod]
    static void RunOnStart()
    {
            Debug.Log("Unregistering quit function");
            Application.quitting -= Quit;
    }

    void Start()
    {
            Debug.Log("Registering quit function");
            Application.quitting += Quit;
    }

    static void Quit()
    {
        Debug.Log("Quitting the Player");
    }
}

??對于運行時腳本(非編輯器相關(guān)),你需要使用 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] 來手動初始化靜態(tài)變量和靜態(tài)事件處理器呼渣。
??對于編輯器腳本棘伴,你需要使用 [InitializeOnEnterPlayMode] 來初始化靜態(tài)變量或者靜態(tài)事件處理器。

筆者補充

    static void Quit()
    {
        Debug.Log("Quitting!");
    }

??上面例子中的 Quit 這個回調(diào)方法也是靜態(tài)的屁置,但這并不影響焊夸,加不加這個靜態(tài)結(jié)果都一樣,依然會被注冊多次蓝角,因為起決定性作用是 Application.quitting 是靜態(tài)的阱穗。
??它的聲明是 public static event Action quitting;,如果變成 public event Action quitting; 那么就不會被注冊多次使鹅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揪阶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子患朱,更是在濱河造成了極大的恐慌鲁僚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異冰沙,居然都是意外死亡侨艾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門拓挥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒋畜,“玉大人,你說我怎么就攤上這事撞叽。” “怎么了插龄?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵愿棋,是天一觀的道長。 經(jīng)常有香客問我均牢,道長糠雨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任徘跪,我火速辦了婚禮甘邀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘垮庐。我一直安慰自己松邪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布哨查。 她就那樣靜靜地躺著逗抑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寒亥。 梳的紋絲不亂的頭發(fā)上邮府,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音溉奕,去河邊找鬼褂傀。 笑死,一個胖子當(dāng)著我的面吹牛加勤,可吹牛的內(nèi)容都是我干的仙辟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胸竞,長吁一口氣:“原來是場噩夢啊……” “哼欺嗤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卫枝,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤煎饼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后校赤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吆玖,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡筒溃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沾乘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怜奖。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖翅阵,靈堂內(nèi)的尸體忽然破棺而出歪玲,到底是詐尸還是另有隱情,我是刑警寧澤掷匠,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布滥崩,位于F島的核電站,受9級特大地震影響讹语,放射性物質(zhì)發(fā)生泄漏钙皮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一顽决、第九天 我趴在偏房一處隱蔽的房頂上張望短条。 院中可真熱鬧,春花似錦才菠、人聲如沸茸时。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幔睬。三九已至翁锡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辖众。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工闹击, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妥畏,地道東北人智润。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像贤徒,于是被迫代替她去往敵國和親芹壕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容