Unity3d多場(chǎng)景編輯功能簡(jiǎn)介


Unity

5.3中新增加了多場(chǎng)景編輯功能刑桑,允許用戶將一個(gè)大場(chǎng)景以某種邏輯分割成多個(gè)小場(chǎng)景并方便的編輯和管理鳖目。這在某些情況下會(huì)比較有用洲敢,是對(duì)Unity編輯器

對(duì)場(chǎng)景編輯能力的一個(gè)重要提升败玉。本文將由Unity官方工程師張為蛀恩,為大家介紹一些多場(chǎng)景編輯的基本功能以及一些實(shí)例疫铜。

什么是多場(chǎng)景編輯

多場(chǎng)景編輯就是允許用戶在Unity編輯器中同時(shí)打開(kāi)多個(gè)場(chǎng)景,并對(duì)它們進(jìn)行編輯双谆。Unity提供了一系列的UI和Scripting APIs來(lái)管理這些場(chǎng)景壳咕。以下就是一個(gè)在Unity編輯器中進(jìn)行多場(chǎng)景編輯的一個(gè)實(shí)例。

什么是場(chǎng)景

在進(jìn)一步了解多場(chǎng)景編輯之前顽馋,我們先了解下什么是場(chǎng)景(Scene)谓厘。簡(jiǎn)而言之場(chǎng)景就是包含了游戲?qū)ο蟮囊粋€(gè)文件,比如Game objects寸谜,Components等竟稳。不過(guò)有一些對(duì)象可能一些用戶并不會(huì)太在意,那就是Scene Game managers熊痴。

Unity中有兩類(lèi)Game Managers:

一類(lèi)是Global Game Managers他爸。它們是全局的Game

managers,包括AudioManager果善、InputManager诊笤、PhysicsManager等。當(dāng)你在Unity5.3中發(fā)布你的游戲的

時(shí)候岭埠,你會(huì)發(fā)現(xiàn)在輸出目錄或者發(fā)布包里面會(huì)有個(gè)globalgamemanagers文件盏混,它包含了所有全局Game managers蔚鸥。

另一類(lèi)是Scene game managers。如果你將Editor Settings中的Asset Serialization選擇為”Force Text”模式许赃,并打開(kāi)一個(gè)已經(jīng)保存的*.unity場(chǎng)景文件止喷,你會(huì)發(fā)現(xiàn)前保存在文件最前面的就是SceneSettings、RenderSettings混聊、LightMapSettings和NavMeshSettings弹谁,它們就是每個(gè)場(chǎng)景都會(huì)有的Game managers。

為什么需要多場(chǎng)景編輯

首先將大場(chǎng)景分割成多個(gè)場(chǎng)景句喜,可以更好的支持場(chǎng)景的流式加載(Scene streaming)预愤;

其次可以更好地支持協(xié)同合作,尤其是在有源代碼版本管理的時(shí)候可以允許多人同時(shí)編輯而不會(huì)產(chǎn)生沖突咳胃;

再者支持卸載場(chǎng)景(Scene unloading)植康,在5.3之前用戶可以通過(guò)Application.LoadLevelAddtive()和Application.LoadLevelAdditiveAsync()動(dòng)態(tài)加載場(chǎng)景,但沒(méi)有對(duì)應(yīng)的Application.UnloadScene()展懈。而5.3中提供了場(chǎng)景卸載销睁,讓用戶可以更靈活的管理多個(gè)場(chǎng)景。

多場(chǎng)景編輯基本功能介紹

接下來(lái)我們看看Unity在5.3中具體提供了哪些多場(chǎng)景編輯的功能存崖。

Scene結(jié)構(gòu)

在5.3之前冻记,Unity中只有概念上的場(chǎng)景,而到5.3中我們引入了真正的Scene結(jié)構(gòu)来惧。它包含了name冗栗、path、isLoaded等變量供搀,同時(shí)也提供了IsValid()以及GetRootGameObjects()方法隅居。

Active Scene

在5.3中,我們引入了Active Scene(當(dāng)前場(chǎng)景)的概念趁曼。引入它的目的在于:

如果有多個(gè)場(chǎng)景同時(shí)打開(kāi)军浆,我們會(huì)選擇Active Scene的Scene game managers作為當(dāng)前的Scene game managers。比如在bake lightmapping的時(shí)候挡闰,我們會(huì)使用Active scene的LightMapSettings來(lái)bake當(dāng)前打開(kāi)的所有場(chǎng)景乒融。

在創(chuàng)建Game object的時(shí)候,會(huì)默認(rèn)加入到Active scene摄悯。

SceneManager

SceneManager在UnityEngine.SceneManagement之下赞季,它是Runtime中的Scene manager,提供了以下方法:

LoadScene() / LoadSceneAsync()

它們?cè)试S用戶通過(guò)name奢驯、build index來(lái)加載場(chǎng)景申钩。用戶可以在Build Settings窗口查看name和build index。通過(guò)這兩個(gè)方法加載的場(chǎng)景瘪阁,要么被加到了Build Settings撒遣,要么存在于AssetBundle之中邮偎。如果是從AssetBundle中加載場(chǎng)景,則只能通過(guò)名字加載义黎。

要說(shuō)明的是如果有多個(gè)場(chǎng)景同名但位于不同的目錄之下禾进,可以使用完整的路徑(不帶.unity后綴名)來(lái)加載不同的場(chǎng)景。

用戶可以通過(guò)LoadSceneMode來(lái)指定不同的加載模式廉涕。LoadSceneMode.Single在加載之前會(huì)卸載其他所有的場(chǎng)景泻云,LoadSceneMode.Additive則是加載的時(shí)候不關(guān)閉之前的場(chǎng)景。

還有一點(diǎn)很重要的是LoadScene()并不是完全同步的狐蜕,它只能保證在下一幀開(kāi)始之前加載完畢宠纯。所以在此推薦大家使用LoadSceneAsync()這個(gè)異步的加載方法。

UnLoadScene()

目前5.3中用戶只能通過(guò)name和build index來(lái)同步的卸載一個(gè)Scene层释。在后續(xù)的版本中我們會(huì)提供通過(guò)Scene結(jié)構(gòu)來(lái)卸載一個(gè)Scene婆瓜,并且提供異步卸載的方法。

GetActiveScene() / SetActiveScene()

獲取和設(shè)置Active scene湃累。

GetSceneAt() / GetSceneByName() / GetSceneByPath()

我們也提供了一組方法來(lái)查詢Scene勃救。

其它

EditorSceneManager

EditorSceneManager在UnityEditor.SceneManagement之下,它是Editor中的Scene manager治力,提供了以下方法:

OpenScene()

它是一個(gè)同步的方法,用戶只能通過(guò)path來(lái)打開(kāi)場(chǎng)景勃黍。不同于LoadScene() / LoadSceneAsync()宵统,它可以直接打開(kāi)一個(gè)存在于Assets目錄下的場(chǎng)景,不管它是否被添加到Build Settings覆获。

用戶可以通過(guò)OpenSceneMode來(lái)指定不同的打開(kāi)模式马澈,相比較LoadSceneMode,它多了一個(gè)AdditiveWithoutLoading模式弄息,允許用戶增加一個(gè)場(chǎng)景但并不真正加載它痊班。

CloseScene()

顧名思義,它可以關(guān)閉一個(gè)場(chǎng)景摹量,同時(shí)它提供了一個(gè)bool參數(shù)來(lái)指定關(guān)閉的時(shí)候是否將場(chǎng)景從Scene manager中移除涤伐。

SaveScene() / SaveScenes()

通過(guò)它們可以保存一個(gè)或多個(gè)Scene。

MarkSceneDirty() / MarkAllScenesDirty()

通過(guò)它們可以將某個(gè)指定的場(chǎng)景或者所有場(chǎng)景標(biāo)記為Dirty缨称。大部分情況Unity內(nèi)部通過(guò)Undo系統(tǒng)來(lái)實(shí)現(xiàn)場(chǎng)景的Dirty跟蹤凝果,但是有些模塊并沒(méi)有完全支持Undo,比如Terrain在設(shè)置某些參數(shù)的時(shí)候就不支持Undo睦尽。所以我們提供了這兩個(gè)方法支持直接將場(chǎng)景設(shè)置為Dirty器净。

其它

API的使用限制

在Editor mode下,UnityEngine.SceneManagement.SceneManager的某些方法是不能使用的当凡。

LoadScene()

LoadSceneAsync()

CreateScene()

UnloadScene()

同樣在Play mode下山害,UnityEditor.SceneManagement.EditorSceneManager的某些方法也不能使用纠俭。

OpenScene()

NewScene()

CloseScene()

SaveScene() / SaveScenes() / …

MarkSceneDirty() / MarkAllScenesDirty()

如果用戶在不同的模式下使用了錯(cuò)誤的方法,我們會(huì)在Console輸出對(duì)應(yīng)的錯(cuò)誤信息引導(dǎo)用戶使用正確的方法浪慌。

DontDestroyOnLoad Scene

在Unity 5.3中冤荆,如果用戶通過(guò)Object.DontDestroyOnLoad()方法將某個(gè)Game object標(biāo)記成DontDestroyOnLoad,在進(jìn)入Play mode的時(shí)候會(huì)發(fā)現(xiàn)Hierarchy窗口中會(huì)多出一個(gè)DontDestroyOnLoad場(chǎng)景眷射,它包含了之前標(biāo)記成DontDestroyOnLoad的Game object匙赞。

為什么需要DontDestroyOnLoad Scene

在Unity 5.3中,所有的Game objects必須隸屬于某一個(gè)場(chǎng)景妖碉。這樣我們必須有一個(gè)特別的場(chǎng)景來(lái)管理這些被標(biāo)記為DontDestroyOnLoad的Game objects涌庭,否則在Unload這些Game objects所屬的場(chǎng)景的時(shí)候,這些Game objects也會(huì)被刪除掉欧宜。這顯然不是我們想要的結(jié)果坐榆。

因此我們引入了DontDestroyOnLoad Scene,當(dāng)進(jìn)入Play mode時(shí)候冗茸,我們會(huì)把所有標(biāo)記為DontDestroyOnLoad的Game objects從所屬的場(chǎng)景移入到這個(gè)特別的場(chǎng)景之中席镀。

DontDestroyOnLoad Scene的特點(diǎn)

DontDestroyOnLoad Scene僅僅存在于Runtime,或者是Play mode夏漱。它不能從外部訪問(wèn)豪诲,僅僅是Unity內(nèi)部用于管理標(biāo)記為DontDestroyOnLoad的Game objects。

事實(shí)上從Unity 5.3開(kāi)始挂绰,我們并不推薦用戶使用DontDestroyOnLoad這一功能屎篱,它使得我們內(nèi)部的代碼邏輯復(fù)雜度增加了不少。5.3之前因?yàn)闆](méi)有多場(chǎng)景的支持葵蒂,所以并沒(méi)有很好地辦法繞開(kāi)它并實(shí)現(xiàn)相同的功能交播。而從5.3開(kāi)始我們推薦用戶創(chuàng)建一個(gè)Manager場(chǎng)景,由它負(fù)責(zé)加載/卸載其它所有的游戲場(chǎng)景践付。它從游戲開(kāi)始便存在一直到游戲退出秦士,這樣所有需要被標(biāo)記為DontDestroyOnLoad的Game objects都應(yīng)該屬于這個(gè)場(chǎng)景。

多場(chǎng)景編輯的進(jìn)階

接下來(lái)我們介紹一些關(guān)于多場(chǎng)景編輯的進(jìn)階以及一些小Tips永高。

Scene Manager Setup

Scene Manager Setup可以用來(lái)保存并恢復(fù)當(dāng)前的Scene hierarchy隧土。EditorSceneManager上提供了GetSceneManagerSetup() / RestoreSceneManagerSetup()來(lái)獲取和恢復(fù)Scene hierarchy。

我們可以通過(guò)ScriptableObject來(lái)保存Scene hierarchy乏梁,如下代碼所示:

[AppleScript]純文本查看復(fù)制代碼

?

1

2

3

4

5publicclassSceneSetupSerialization:ScriptableObject

{

[SerializeField]

public SceneSetup[] SceneSetups;

}

以下的代碼展示了如何保存以及讀取Scene manager setup次洼。

[C#]純文本查看復(fù)制代碼

string sceneSetupAssetPath = "Assets/SceneSetup.asset";

public static void SaveSceneSetups()

{

// Create SceneSetupSerialization

var sceneSetupSerialization = ScriptableObject.CreateInstance();

// Set SceneManagerSetup.

var sceneSetups = EditorSceneManager.GetSceneManagerSetup();

sceneSetupSerialization.SceneSetups = sceneSetups;

// Create and save the asset.

AssetDatabase.CreateAsset(sceneSetupSerialization, sceneSetupAssetPath);

AssetDatabase.SaveAssets();

}

public static void LoadSceneSetups()

{

// Restore SceneManagerSetup from the asset.

var sceneSetupSerialization = AssetDatabase.LoadMainAssetAtPath(sceneSetupAssetPath) as SceneSetupSerialization;

EditorSceneManager.RestoreSceneManagerSetup(sceneSetupSerialization.SceneSetups);

}

Lightmap & NavMesh Baking

在Unity 5.3中,Lightmap和NavMesh的烘焙都同時(shí)支持多個(gè)場(chǎng)景遇骑,它們之間的不同之處在于如何管理和劃分烘焙的結(jié)果卖毁。

對(duì)于Lightmap Baking,我們會(huì)根據(jù)Scenes劃分Lightmaps和Realtime GI數(shù)據(jù)。每個(gè)場(chǎng)景都只會(huì)加載和自己相關(guān)的那部分?jǐn)?shù)據(jù)亥啦。

對(duì)于NavMesh Baking炭剪,因?yàn)樗姹旱慕Y(jié)果很小,所以我們將NavMesh的數(shù)據(jù)保存在一個(gè)asset當(dāng)中翔脱,每個(gè)場(chǎng)景都會(huì)引用到這個(gè)asset并能夠找到自己所關(guān)聯(lián)的那部分?jǐn)?shù)據(jù)奴拦。

另外用戶也可以通過(guò)腳本進(jìn)行Baking,Lightmapping.BakeMultipleScenes()和NavMeshBuilder.BuildNavMeshForMultipleScenes()都支持一次烘焙多個(gè)場(chǎng)景届吁。

Scene Dirty Track

Unity內(nèi)部大多通過(guò)Undo系統(tǒng)來(lái)實(shí)現(xiàn)Scene dirty追蹤错妖。Unity 5.3為了支持多場(chǎng)景編輯,我們通過(guò)在Undo操作中保存Scene handles來(lái)擴(kuò)展Undo系統(tǒng)疚沐。

另外我們?cè)黾恿薝ndo.MoveGameObjectToScene()方法來(lái)支持場(chǎng)景之間Game object移動(dòng)的Undo暂氯。同時(shí)Scene結(jié)構(gòu)上面也有一個(gè)Scene.isDirty屬性用于查詢某個(gè)Scene是否被修改。

“Ctrl + S”的行為

在這里有一個(gè)問(wèn)題想跟大家討論的是“Ctrl + S”的行為亮蛔。在5.3以前痴施,無(wú)論場(chǎng)景是否Dirty,只要用戶按下”Ctrl + S”究流,我們一定會(huì)保存該場(chǎng)景辣吃。而在5.3中,因?yàn)槎鄨?chǎng)景編輯的引入芬探,我們改變了這一行為神得。

從5.3開(kāi)始,”Ctrl + S”只會(huì)保存Dirty的場(chǎng)景偷仿。試想如果用戶打開(kāi)了上百個(gè)場(chǎng)景循头,只修改了其中某一個(gè)場(chǎng)景,如果“Ctrl + S”還是保存非Dirty的場(chǎng)景炎疆,保存速度會(huì)受到比較大的影響。

這個(gè)改動(dòng)會(huì)影響到一些Editor的工具国裳。比如某個(gè)Editor的工具創(chuàng)建了一個(gè)Game object形入,由于沒(méi)有使用Undo系統(tǒng)(Undo.RegisterCreatedObjectUndo),使得場(chǎng)景未標(biāo)記成Dirty缝左。這樣當(dāng)在保存的時(shí)候亿遂,Unity并不會(huì)去真正保存這個(gè)場(chǎng)景。

在此推薦大家使用Undo系統(tǒng)來(lái)注冊(cè)Undo操作渺杉,從而能夠正確的將受影響的場(chǎng)景標(biāo)記為Dirty蛇数。我們也樂(lè)于聽(tīng)到大家的反饋,來(lái)看看我們是否有辦法更好的處理這個(gè)問(wèn)題是越。

Scene加載的延遲Awaking

在多場(chǎng)景的使用中耳舅,一個(gè)比較有意思的地方就是Scene加載過(guò)程中的Delay awaking。在介紹它之前我們來(lái)看看Unity內(nèi)部加載一個(gè)Scene所需的步驟。

Scene加載的兩個(gè)步驟

Unity內(nèi)部場(chǎng)景的加載分為兩步:

Loading浦徊。是指從文件馏予、內(nèi)存(主要是Streamed scene

AssetBundle)中加載Scene的內(nèi)容,創(chuàng)建并讀取所有相關(guān)的Game objects盔性、Assets以及Scene game

managers霞丧。所有的IO操作都在這一步完成,所以它是比較耗時(shí)的過(guò)程冕香。當(dāng)這一步完成的時(shí)候蛹尝,我們內(nèi)部會(huì)將加載進(jìn)度標(biāo)記為90%。

Awaking悉尾。主要是一些輕量級(jí)的操作突那,比如在Transform的Awaking的時(shí)候,我們會(huì)將Game objects加入到它所屬于的Scene焕襟。

我們這里所說(shuō)的Scene加載過(guò)程中的Delay awaking就是指第二步陨收。

比如用戶有一個(gè)大場(chǎng)景劃分成了若干個(gè)子場(chǎng)景,在所有場(chǎng)景加載完畢我們才會(huì)開(kāi)始Game play鸵赖。這時(shí)我們就可以推遲所有子場(chǎng)景的Awaking务漩。當(dāng)所有的加載第一步完成了,我們才進(jìn)行所有場(chǎng)景的Awaking它褪。

用戶可以通過(guò)將AsyncOperation.allowSceneActivation設(shè)置成false來(lái)阻止Scene的Awaking饵骨,示例如下:

[C#]純文本查看復(fù)制代碼

?

1

2

3stringname = “TestScene”;

AsyncOperation operation = SceneManager.LoadSceneAsync(name, LoadSceneMode.Additive);

operation.allowSceneActivation =false;

當(dāng)加載進(jìn)度AsyncOperation.progress到達(dá)90%的時(shí)候,就可以將allowSceneActivation設(shè)置成true來(lái)允許Scene awaking茫打。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末居触,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子老赤,更是在濱河造成了極大的恐慌轮洋,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抬旺,死亡現(xiàn)場(chǎng)離奇詭異弊予,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)开财,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)汉柒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人责鳍,你說(shuō)我怎么就攤上這事碾褂。” “怎么了历葛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵正塌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)传货,這世上最難降的妖魔是什么屎鳍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮问裕,結(jié)果婚禮上逮壁,老公的妹妹穿的比我還像新娘。我一直安慰自己粮宛,他們只是感情好窥淆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著巍杈,像睡著了一般忧饭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上筷畦,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天词裤,我揣著相機(jī)與錄音,去河邊找鬼鳖宾。 笑死吼砂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鼎文。 我是一名探鬼主播渔肩,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拇惋!你這毒婦竟也來(lái)了周偎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撑帖,失蹤者是張志新(化名)和其女友劉穎蓉坎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胡嘿,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡袍嬉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了灶平。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡箍土,死狀恐怖逢享,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吴藻,我是刑警寧澤瞒爬,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響侧但,放射性物質(zhì)發(fā)生泄漏矢空。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一禀横、第九天 我趴在偏房一處隱蔽的房頂上張望屁药。 院中可真熱鬧,春花似錦柏锄、人聲如沸酿箭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缭嫡。三九已至,卻和暖如春抬闷,著一層夾襖步出監(jiān)牢的瞬間妇蛀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工笤成, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留评架,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓疹启,卻偏偏與公主長(zhǎng)得像古程,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喊崖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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