如何使用collision pipeline提升游戲開發(fā)優(yōu)勢(shì)
來(lái)源:
未知 |
責(zé)任編輯:六月芳菲 |
發(fā)布時(shí)間: 2018-03-02 09:17 | 瀏覽量:
更多精彩unity教程:http://trusteddivorcelawyers.com/resource/
當(dāng)我在移動(dòng)設(shè)備上工作的時(shí)候,我遇到了一個(gè)二維的基于網(wǎng)格的動(dòng)作難題,我遇到了一個(gè)復(fù)雜的問(wèn)題,但是使用Unity3D的collision pipeline,我可以用一種可靠的方式來(lái)解決它。
好的,想象一下你有一個(gè)2D的基于網(wǎng)格的游戲,玩家可以在直線上運(yùn)行,然后撞到墻上,你需要讓玩家在游戲中運(yùn)行一些基于這樣原理的關(guān)卡。
我們使用一個(gè)帶有一個(gè)BoxCollider2D的精靈來(lái)制作一個(gè)“塊”,并附加一個(gè)“塊”腳本,當(dāng)玩家碰到它時(shí),它會(huì)將這個(gè)玩家反射到相反的方向上。
更多精彩unity教程:http://trusteddivorcelawyers.com/resource/
現(xiàn)在你可以在場(chǎng)景周圍放置幾個(gè)這樣的“方塊”,效果很好。
但這還不夠,你想要加快速度,所以你要在你的項(xiàng)目中包含一個(gè)2D地圖編輯工具。這個(gè)工具使你可以在你的場(chǎng)景中直接繪制出與網(wǎng)格直接對(duì)齊的瓷磚,你甚至可以一次在多個(gè)圖層上工作。太棒了!現(xiàn)在,讓這個(gè)層次成為一種輕而易舉的事情,你可以把設(shè)計(jì)層次的任務(wù)委托給關(guān)卡設(shè)計(jì)師,
最終,關(guān)卡設(shè)計(jì)師說(shuō):“嘿!我們需要一個(gè)能在玩家撞到他的時(shí)候殺死玩家的蜘蛛,這樣我就能創(chuàng)造出更有趣的關(guān)卡。”這對(duì)你來(lái)說(shuō)不是問(wèn)題,所以你要敲出一個(gè)小的“SpikeyBlock”腳本,當(dāng)玩家撞到它時(shí),它就會(huì)殺死玩家。有了“SpikeyBlock”腳本,不久你就會(huì)有“粘塊”、“buttonblock”等等
一切都很順利,直到不可思議的事情發(fā)生。關(guān)卡設(shè)計(jì)人員需要一個(gè)塊,在一邊是spikey,在另一邊是sticky。換句話說(shuō),塊現(xiàn)在應(yīng)該有邊了!邊! !而級(jí)別設(shè)計(jì)人員希望能夠以不同的方式添加大量的邊。那么你會(huì)怎么做呢?
一開始,您考慮向塊類添加額外的變量和沖突邏輯,但是很快意識(shí)到這種方法將使塊類變得復(fù)雜且難以擴(kuò)展。這也會(huì)使那些現(xiàn)在不得不在檢查器窗口中設(shè)置值的關(guān)卡設(shè)計(jì)人員變得更加困難。這不僅是一個(gè)緩慢的過(guò)程,而且還會(huì)讓可愛的小地圖編輯工具毫無(wú)意義。
然后,您提出了另一個(gè)想法,來(lái)創(chuàng)建一個(gè)“Edge”類,它封裝了不同的行為,并可以添加到一個(gè)塊中。更好。這解決了保持代碼整潔的問(wèn)題,但是對(duì)于仍然需要在檢查器窗口中添加邊緣組件的關(guān)卡設(shè)計(jì)人員來(lái)說(shuō),這并不能使事情變得更容易。
解決方案
這讓我們了解了本文的關(guān)鍵,即利用Unity3D pipeline的解決方案。
首先,你將一個(gè)邊緣的概念分解成一個(gè)單獨(dú)的對(duì)象,這個(gè)對(duì)象可以使用不同的timap層來(lái)放置在tilemap的任何地方。通過(guò)小心的預(yù)制結(jié)構(gòu),邊緣可以放置在一塊磚的旁邊,看起來(lái)就像它的一部分一樣。這解決了級(jí)別設(shè)計(jì)人員的工作流程問(wèn)題。
其次,我們用一種稍微不同的方式構(gòu)造邊界,把它們的碰撞器標(biāo)記為檢查器的觸發(fā)器區(qū)域。這讓我們有機(jī)會(huì)在與區(qū)塊碰撞前處理與邊的碰撞,因?yàn)椋却?,在管道中發(fā)生固體碰撞之前,觸發(fā)大碰撞,如果你不相信的話,請(qǐng)檢查Unity的“事件頁(yè)面的執(zhí)行順序”。我們只是將OnCollision函數(shù)的代碼移到OnTrigger函數(shù)中。
但是,等一下,如果玩家正在擦過(guò)其中的一個(gè)邊,并觸碰到一個(gè)觸發(fā)區(qū)域,會(huì)怎么樣呢?我們只想處理碰撞,如果玩家撞到邊緣,而不是越過(guò)它。如果玩家在一個(gè)有兩種不同邊的角上呢?我們應(yīng)該打哪邊?現(xiàn)在我們要做一系列的計(jì)算來(lái)檢驗(yàn)我們是否真的擊中了邊緣。這是不對(duì)的,Unity是一個(gè)游戲引擎!我們不需要做這些檢查,我們只是想知道什么時(shí)候發(fā)生了碰撞,然后做一些很酷的事情。我們?nèi)匀豢梢赃M(jìn)一步利用pipeline。
假設(shè)玩家有一個(gè)Edges數(shù)組,當(dāng)玩家進(jìn)入一個(gè)邊緣的觸發(fā)區(qū)域時(shí),它會(huì)被添加到數(shù)組中,當(dāng)玩家離開該區(qū)域時(shí),它會(huì)被移除。就是這樣,這就是我們所做的,我們不需要做任何檢查就能知道我們什么時(shí)候到達(dá)了Block的邊緣。相反,我們讓Unity告訴我們,當(dāng)我們撞到這個(gè)街區(qū)的時(shí)候,因?yàn)槲覀儠?huì)收到一個(gè)碰撞事件,因?yàn)樗墓腆w碰撞器。然后我們要做的就是讓玩家檢查數(shù)組中的任何邊(最大的3條邊),如果任何邊都朝向相反的方向(我使用了一個(gè)enum),玩家就會(huì)與這條邊發(fā)生碰撞,否則我們就會(huì)與這個(gè)方塊發(fā)生碰撞。請(qǐng)記住, OnTrigger是在OnCollision之前處理的,因此我們確信,當(dāng)玩家到達(dá)塊時(shí),他們的數(shù)組中已經(jīng)有了邊緣。
玩家的碰撞檢查很簡(jiǎn)單:
[C#] 純文本查看 復(fù)制代碼
?
結(jié)論
好了,這可能需要一段時(shí)間才能達(dá)到這個(gè)目的,但我最終到達(dá)了這里,希望你們已經(jīng)看到了如何使用流水線上的執(zhí)行順序來(lái)幫助解決復(fù)雜的問(wèn)題。
無(wú)論如何,我試圖保持這篇文章的光芒(盡管主題是一些技術(shù)性的),并希望它能在某種程度上有所幫助。歡迎發(fā)表任何問(wèn)題或評(píng)論,我將盡我所能做出回應(yīng)。
更多精彩unity教程:http://trusteddivorcelawyers.com/resource/
當(dāng)我在移動(dòng)設(shè)備上工作的時(shí)候,我遇到了一個(gè)二維的基于網(wǎng)格的動(dòng)作難題,我遇到了一個(gè)復(fù)雜的問(wèn)題,但是使用Unity3D的collision pipeline,我可以用一種可靠的方式來(lái)解決它。
好的,想象一下你有一個(gè)2D的基于網(wǎng)格的游戲,玩家可以在直線上運(yùn)行,然后撞到墻上,你需要讓玩家在游戲中運(yùn)行一些基于這樣原理的關(guān)卡。
我們使用一個(gè)帶有一個(gè)BoxCollider2D的精靈來(lái)制作一個(gè)“塊”,并附加一個(gè)“塊”腳本,當(dāng)玩家碰到它時(shí),它會(huì)將這個(gè)玩家反射到相反的方向上。
01 02 03 04 05 06 07 08 09 10 11 |
public class Block : MonoBehaviour { void OnCollisionEnter2D(Collision2D coll) { if (coll.gameObject.tag == "Player") { Player player = coll.gameObject.GetComponent <PLayer> (); if (player) player.direction = Opposite(direction); } } } |
更多精彩unity教程:http://trusteddivorcelawyers.com/resource/
現(xiàn)在你可以在場(chǎng)景周圍放置幾個(gè)這樣的“方塊”,效果很好。
但這還不夠,你想要加快速度,所以你要在你的項(xiàng)目中包含一個(gè)2D地圖編輯工具。這個(gè)工具使你可以在你的場(chǎng)景中直接繪制出與網(wǎng)格直接對(duì)齊的瓷磚,你甚至可以一次在多個(gè)圖層上工作。太棒了!現(xiàn)在,讓這個(gè)層次成為一種輕而易舉的事情,你可以把設(shè)計(jì)層次的任務(wù)委托給關(guān)卡設(shè)計(jì)師,
最終,關(guān)卡設(shè)計(jì)師說(shuō):“嘿!我們需要一個(gè)能在玩家撞到他的時(shí)候殺死玩家的蜘蛛,這樣我就能創(chuàng)造出更有趣的關(guān)卡。”這對(duì)你來(lái)說(shuō)不是問(wèn)題,所以你要敲出一個(gè)小的“SpikeyBlock”腳本,當(dāng)玩家撞到它時(shí),它就會(huì)殺死玩家。有了“SpikeyBlock”腳本,不久你就會(huì)有“粘塊”、“buttonblock”等等
一切都很順利,直到不可思議的事情發(fā)生。關(guān)卡設(shè)計(jì)人員需要一個(gè)塊,在一邊是spikey,在另一邊是sticky。換句話說(shuō),塊現(xiàn)在應(yīng)該有邊了!邊! !而級(jí)別設(shè)計(jì)人員希望能夠以不同的方式添加大量的邊。那么你會(huì)怎么做呢?
一開始,您考慮向塊類添加額外的變量和沖突邏輯,但是很快意識(shí)到這種方法將使塊類變得復(fù)雜且難以擴(kuò)展。這也會(huì)使那些現(xiàn)在不得不在檢查器窗口中設(shè)置值的關(guān)卡設(shè)計(jì)人員變得更加困難。這不僅是一個(gè)緩慢的過(guò)程,而且還會(huì)讓可愛的小地圖編輯工具毫無(wú)意義。
然后,您提出了另一個(gè)想法,來(lái)創(chuàng)建一個(gè)“Edge”類,它封裝了不同的行為,并可以添加到一個(gè)塊中。更好。這解決了保持代碼整潔的問(wèn)題,但是對(duì)于仍然需要在檢查器窗口中添加邊緣組件的關(guān)卡設(shè)計(jì)人員來(lái)說(shuō),這并不能使事情變得更容易。
解決方案
這讓我們了解了本文的關(guān)鍵,即利用Unity3D pipeline的解決方案。
首先,你將一個(gè)邊緣的概念分解成一個(gè)單獨(dú)的對(duì)象,這個(gè)對(duì)象可以使用不同的timap層來(lái)放置在tilemap的任何地方。通過(guò)小心的預(yù)制結(jié)構(gòu),邊緣可以放置在一塊磚的旁邊,看起來(lái)就像它的一部分一樣。這解決了級(jí)別設(shè)計(jì)人員的工作流程問(wèn)題。
其次,我們用一種稍微不同的方式構(gòu)造邊界,把它們的碰撞器標(biāo)記為檢查器的觸發(fā)器區(qū)域。這讓我們有機(jī)會(huì)在與區(qū)塊碰撞前處理與邊的碰撞,因?yàn)椋却?,在管道中發(fā)生固體碰撞之前,觸發(fā)大碰撞,如果你不相信的話,請(qǐng)檢查Unity的“事件頁(yè)面的執(zhí)行順序”。我們只是將OnCollision函數(shù)的代碼移到OnTrigger函數(shù)中。
但是,等一下,如果玩家正在擦過(guò)其中的一個(gè)邊,并觸碰到一個(gè)觸發(fā)區(qū)域,會(huì)怎么樣呢?我們只想處理碰撞,如果玩家撞到邊緣,而不是越過(guò)它。如果玩家在一個(gè)有兩種不同邊的角上呢?我們應(yīng)該打哪邊?現(xiàn)在我們要做一系列的計(jì)算來(lái)檢驗(yàn)我們是否真的擊中了邊緣。這是不對(duì)的,Unity是一個(gè)游戲引擎!我們不需要做這些檢查,我們只是想知道什么時(shí)候發(fā)生了碰撞,然后做一些很酷的事情。我們?nèi)匀豢梢赃M(jìn)一步利用pipeline。
假設(shè)玩家有一個(gè)Edges數(shù)組,當(dāng)玩家進(jìn)入一個(gè)邊緣的觸發(fā)區(qū)域時(shí),它會(huì)被添加到數(shù)組中,當(dāng)玩家離開該區(qū)域時(shí),它會(huì)被移除。就是這樣,這就是我們所做的,我們不需要做任何檢查就能知道我們什么時(shí)候到達(dá)了Block的邊緣。相反,我們讓Unity告訴我們,當(dāng)我們撞到這個(gè)街區(qū)的時(shí)候,因?yàn)槲覀儠?huì)收到一個(gè)碰撞事件,因?yàn)樗墓腆w碰撞器。然后我們要做的就是讓玩家檢查數(shù)組中的任何邊(最大的3條邊),如果任何邊都朝向相反的方向(我使用了一個(gè)enum),玩家就會(huì)與這條邊發(fā)生碰撞,否則我們就會(huì)與這個(gè)方塊發(fā)生碰撞。請(qǐng)記住, OnTrigger是在OnCollision之前處理的,因此我們確信,當(dāng)玩家到達(dá)塊時(shí),他們的數(shù)組中已經(jīng)有了邊緣。
玩家的碰撞檢查很簡(jiǎn)單:
[C#] 純文本查看 復(fù)制代碼
?
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 |
// in the Player script OnHitBlock(Block block) { // check the edges foreach (Edge edge in edges) { if (edge.direction == Opposite(player.direction)) { Hit(edge); // handle edge collision return; } } Hit(block); // otherwise handle the block collision } |
結(jié)論
好了,這可能需要一段時(shí)間才能達(dá)到這個(gè)目的,但我最終到達(dá)了這里,希望你們已經(jīng)看到了如何使用流水線上的執(zhí)行順序來(lái)幫助解決復(fù)雜的問(wèn)題。
無(wú)論如何,我試圖保持這篇文章的光芒(盡管主題是一些技術(shù)性的),并希望它能在某種程度上有所幫助。歡迎發(fā)表任何問(wèn)題或評(píng)論,我將盡我所能做出回應(yīng)。
更多精彩unity教程:http://trusteddivorcelawyers.com/resource/
-
分享到:
相關(guān)文章
網(wǎng)友評(píng)論
您需要登錄后才可以發(fā)帖 登錄 | 立即注冊(cè)
關(guān)閉
- 用戶名:
- 密 碼:
- 驗(yàn)證碼: 看不清? 點(diǎn)擊更換
- 忘記密碼?
全部評(píng)論:0條
推薦
熱門