本文轉載自kingmax_res
《[Unity3D]無縫場景切換解決方案(1) - 簡單場景切換》
因為前一段時間忙着openGL事情,所以沒玩u3d了,這幾天閑有性質研究下韓MM的問題
。
所謂無縫場景切換,無非是涉及到場景或物體的預讀,復雜點涉及下場景卸載,在復雜點涉及到場景二維數組,再在復雜點涉及數據結構用二叉樹實現場景資源有序的讀取與卸載。當然,復雜的我以后慢慢再說,比較懶,先寫最簡單的,如果能起到拋磚引玉作用,那這篇文章也算是物有所值了。
無縫場景切換的優缺點:
優點:
1.場景(游戲)連貫性。
2.相對於多場景游戲,不需要等待場景更換(在進入場景后已經在實時加載下一個場景了)
3.相對於單個大場景,這種方式能避免所有的場景數據被裝入內存(盡管u3d優化很好並不會被渲染出來),很大的數據在內存里影響你游戲的性能(特別是在iphone這種小內存環境)。
缺點:
1.操作繁瑣(本文介紹比較基礎簡單的方式)
2.開發者要求較高(注意保持邏輯清晰,不然后期你會全亂掉的)
涉及到幾個U3D函數:
Application.LoadLevel(lv) 場景讀取(記着用多場景前要現在File-Build Setting里登記下場景,才能在腳本里讀取到) DontDestroyOnLoad(object) 保持物體在場景切換的時候不被卸載(能保持他的所有屬性哦)
*AssetBundle 類 預讀資源(主要用於web3d,運行時實時從服務器下載需要的場景資源)
涉及到幾個基礎知識:
static 靜態類、靜態變量:在整個游戲中都不會被重新加載,所以可以當全局全場景變量使用,主要用於記錄場景數組。
Collider的Is Trigger屬性:設置成True,他是可以穿越不會產生能量傳遞的,但是,他是可以接受碰撞偵測的。配合主角的OnTriggerEnter事件,就可以知道你是否正在穿越一個Trigger了。在這里,我們用在判斷何時加載新場景上。
簡單的無縫場景切換方案:
1.建立場景(已經做好很大場景的就准備做切割吧)
場景盡量小,如果是web3d,那需要更小,已保證場景在網絡上傳輸時間不至於太長,在漫游中再實時讀取其他場景數據。一般來說,場景大小考慮因素有兩種:如果是web3d模式,考慮網絡傳輸速度;如果是pc,mac,wii,iphone,那就得考慮內存或顯存能吃你多少場景數據並且處理起來不費力。
按照你所需要建立的無縫場景切換方式,你可以按場景的坐標建立以下幾種方式:
1 ) 雙場景切換(本文重點) 2)九宮格場景切換
1)雙場景切換:用於單個場景較大的情況。同一時間只加載1個到2個場景(預讀周圍4個場景),場景間需要交錯,避免讓用戶看到場景的邊界深淵=.=.當用戶走到邊界,就加載下一個場景,如果走到4個頂點,加載下兩個場景(如果場景龐大應盡量用障礙物避免用戶走到頂點,因為走到頂點要加載的數據是走到邊界加載的2倍-,-)
2)九宮格場景切換:用於單個場景較小的情況。因為同一時間需要在內存中載入以用戶為中心的周圍(包括本地)9個場景資源,不同於雙場景切換的是,場景間不需要交錯,因為用戶視野永遠不會看到當前場景界限。用9宮格方式需要將場景預先存入靜態的二維數組,以便讀取使用。
2.制作場景邊界
使用Cube + IsTrigger=True屬性是最好的辦法。
1)如果是雙場景切換,注意兩個場景邊界坐標別重在一起,不然你走到邊界會發現兩個邊界不停的切換=.=,要讓2個場景邊界互相交錯一起(做的時候你自然會明白)。有必要的話,邊界可以往里面縮一點(甚至可以吧場景重疊1/3,但這樣兩個場景你要做很多重復的東西),避免用戶看到邊界。然后建議是把Cube的名字設置成鄰接場景名稱,因為待會兒寫腳本時候方便。
2)如果是九宮格場景,那就不需要重在一起了,邊界Cube名字建議使用本場景的名字,因為這樣你一走到下一個場景,就可以知道你在的場景位置而讀取周圍新場景了。
3.編寫腳本
好了,現在可以開始寫腳本了,我一如既往的很懶,所以不會吧全部代碼粘帖出來
。
先理清楚邏輯關系以及一些常識:
1.是主攝像機走到邊界才會做場景加載或卸載動作。所以代碼是放在主攝像機上或者主角上。
2.場景可以加載,但是沒有卸載場景這個東西(也沒必要卸載,因為同一時間只會有一個場景為當前場景),所以如果你用九宮格方式做無縫連接,你需要把場景讀取,然后讓場景里所有物體DontDestroyOnLoad(當然包括主角,也就是this),然后其他場景也這么操作,當需要卸載場景時,只要把所有那個場景Object給Destroy掉就可以了。而做雙場景連接則不需要這樣,也簡單的多。
3.如果是九宮格,你需要一個靜態二維數組去記錄每個位置場景的名字。這里也可以不需要這么做,有個技巧,你可以格式化場景名字規則來推算下一個需要加載的場景名字,比如M1N1表示(1,1)場景,那你就可以用字符串拆分的方法知道需要讀取M0N0,M1N0,M2N0等等的場景。
4.接下來就是處理碰撞,獲取下一個場景(雙場景方式)或者當前場景(九宮格方式)的名字,這里你就可以看到一個被格式化過的場景名有多么重要。
function OnTriggerEnter(other:Collider){
Application.LoadLevel(other.name); //這是雙場景方式直接把邊界Cube名字設為了下一個場景名
}
更加復雜化的無縫切換方案思路:
1.使用角色與邊界距離動態判斷,以確定載入時機以及載入哪個方位的場景。
2.加入判斷角色為中心的圓內的物體加載(操作起來有點復雜,除非你整個場景是數字化的,或者干脆是動態生成的),這需要一個加權的二叉搜索樹將大地圖所有的物體放進去,在滿足條件時候去載入最近的。
(僅提供思路,可能有更好的數據結構去優化他)
![[Unity3D]無縫場景切換解決方案(1) - 簡單場景切換 - kingmax_res - kingmax_res的博客](/image/aHR0cDovL2ltZy5ibG9nLjE2My5jb20vcGhvdG8vTzZPbDBjR0VIR08xNWdEV2dad2NEUT09LzI4OTAxODUwNjA4NjU3NjY3MjQuZ2lm.png)
所謂無縫場景切換,無非是涉及到場景或物體的預讀,復雜點涉及下場景卸載,在復雜點涉及到場景二維數組,再在復雜點涉及數據結構用二叉樹實現場景資源有序的讀取與卸載。當然,復雜的我以后慢慢再說,比較懶,先寫最簡單的,如果能起到拋磚引玉作用,那這篇文章也算是物有所值了。
無縫場景切換的優缺點:
優點:
1.場景(游戲)連貫性。
2.相對於多場景游戲,不需要等待場景更換(在進入場景后已經在實時加載下一個場景了)
3.相對於單個大場景,這種方式能避免所有的場景數據被裝入內存(盡管u3d優化很好並不會被渲染出來),很大的數據在內存里影響你游戲的性能(特別是在iphone這種小內存環境)。
缺點:
1.操作繁瑣(本文介紹比較基礎簡單的方式)
2.開發者要求較高(注意保持邏輯清晰,不然后期你會全亂掉的)
涉及到幾個U3D函數:
Application.LoadLevel(lv) 場景讀取(記着用多場景前要現在File-Build Setting里登記下場景,才能在腳本里讀取到) DontDestroyOnLoad(object) 保持物體在場景切換的時候不被卸載(能保持他的所有屬性哦)
*AssetBundle 類 預讀資源(主要用於web3d,運行時實時從服務器下載需要的場景資源)
涉及到幾個基礎知識:
static 靜態類、靜態變量:在整個游戲中都不會被重新加載,所以可以當全局全場景變量使用,主要用於記錄場景數組。
Collider的Is Trigger屬性:設置成True,他是可以穿越不會產生能量傳遞的,但是,他是可以接受碰撞偵測的。配合主角的OnTriggerEnter事件,就可以知道你是否正在穿越一個Trigger了。在這里,我們用在判斷何時加載新場景上。
簡單的無縫場景切換方案:
1.建立場景(已經做好很大場景的就准備做切割吧)
場景盡量小,如果是web3d,那需要更小,已保證場景在網絡上傳輸時間不至於太長,在漫游中再實時讀取其他場景數據。一般來說,場景大小考慮因素有兩種:如果是web3d模式,考慮網絡傳輸速度;如果是pc,mac,wii,iphone,那就得考慮內存或顯存能吃你多少場景數據並且處理起來不費力。
按照你所需要建立的無縫場景切換方式,你可以按場景的坐標建立以下幾種方式:
1 ) 雙場景切換(本文重點) 2)九宮格場景切換
1)雙場景切換:用於單個場景較大的情況。同一時間只加載1個到2個場景(預讀周圍4個場景),場景間需要交錯,避免讓用戶看到場景的邊界深淵=.=.當用戶走到邊界,就加載下一個場景,如果走到4個頂點,加載下兩個場景(如果場景龐大應盡量用障礙物避免用戶走到頂點,因為走到頂點要加載的數據是走到邊界加載的2倍-,-)
2)九宮格場景切換:用於單個場景較小的情況。因為同一時間需要在內存中載入以用戶為中心的周圍(包括本地)9個場景資源,不同於雙場景切換的是,場景間不需要交錯,因為用戶視野永遠不會看到當前場景界限。用9宮格方式需要將場景預先存入靜態的二維數組,以便讀取使用。
2.制作場景邊界
使用Cube + IsTrigger=True屬性是最好的辦法。
1)如果是雙場景切換,注意兩個場景邊界坐標別重在一起,不然你走到邊界會發現兩個邊界不停的切換=.=,要讓2個場景邊界互相交錯一起(做的時候你自然會明白)。有必要的話,邊界可以往里面縮一點(甚至可以吧場景重疊1/3,但這樣兩個場景你要做很多重復的東西),避免用戶看到邊界。然后建議是把Cube的名字設置成鄰接場景名稱,因為待會兒寫腳本時候方便。
2)如果是九宮格場景,那就不需要重在一起了,邊界Cube名字建議使用本場景的名字,因為這樣你一走到下一個場景,就可以知道你在的場景位置而讀取周圍新場景了。
3.編寫腳本
好了,現在可以開始寫腳本了,我一如既往的很懶,所以不會吧全部代碼粘帖出來
![[Unity3D]無縫場景切換解決方案(1) - 簡單場景切換 - kingmax_res - kingmax_res的博客](/image/aHR0cDovL2ltZy5ibG9nLjE2My5jb20vcGhvdG8vTzZPbDBjR0VIR08xNWdEV2dad2NEUT09LzI4OTAxODUwNjA4NjU3NjY3MjQuZ2lm.png)
先理清楚邏輯關系以及一些常識:
1.是主攝像機走到邊界才會做場景加載或卸載動作。所以代碼是放在主攝像機上或者主角上。
2.場景可以加載,但是沒有卸載場景這個東西(也沒必要卸載,因為同一時間只會有一個場景為當前場景),所以如果你用九宮格方式做無縫連接,你需要把場景讀取,然后讓場景里所有物體DontDestroyOnLoad(當然包括主角,也就是this),然后其他場景也這么操作,當需要卸載場景時,只要把所有那個場景Object給Destroy掉就可以了。而做雙場景連接則不需要這樣,也簡單的多。
3.如果是九宮格,你需要一個靜態二維數組去記錄每個位置場景的名字。這里也可以不需要這么做,有個技巧,你可以格式化場景名字規則來推算下一個需要加載的場景名字,比如M1N1表示(1,1)場景,那你就可以用字符串拆分的方法知道需要讀取M0N0,M1N0,M2N0等等的場景。
4.接下來就是處理碰撞,獲取下一個場景(雙場景方式)或者當前場景(九宮格方式)的名字,這里你就可以看到一個被格式化過的場景名有多么重要。
function OnTriggerEnter(other:Collider){
Application.LoadLevel(other.name); //這是雙場景方式直接把邊界Cube名字設為了下一個場景名
}
更加復雜化的無縫切換方案思路:
1.使用角色與邊界距離動態判斷,以確定載入時機以及載入哪個方位的場景。
2.加入判斷角色為中心的圓內的物體加載(操作起來有點復雜,除非你整個場景是數字化的,或者干脆是動態生成的),這需要一個加權的二叉搜索樹將大地圖所有的物體放進去,在滿足條件時候去載入最近的。
(僅提供思路,可能有更好的數據結構去優化他)