Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
2D 視差滾動
前言
視差(Parallax)是一種常用來模擬景深的效果,讓不同圖層(紋理)相對於攝影機以不同速度移動。Godot 提供 Parallax2D 節點來實現這個效果。不過在使用上還是很容易出錯,所以本頁會詳細說明相關屬性,以及常見問題與修正方法。
備註
本頁介紹如何使用 Parallax2D,建議優先使用它來取代過去的 ParallaxLayer 和 ParallaxBackground 節點。
入門
Parallax 節點可以加上算繪用的子節點,因此每一層可以用一個或多個節點組成。首先,將你希望能獨立滾動的節點都放到各自的 Parallax 節點下當子節點。請確保每個用到的紋理左上角都對齊 (0, 0),如下圖所示。為什麼這很重要,參考 定位 一節。
上圖的場景是用一張事先準備好的高雲紋理加在 Sprite2D 上,但你也可以用多個節點分別排開來組成這一層。
捲動縮放
視差效果的核心是 scroll_scale 屬性。這個屬性會當作滾動速度的倍率,讓每個軸向的圖層可以跟攝影機有不同的移動速度。數值 1 表示該層與攝影機同速移動。如果你希望圖像看起來比較遠,就設小於 1(0 則完全不動);如果要讓內容看起來更靠近攝影機,則設大於 1,這樣滾動會比較快。
上圖場景有五個圖層,以下是一些常用的 scroll_scale 值參考:
(0.7, 1)- 森林(0.5, 1)- 山丘(0.3, 1)- 低雲(0.2, 1)- 高雲(0.1, 1)- 天空
下方影片展示這些數值在遊戲中如何影響視差滾動效果:
無限重複
Parallax2D 還能額外讓紋理看起來像是無限重複。repeat_size 屬性會指定當攝影機捲動超過這個數值時自動將位置往前或往後跳。這個效果是透過為所有子畫布項目多加一次重複、並做位移來實現的。當攝影機在原始圖像與重複圖像之間捲動時,畫面會在看不見的情況下跳回頭,營造出圖像無限循環的錯覺。
這個效果比較細緻,新手常常容易設錯。我們來看看常見問題的「成因」與「解法」。
尺寸不正確
要讓無限重複效果好用,最好是圖像本身就是無縫可重複的,並且「在設定 repeat_size 前」圖像尺寸要跟視窗一樣大或更大。如果你的素材不是專門做來無縫重複,還有一些其他方式可以調整圖像尺寸。
下面是一個紋理太小、不足以覆蓋視窗的例子:
可以看到視埠大小是 500x300,但圖像只有 288x208。如果我們把 repeat_size 設成圖像大小,無限重複效果會失敗,因為原始圖像覆蓋不了整個視窗。如果 repeat_size 設成視窗大小,中間又會有大空隙。該怎麼辦?
把視窗縮小
最簡單的解法,就是把視窗調成跟你的圖像一樣大或更小。在 專案設定 > 顯示 > 視窗 裡,把 Viewport Width 和 Viewport Height 設成跟背景圖一樣。
縮放 Parallax2D 本身
如果你不追求像素完美,或不介意有點模糊,也可以直接把紋理放大到填滿螢幕。只要設定 Parallax2D 的 scale,所有子節點紋理也會跟著縮放。
縮放子節點
和縮放 Parallax2D 類似,你也可以直接把 Sprite2D 子節點放大到足以覆蓋整個畫面。但要注意,像 Parallax2D.repeat_size 和 Sprite2D.region_rect 這些設定不會自動根據縮放調整,所以必須手動依縮放倍率對應調整這些數值。
重複紋理
你也可以一開始就將子節點準備好。如果你有一個 Sprite2D 紋理想要重複但尺寸太小,可以用下列做法讓它重複鋪滿:
將 region_enabled 設為
true把 region_rect 設成足夠覆蓋視窗的多倍尺寸。
如下圖,將圖像重複兩次就足以覆蓋整個畫面。
位置錯誤
常見錯誤是把所有紋理都設為以 (0,0) 為中心:
這樣會導致無限重複效果出錯,應該避免。所謂的「無限重複畫布」從 (0,0) 開始,向右下延伸到 repeat_size 設定的大小。
如果紋理是以 (0,0) 為中心,無限重複畫布就只有部分被覆蓋,導致只有部分能正確重複。
多設幾個 repeat_times 可以解決嗎?
把 repeat_times 加大在某些情況下確實有用,但這只是硬解,並不是這個參數本來該解決的問題(稍後會說明)。更好的做法是先了解無限重複的原理,再正確設置你的視差紋理。
首先檢查你的紋理有沒有超出畫布的負座標。確保所有用於視差的紋理都放在從 (0,0) 開始的「無限重複畫布」範圍內。這樣只要 Parallax2D.repeat_size 設正確,就會像這樣,圖像單次循環就能覆蓋整個視窗甚至更大:
想像畫面捲動時,會先顯示紅色方框(這個區域由 repeat_size 決定)的內容,當畫面滾到黃色方框時,畫面會瞬間跳到下一輪,營造出無限捲動的錯覺。
如果你的圖像沒有對齊「無限重複畫布」,當攝影機滾到黃色方框時,畫面會被截掉一半才跳轉,如下圖所示:
捲動偏移
如果你的視差紋理已經正常顯示,但你希望畫面從不同位置開始,Parallax2D 有一個 scroll_offset 屬性可以調整無限重複畫布的起始點。例如圖像大小 288x208 時,把 scroll_offset 設成 (-144,0) 或 (144,0),就能讓它從圖像中間起始。
重複次數
理想情況下,根據本指南設置後,你的視差紋理即使在畫面縮小時也足以覆蓋整個螢幕。前面我們範例是 288x208 紋理對應 288x208 視窗,但如果我們把 Camera2D.zoom 設為 (0.5, 0.5),畫面縮小一半就會出現問題:
即使預設縮放下都沒問題,當畫面縮小後,原本的紋理就不夠大,無限重複效果就會壞掉。這時就需要用 repeat_times 。設成 3 (前後各加一個重複),就能讓圖像足夠大來支援無限重複。
如果你的紋理設計本來就要垂直重複,可以把 repeat_size 的 y 設成相應數值,repeat_times 就會自動在上下也加一個重複。這裡範例只有做水平視差,所以上下會有空白。該怎麼辦呢?可以有創意地把天空拉高、草地拉低,這樣紋理就能同時支援正常與縮小一半的縮放。
分割畫面
大多數 Godot 分割畫面教學會先寫個小腳本,把第一個 SubViewport 的 Viewport.world_2d 指定給第二個 SubViewport,讓它們共享顯示。這時就常常會有人問:「要怎麼讓兩個畫面都能有同樣的視差效果?」。
視差效果是透過每個圖層根據攝影機位置不同而移動,營造出景深。如果你有多個攝影機,就會產生問題,因為同一張紋理不可能同時出現在兩個不同位置!
其實還是可以辦到,只要把視差節點複製到第二個(甚至第三、第四個):ref:SubViewport<class_subviewport>。下圖是雙人遊戲的範例:
這時會發現兩個 SubViewport 都會顯示兩個背景。我們想要的是每個視差圖層只顯示在對應的畫面。可以這樣做:
讓所有視差節點都維持預設的 visibility_layer (層 1)。
把第一個 SubViewport 的 canvas_cull_mask 設成只顯示層 1 和 2。
第二個 SubViewport 也一樣設,但改用層 1 和 3。
把第一個 SubViewport 的所有視差節點放在同一個父節點下,並把該父節點的 visibility_layer 設為 2。
第二個 SubViewport 的視差節點也同理,但設成 3 層。
這個機制是這樣:如果某個畫布項目的 visibility_layer 跟 SubViewport 的 canvas_cull_mask 不符,就算子節點有設定,整個分支也都會被隱藏。我們就利用這點,讓每個 SubViewport 只顯示有對應父層 visibility_layer 的視差節點。
在編輯器中預覽
Godot 4.3 以前的做法,建議每一層都用一個自己的 ParallaxBackground ,啟用 follow_viewport_enabled ,再分別縮放每一層。這個做法其實一直都比較複雜,但現今你可以改用 CanvasLayer 來實現分層,而不是 ParallaxBackground 。
備註
另一個推薦是 KoBeWi 的「Parallax2D Preview」外掛,它提供多種預覽模式,非常好用!