製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

lanza發表於2021-02-05
製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

我經常說,我們以前玩過的很多遊戲雖然看上去是 2D 的,但其實是 3D 遊戲——比如熱血物語、雙截龍系列,它們具有一套三維的立體空間邏輯,從而不再使得遊戲的舞臺限制在只有左右移動和上下跳躍這兩種軸向——擁有三個維度極為自由開放的移動範圍相信也給很多玩家留下了深刻的印象,在上次的文章裡,我們已經介紹了這種遊戲的物理部分簡單實現,本次將會聊到這類遊戲在渲染上的重要技巧。

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

顯然,在用 2D 精靈模擬的 3D 空間裡,任何一個物體都不簡單:如圖所示的一個立方體,具有一個 oblique 視角(或者,我們叫 cabinet 視角更準確)的造型。這樣的視角下,如果有另外一個精靈和它相互遮擋,應該怎麼處理它們的渲染順序關係呢?

注:為了簡化描述,本文章的 3D 空間假設所有物件的 z 座標都相同,即“沒有和地面的高度差”。

任意兩個物體之間的排序

按照我們一般的簡單思路(比如在經典的 topdown 視角下,如 RPGMAKER 系列),誰在世界上具有較大的 y 值,誰就靠近螢幕,誰就應該更靠後地渲染,對吧?不過在這樣的視角下,就沒有那麼簡單了,來看一個例子:

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

如圖,根據十字形標記,我們可以輕鬆地發現 shari 的 y 座標小於立方體的座標,所以她理應被擋在立方體的後面(先於立方體渲染),對吧?可是當她來到另外一側的時候,情況就變化了:

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

如圖,shari 的 y 座標仍然小於立方體的 y 座標,但這個位置上,我們是希望 shari 遮擋立方體而不是被立方體遮擋的,所以我們需要考慮到更多的情況。

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

顯然,這個世界裡的任何一個物體都應該攜帶它的"底座"資訊。如圖,紅色的平行四邊形就是上面立方體的"底座"資訊,而綠色是它的高度資訊(如果你需要一些更細緻的排序,比如算上 z 軸,本文暫不討論)有了這個資訊,我們就可以確定任意兩個物件之間的繪製順序。

我們把兩個要排序的物體分別命名為 A 和 B,A 底座的上邊緣稱為 aTop,下邊緣稱為 aBottom;B 底座的上邊緣稱為 bTop,下邊緣稱為 bBottom

aBottom y 座標小於 bTop y 座標

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

這時候 A 顯然是在 B 的後方,也就是 A 先於 B 渲染。

aTopy 座標大於 bBottomy 座標

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

這時候 A 顯然是在 B 的前方,也就是 B 先於 A 渲染。

其它的情況:

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

由於我們這裡的視角下,側面是一個 45 度的斜線,所以我們可以很輕鬆地把兩個物體下邊緣的 y 軸距離加到 aBottom 的右端點去進行判斷,像是這樣:

distanceY = bBottom.y - aBottom.y
(我們用 left right 表示一個線段的左端點和右端點)

aBottom.left.x > bBottom.right.x + distanceY

如果這個判斷是成立的,那就是上圖所述的情況:A 在 B 的前方,也就是 B 先於 A 渲染。

否則就是下圖所述的情況:A 在 B 的後方,也就是 A 先於 B 渲染。

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

對場景內所有物體的排序

好,至此我們已經可以為場景內任意的兩個物件進行排序了,那麼,我們也可以為場景中所有的物件組織排序。很多人的第一反應是,直接用冒泡/選擇/歸併/快排這樣的演算法來對場景中需要排序的物體進行排序不就好了嗎?其實這是不合適的,因為場景中的物體遮擋存在拓撲關係,如果直接使用線性表的排序方法,可能在 swap 一對物體以確保他們遮擋關係的同時又會直接破壞了另一對物體的遮擋關係,因此,我們的第一步是對場景中需要排序的物體進行連線。

圖片帶有弧線的那一端是射線的末端,末端的物體比首端的物體更先渲染(位置更靠後)。

這裡說明一下,我們只對需要排序的一對物體進行連線(出於效能考慮),所以你的顯示物件可能需要有相應的 bounding_box 或是什麼的。

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

當場景中的物體足夠多,遮擋關係足夠複雜時,不難發現,我們的物體遮擋關係實際上構建出了一個有向圖。而有向圖可以通過拓撲排序來獲取一個不唯一的線性序列,照著這個線性序列進行渲染就可以獲得正確的場景排序了。

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

(圖中藍綠色的矩形是判斷精靈相交/重疊用的 bounding_boxDRAWIDX 則是拓撲排序後得到的渲染順序值)

這樣,就得到了整個場景的正確呈現順序。

製作 oblique/cabinet 投影的 2D 遊戲時,確認精靈先後順序的排序方法

最後一點問題

相信我們都看到過一些"視覺錯覺"的趣味圖片,對吧?譬如三個無限迴圈的臺階,相互遮擋的三個稜柱……之類的,很有意思,不過在遊戲開發當中可一點也不有趣。很顯然,當遊戲場景中出現了幾個互相存在遮擋和被遮擋關係的物件時,我們構造出的有向圖就成環了。而成環的有向圖是不能進行拓撲排序的,這就導致我們沒有辦法去按正確順序呈現畫面。解決這個問題的最好方法就是把容易引起該問題的那個物體分割為兩個物體,使得其中的一個部分"專門遮擋"而另一個部分"專門被遮擋",這樣就可以消除我們構造的有向圖中的環。

本次的討論就到這裡,祝大家開發順利,新年快樂!

作者:lanza
來源:indienova
地址:https://mp.weixin.qq.com/s/-8-cXkJ9hG8Di-yeJcPo7w

相關文章