FC遊戲的偽多捲軸
各位讀者,大家好!
這次將要介紹的是FC(也就是大家熟悉的紅白機)上,關於遊戲畫面的一些小知識。
一如既往地啰嗦,請見諒。
——————————
本文始於KONAMI 的《魂斗羅》(Contra)中角色為什麼要「蘿莉式屈腿俯卧」? - 遊戲這個問題,一番熱烈討論之後,@勝勛 發來一個擴展問題:
『三目童子』是如何做到場景雙捲軸的?
(三目童子的場景雙捲軸演示)
限於知乎私信系統限制,當時僅以簡短文字作答。對方身為開發者,自然立刻理解了答案。
不過呢,我認為這是一個非常有趣而高質量的提問,值得專門進行一番解說,供更多玩家閱讀。搜索了一下,並沒有人在知乎創建這個問題,我又不習慣自問自答,正好這個專欄已經快長草了,於是寫在這裡。——————
首先,可能有些朋友無法理解這個問題本身在問什麼,這裡有必要說明一下:
FC的硬體設計是只支持單層捲軸背景的。
所謂「捲軸背景」是相對「固定背景」而言。早期的很多遊戲畫面場景是固定的(甚至乾脆全黑),玩家控制的角色只能在屏幕框內活動。
要表達超過一個屏幕的場景內容時,就用房間切換的概念,把地圖分割成一個個單屏幕區域,當角色走到屏幕邊緣時,場景會切換成下一個房間。這種做法本質上依然是靜態背景。
(其實我這兩個例子舉得不好,圖中的遊戲相對都比較晚了,只是大家相對熟悉這兩作,便於理解。70年代末80年代初的主流遊戲基本都是固定背景。)
捲軸遊戲則不同,它實現了背景的捲動效果,視覺上好像是鏡頭跟著角色移動一般。這種技術可以讓玩家感到自己的角色在更遼闊的場景中活動,而不是局限於一個個小房間。
上圖的『超級馬里奧兄弟』想必大家都玩過吧?回想一下這個遊戲是什麼樣子的?背景就像一幅長條形的畫,隨著玩家的操作,背景能夠平滑地向左捲動(會被玩家理解為鏡頭向右移動)。
那麼「單層背景」是什麼意思呢?
畫面一動起來,稍微留神就可以發覺,遊戲中的水管、樹叢、白雲等元素都是固定在背景上的——它們都屬於同一層「背景」;而玩家角色、敵方角色則是另一層上的「活動塊」。
這就是FC的機能限制(其中之一)所在。
我們可以用SFC上的『超級馬里奧世界』對比一下。SFC續作中,場景被分成了「近景」和「遠景」,即「近處」的地面、水管、磚塊等,和「遠處」的山脈、雲朵等。當鏡頭進行移動時,這兩層的捲動是分開的,遠景移動的速度比近景要慢。比起FC的前作,層次感明顯更加豐富。
「多層背景捲軸」的處理能夠讓遊戲畫面顯得更自然更真實。它模擬了人們的生活體驗:乘坐汽車、火車時,可以看到路邊的電線杆飛快掠過,但遠處的房子和山等景物「後退的速度」就顯得沒那麼快(因為遠方物體視角變化較小)。
這樣的效果是托SFC強大的機能所賜,除了發色數、活動塊數量等方面的進化以外,SFC提供了3層標準可捲動背景(Mode0最多4層,但圖像質量會顯著降低),而老前輩FC則只提供了1層。
——————
然而,TOMY的『三目童子』卻在FC上實現了這樣的效果。請格外注意青色磚塊和褐色石塊的相對位置:
(本文開始處有視頻鏈接)
磚塊居然錯開運行了!這意味著這個洞窟中的畫面是「兩層捲軸」。
記得么?前面說過,FC從硬體上就只支持一層捲軸。
……
這簡直是魔法般的效果。
怎麼實現的?
——————
錯誤答案1:活動塊
可能有人會想到,捲軸不夠那就用活動塊來偽造背景唄。
……但是很遺憾,FC的機能是不足以做到這一點的。
對於FC來講,即使只處理單層背景也要消耗2/3以上(256/341)的PPU計算資源,乃至於同一水平掃描行上只能夠渲染8個活動塊(參見NESDEV,或我的答案)。
當同一掃描行上活動塊數量多於8個時,多餘的會被直接放棄掉,只能顯示其中8個。例如上圖中,爆炸花光效果、小兵的腿都各自出現了一定殘缺。
如果遊戲設計時預計會出現這種需要大量橫向內容的場景,那麼程序員應當指定「輪換優先順序」的邏輯,讓它們在不同的幀輪流顯示。
人類的眼睛和大腦有視覺暫留效應,對於玩家來講,一定程度的閃爍是可以接受的,它會被玩家腦補成連續運動。如果不進行優先順序輪換處理,那麼內容過多時,很可能某些特定活動塊就會一直被放棄顯示,變為徹底隱形的——如果『魂斗羅』中敵人的子彈是隱形的,跑著跑著你就莫名其妙死了,你還會喜歡玩嗎?同一水平線上活動塊數量越多,輪到每個塊顯示的間隔就越久,閃爍感就越強烈。所以魂斗羅趴下也不能太寬,要把腿勾起來才好。
所以,8個活動塊是什麼概念呢?
每個活動塊的寬度是8像素,把它們拼在一起也就只有64像素寬。
而三目童子的畫面上無論「近景」還是「遠景」,都是整塊的、大片的圖像,完全沒有閃爍,絕不是8個活動塊能覆蓋得了的。
在FC上,這一手並非完全無用,但僅限於細節處的修修補補,不可能全指望它。
——————
錯誤答案2:水平切割
另外一項技術被稱為Raster Scroll。它利用的是線掃描的時間差。
前面提供的關於FC PPU渲染原理的介紹中提到過:FC的圖像是按照水平掃描線逐行計算輸出的,如果在上一行的背景部分處理完畢後、下一行開始前,重寫背景的X坐標偏移量,就可以讓下一行的背景圖像水平錯開。
這個技術能夠在橫向運鏡時製造一定程度的層次感。
例如『忍者龍劍傳』的開場動畫中,這片草地就被分成了若干個層次,畫面越靠下(越接近鏡頭)的草,橫向移動就越快。
再例如『忍者龍劍傳2』的開場動畫,請注意城牆、山脈、烏雲之間的錯層水平移動(烏雲內部本身也被分了幾層)。
不光是開場動畫,實際遊戲中也有著大量利用水平切割製造層次感的場景,例如2-1的火車、『忍者龍劍傳3』中7-1的戰艦等。
當然,這個也不是忍龍系列的什麼專利,拿它舉例只是因為它畫面出了名的好。FC上利用水平切割來增強畫面層次感的動作遊戲非常多。
例如『熱血新紀錄』中的400米比賽,遠景的看台和近景的跑道的移動速度就有所不同。
類似的例子我還能舉出一大堆,這裡就不贅述了。
聰明的你可能會想到水平切割的技術局限。
這一招的本質是Y軸切割,不是Z軸疊放。換言之,水平切割技術只能做到把畫面切成若干個橫條,讓上下各橫條之間的水平運動速度分離。它能實現背景錯層運動,但無法實現前後遮蓋。
再回頭看看這個畫面,褐色石塊和青色磚塊有明顯的左右交接,鏡頭移動時,就會產生遮蓋效果——FC根本就不支持多層背景相互遮蓋。
所以我才說這是個有趣的問題。
——————
那麼,正確答案是什麼呢?When you have eliminated the impossible, whatever remains, however improbable, must be the truth.
——Sherlock Holmes
糊爾摩斯講過,用排除法推理嘛!把不可能的方向排掉,剩下的自然就是正確答案了~
現在複習一下前面的線索:
- FC在渲染每一行的輸出畫面時,只能夠處理256像素寬的(平鋪)背景,外加8個8像素寬的活動塊。活動塊可以遮蓋背景,但超過8個的活動塊會被隱藏,只能閃爍輪流顯示。
三目童子的雙層背景很寬,而且沒有閃爍。因此不可能是用活動塊偽造出來的。
- FC可以採用水平切割的花招,改變不同掃描行間的X偏移,將畫面切割成橫條,實現錯層運動。但是橫條之間必須是上下平鋪擺放的,不能疊放,也不能互相遮蓋。三目童子的雙層背景有左右進出的遮蓋效果。因此不可能是用水平切割偽造出來的。
- 再重複一遍,FC的背景只能單層、平鋪。
這也不行,那也不行,剩下的只有一種可能了……
——————
不知道各位看沒看過這麼一個笑話:
一個茶館的常客去喝茶,看見鄰座新來了個外地人,聊了幾句就熟起來了。
過了倆禮拜,他隱約覺得那外地人拿的鼻煙壺有點不對勁,想來想去知道怎麼回事了——第一次見面的時候那鼻煙壺上刻了個月牙,今天居然變成滿月了。這人沒提這茬,又悄悄觀察了幾天,發現這鼻煙壺上刻的月亮果然能跟著真月亮變。他興奮起來了,這特么是個寶貝啊!他跟外地人再聊起來的時候忍不住問:「你這鼻煙壺多少錢啊,賣給我吧?」外地人說:「這是我自己用的啊。你買個新的多好乾嘛非要我這個。」「我就喜歡你這個,五千怎麼樣?不,要不一萬吧?」好說歹說一頓軟磨硬泡,買下來了。哥們高興地一溜小跑回家,關在屋裡研究了好幾天,結果發現那月亮卻死活沒再變了。
這人垂頭喪氣地回到茶館,找到那外地人:「這鼻煙壺怎麼在你手上的時候月亮能變,我買回來就變不了了?」「哦,我這是一套的,家裡還有30個呢,你還買么?」
其實,就是這個意思。每樣畫一個,需要哪個拿哪個就好了。
正確答案:改貼圖
FC留給貼圖(Pattern Tables)的地址空間有8kB,兩個Pattern Table各4kB,通常一個供背景使用,另一個供活動塊使用,各包含256個8*8的2bit(4色)點陣圖。單個Pattern Table也可以直接表示為128*128的形式。
對於素材較為豐富的遊戲,在卡帶上可以通過MMC晶元來切換Pattern Table的內容。
對應前面三目童子那三張「遠景石塊不同覆蓋程度」的截圖,Pattern Table 0的狀態如下(注意F0到FF,也就是最下面一行圖塊):
把FF這一塊放大10倍看看:
明白了吧?開發者預先繪製了n套背景,錯開一個像素就是一張新圖片。通過演算法切換調用,強行實現近景遠景「雙層捲軸」的視覺效果。
除了三目童子以外,據我所知『戰蛙』、『劍王』等遊戲也用了類似的手段。這招簡單粗暴,代價也是顯而易見的:對卡帶容量和性能的需求——換句話說就是製造成本。畢竟存儲額外圖像素材所需的ROM是要錢的,用來切換bank的MMC晶元也是要錢的。
1985年的超級馬里奧兄弟只有40kB,多數早期遊戲甚至比它還小。1987年隨著任天堂官方MMC1開始大量出現128kB的遊戲,到了1988年256kB才成為主流。上面提到的幾個用改貼圖實現偽多捲軸的遊戲,都是1990年以後的了(彼時MD、SFC都已經面世,玩家對遊戲畫面的追求也被提升了一截)。
即使有256kB容量,想利用換貼圖來實現多層捲軸也要小心些,Pattern要做得盡量重複、簡單,能少畫幾張是幾張。畢竟FC的硬實力就那樣,把有限的資源放在更多遊戲內容上才是王道。
——————————
後記
其實水平切割也好、改貼圖也好,其早期應用都不在於偽多捲軸。
拿水平切割來說,你能想到超級馬里奧兄弟其實也在用嗎?
它是用來做屏幕頂端的計分板的——沒錯,上面那一排分數、時間什麼的都是背景的一部分,而不是活動塊(不然早就擺不下了,還記得8個活動塊的限制么)。如果你仔細觀察就會發現,計分板那一橫條是沒有其它遊戲內容的,只有純色背景。
對X偏移做了修正,計分板才能夠固定在屏幕頂端,而不會和雲彩什麼的一起滾到左邊去。FC上很多遊戲的計分板、狀態欄什麼的都是這麼處理的。例如前面說過的忍龍,還有惡魔城什麼的,一眼就能看出來。而改貼圖呢,主要是場景切換,以及一些附加的動態效果。
例如日版魂斗羅第一關,樹葉搖動的效果,就是通過VRC2晶元(*K社自家的MMC)實現的。(順帶一提,魂斗羅的命數顯示用的是活動塊而不是背景)
大概就是這樣。
感謝閱讀:)
推薦閱讀:
※非IT人士都能看懂的工程代碼重構方法:三步走
※【《Real-Time Rendering 3rd》 提煉總結】(九) 第十章 · 遊戲開發中基於圖像的渲染技術總結
※從零開始手敲次世代遊戲引擎(MacOS特別篇 貳)
※遊戲不再是增量市場,它已經充滿了不確定性
※國外大學中,有哪些大學開設了網路遊戲開發,有公開課么?