Babybus-u3d技術(shù)交流-隱藏3D模型及GetComponentsInChildren的使用
有時(shí)游戲設(shè)計(jì)的需求迷帜,在場(chǎng)景中的3D模型物件未必都是一開(kāi)始就一直是顯示的狀態(tài),有可能會(huì)因?yàn)槟承┦录陌l(fā)生而必須將物件隱藏捷绑,或因?yàn)槟承┦录陌l(fā)生必須使該物件再次顯示出來(lái),通常在大部份的狀況玻粪,我們可能會(huì)先制作一個(gè)Prefabs论泛,在需要該物件時(shí)利用Instantiate()建立一個(gè)實(shí)例物件辩撑,使物件在場(chǎng)景中運(yùn)作,在不需要該物件時(shí)利用Destroy()將此物件銷毀竞漾,可是如果我們的需求是必須持續(xù)使用該物件眯搭,物件本身帶有某些資料值會(huì)持續(xù)使用到,那么就不能隨意將其銷毀业岁,但此時(shí)需有一段時(shí)間不能使該物件出現(xiàn)在畫(huà)面上坦仍,那么我們應(yīng)該怎么做呢?
物件的隱藏與顯示叨襟,這個(gè)定義上很廣泛繁扎,主要就是讓鏡頭里看不到此物件,以下就來(lái)討論幾種方式:
將物件移出鏡頭外
通常游戲場(chǎng)景都會(huì)有地板糊闽、背景等梳玫,我們?nèi)绻麜簳r(shí)需要將物件隱藏掉,可暫時(shí)改變物件在3D空間的座標(biāo)位置右犹,將它藏在地板下提澎、背景后,甚至是鏡頭后方念链,這樣就可以很輕易的隱藏畫(huà)面中的物件盼忌,不過(guò)积糯,有些缺點(diǎn),就是當(dāng)需要再次將物件顯示在畫(huà)面之中時(shí)谦纱,必須將物件放回正確的位置嘉栓,如果游戲場(chǎng)景及鏡頭都是定點(diǎn)固定不動(dòng)的缭付,那么將物件放回原來(lái)位置并不難究履,但如果游戲場(chǎng)景亡笑、鏡頭都是依照游戲進(jìn)行在不斷運(yùn)作改變方向及內(nèi)容的話,此時(shí)在處理物件座標(biāo)定位上可能就要多費(fèi)點(diǎn)功夫了祠乃。
統(tǒng)一儲(chǔ)存相關(guān)資訊
如上面第一段所提到的梦重,在需要時(shí)產(chǎn)生物件,在不需要顯示時(shí)銷毀物件亮瓷,需要延續(xù)使用的相關(guān)數(shù)據(jù)琴拧,統(tǒng)一儲(chǔ)存在某個(gè)記憶位置、檔案嘱支、資料庫(kù)...中蚓胸,如此做法其實(shí)相當(dāng)直接,不需要的東西就丟斗塘,但也有同樣的問(wèn)題赢织,當(dāng)該物件于下次需要顯示時(shí),我們必須要很清楚知道他應(yīng)該出現(xiàn)的位置馍盟,然后在這個(gè)位置產(chǎn)生物件于置,使游戲進(jìn)行不會(huì)錯(cuò)亂掉,但對(duì)于有使用物理碰撞反彈等等的游戲贞岭,那就很難去預(yù)測(cè)到該出現(xiàn)的正確位置八毯,而且如果這些位置數(shù)據(jù)還要自己寫(xiě)程式計(jì)算的話,Unity的物理引擎反倒顯得無(wú)用武之地了瞄桨。
關(guān)閉物件话速,使物件無(wú)法運(yùn)作
當(dāng)游戲進(jìn)行到某事件發(fā)生時(shí),我們不想將物件銷毀芯侥,而只想讓物件在目前位置消失并停止運(yùn)作泊交,等待之后事件發(fā)生時(shí)再顯示出來(lái),此時(shí)我們就可以利用GameObject.active將該物件關(guān)閉柱查,或使用GameObject.SetActiveRecursively()直接將該物件及他的子物件全部關(guān)閉廓俭,使他停止運(yùn)作,因?yàn)槲锛煌V沽税ぃ源藭r(shí)他將不會(huì)顯示在畫(huà)面上研乒,而物件本身帶有的Component也都會(huì)停止運(yùn)作,待之后事件發(fā)生需要顯示該物件時(shí)再將其開(kāi)啟淋硝,不過(guò)此時(shí)很容易發(fā)生一種情形是雹熬,GameObject.Find()要找回此物件并將其開(kāi)啟時(shí)宽菜,卻發(fā)現(xiàn)找不到,因?yàn)镕ind()只會(huì)幫你找出正在活動(dòng)中的物件竿报,所以在將物件關(guān)閉前铅乡,我們必須將此物件放至預(yù)先定義好的變數(shù)成員中,使我們的程式保有他的參照仰楚,在需要開(kāi)啟時(shí)才能利用此參照找回這個(gè)已被關(guān)閉的物件隆判;因?yàn)橐殉钟兴膮⒄杖樱源宋锛m然是在關(guān)閉的狀態(tài)僧界,但我們?nèi)匀荒軐?duì)他控制,使他改變位置或變更其他數(shù)據(jù)臭挽,但也因?yàn)槭顷P(guān)閉的狀態(tài)捂襟,所以我們付予他的任何主動(dòng)功能動(dòng)作將不會(huì)運(yùn)作。
只控制renderer的開(kāi)關(guān)
這是最直接的方式欢峰,利用renderer.enabled來(lái)控制模型渲染是否啟用葬荷,關(guān)閉了就只是看不到該物件,但全部的Component仍然正常運(yùn)作中纽帖,待需要顯示時(shí)再將它開(kāi)啟宠漩,不過(guò)通常一個(gè)模型并不單單只有一個(gè)物件,例如一個(gè)人物可能分為上半身懊直、下半身扒吁、身體、手室囊、腳雕崩、頭等等,甚至是更細(xì)部融撞,所以我們可能就會(huì)想利用類似這樣的方式將子物件的模型渲染都關(guān)閉..
for(var_child:TransforminparentObject)
{
_child.renderer.enabled=false;
}
但是如果整個(gè)模型構(gòu)造不只一層盼铁,而是多層次的樹(shù)狀結(jié)構(gòu),那么我們可能就需要用巢狀式的forin回圈一層一層的執(zhí)行renderer.enabled=false尝偎,此時(shí)又必須考慮到每個(gè)模型的樹(shù)狀結(jié)構(gòu)都不同饶火,總不能為每個(gè)模型都客制化寫(xiě)一個(gè)巢狀回圈讓他們?nèi)プ鲭[藏,這樣子寫(xiě)程式就太笨了致扯,于是我們可能會(huì)寫(xiě)一個(gè)script專門(mén)做這個(gè)動(dòng)作肤寝,不過(guò)我們并不知道模型的結(jié)構(gòu)會(huì)有幾層,這么做還真是不好處理急前;幸好Unity有個(gè)GameObject.GetComponentsInChildren()幫我們解決了這個(gè)問(wèn)題醒陆,在這部份,我們不再去考慮模型本身是否有子物件或者是有幾層的結(jié)構(gòu)裆针,一句話就能取得全部并控制他們刨摩;官方說(shuō)明頁(yè)面的范例寺晌,我照樣的改到我的程式中并無(wú)法取得我需要的東西,所以在此提供我的寫(xiě)法以供參考...
varmeshObject:Transform;
_components:Component[]=meshObject.GetComponentsInChildren(Renderer);
for(var_comp:Componentin_component)
{
_comp.renderer.enabled=false;
}
如此澡刹,我們很方便的就能為物件隱藏或顯示呻征,但物件在游戲場(chǎng)景中仍正常動(dòng)作中,如果設(shè)計(jì)了一些物理運(yùn)作或碰撞事件罢浇,那么物件碰到某物件或移動(dòng)到某個(gè)區(qū)域就自己隱藏起來(lái)陆赋,隱藏后仍繼續(xù)活動(dòng),可能又碰到了某物件或到了某個(gè)特定區(qū)域又再自己顯示出來(lái)嚷闭,如此下去攒岛,我們可以省掉許多程式運(yùn)算及控制,只要在適當(dāng)?shù)臅r(shí)候告訴物件應(yīng)該隱藏或顯示就行了胞锰。
GetComponentsInChildren()不只是用在物件的renderer的控制上灾锯,還可用在任何Component的控制上,所以我們可以將數(shù)個(gè)相關(guān)的物件都放到一個(gè)空物件中嗅榕,以群組的方式利用GetComponentsInChildren()來(lái)統(tǒng)一管理并控制其中的Component及script中的變數(shù)成員及函式顺饮。