夢(mèng)開(kāi)始的地方——FC游戲開(kāi)發(fā)指南(8)背景與卷軸
(本系列是一個(gè)回歸電子游戲原點(diǎn)的特別系列,作者 @goodorc_gamedev)
上期鏈接:https://www.bilibili.com/read/cv13763901
從最早的FC作品之一:超級(jí)瑪麗兄弟開(kāi)始,F(xiàn)C就以它強(qiáng)大的背景卷軸機(jī)能給玩家留下了深刻印象。
背景卷軸技術(shù)最大的難點(diǎn)在于——當(dāng)背景向左移動(dòng)一個(gè)像素時(shí),背景需要被完整刷新一次,每個(gè)像素都要重新繪制一遍。如果用CPU來(lái)做這件事簡(jiǎn)直是不可想象的,所以80年代的電腦系統(tǒng)大都不支持流暢的全屏卷軸,相比FC的流暢效果,其它電腦系統(tǒng)都有所妥協(xié)。
所以,學(xué)到這里的同學(xué)也都能猜到——一定又是PPU的功能對(duì)不對(duì)?
沒(méi)錯(cuò)。本節(jié)將從繪制大背景開(kāi)始,介紹“背景卷軸”這個(gè)重點(diǎn)功能的實(shí)現(xiàn)方法。
1、繪制背景
我做的打飛機(jī)游戲,背景是在海面上飛行,比較簡(jiǎn)單,所以我對(duì)背景研究也不是很深。
制作背景的原理兩句話就能說(shuō)清楚——還是用之前做好的chr文件,從已有的Tile中任意選擇,將它們拼在一張大圖上,就是背景了。

如上圖,我添加了4個(gè)tile小格,將它們重復(fù)平鋪就可以形成一整張海面背景。
制作背景圖,只需要在FC游戲大師中新建一個(gè)“背景工程(nmr)”即可。
新建時(shí)提示沒(méi)有調(diào)色板、沒(méi)有chr,都沒(méi)關(guān)系。
新建的背景圖一開(kāi)始是空的,首先導(dǎo)入字模(字模就是CHR)。
配色不需要導(dǎo)入,點(diǎn)擊主菜單的配色 > #00,手動(dòng)選擇與之前的調(diào)色板同樣的顏色就可以了。 (由于文件格式不兼容,導(dǎo)入原來(lái)的配色更費(fèi)勁,不如手動(dòng)選擇了。)
在右側(cè)選中tile,在左側(cè)用鼠標(biāo)刷出來(lái)即可。注意:此工具窗口有點(diǎn)小,菜單中有x2放大功能。
FC地圖編輯器,支持一次選中4個(gè)tile。只要選中“連續(xù)方塊”選項(xiàng)即可。


基本方法就是這么簡(jiǎn)單。
保存以后得到一個(gè)nmr文件,一個(gè)nam文件,直接用nam即可。
2、顯示背景
和之前一樣,導(dǎo)入二進(jìn)制文件到rom中,需要修改crt0.s文件。詳細(xì)步驟:
1、我保存的背景文件是test.nam文件,在文件夾中確認(rèn)它存在。
2、修改crt0.s文件,在文件前面導(dǎo)出 _test_nam的符號(hào)給C語(yǔ)言使用。
3、在irq那幾行指令后面,加入test.nam的二進(jìn)制內(nèi)容。
說(shuō)明:上面第2步導(dǎo)出了一個(gè)符號(hào)給C語(yǔ)言,第3步是將整個(gè)nam文件的內(nèi)容復(fù)制到了最終游戲rom中去。
4、修改C語(yǔ)言代碼。首先在文件前面加一句外部符號(hào)test_nam聲明,這里不能寫開(kāi)頭的下劃線:
在游戲初始化畫面時(shí)略加修改:
解釋:load_BG_palette意思時(shí)加載背景調(diào)色板,這里復(fù)用了精靈的顏色。
load_full_name_0就是加載0號(hào)名字表,包含符號(hào)表和屬性表。
FC提供了兩個(gè)名字表0號(hào)和1號(hào),這樣方便我們做出背景連續(xù)滾動(dòng)的效果。如圖:

實(shí)際上還有另外兩個(gè),一共4個(gè)名字表,不過(guò)單向卷軸2個(gè)表就夠了。
簡(jiǎn)單編寫之后,我們的“移動(dòng)”游戲也有背景了:

3、在匯編中添加卷軸變量,并在C語(yǔ)言中賦值
經(jīng)過(guò)嘗試,卷軸功能寫在C語(yǔ)言代碼中總有一些時(shí)序問(wèn)題,很難完美。
所以這里直接介紹在匯編中操作卷軸的方法,還是和上次講過(guò)的NMI中斷有關(guān)。
首先加入兩個(gè)匯編變量,修改nes.inc文件,在tickcount變量之后加兩個(gè)變量:
其中,vpos指的是縱向卷軸的位置,取值范圍0~239(因?yàn)镕C一屏正好240行),而escroll是卷軸功能開(kāi)關(guān),只要escroll==0,就停止卷軸。
這樣定義的變量,在匯編中是可以用的。但是怎樣在C語(yǔ)言中用它呢?注意到,其實(shí)匯編中定義的變量,是已經(jīng)指定了地址的,vpos內(nèi)存地址是0x6d,escroll內(nèi)存地址是0x6e。所以C語(yǔ)言中用指針引用它們:
使用時(shí),只要寫 *pescroll = 1; ? 就給該變量賦值為1了。怕之后忘,現(xiàn)在就在初始化階段加上:
4、加入卷軸代碼
端口0x2005控制卷軸功能。
修改crt0.s的NMI中斷代碼,在原有代碼中插入了16行,同時(shí)刪除tickcount+1的那行,完整摘錄如下:
其實(shí)功能很簡(jiǎn)單,就是對(duì)vpos變量進(jìn)行加1操作,到了240就回到1。每幀將vpos值寫入0x2005端口,0x2005就是控制卷軸的端口。
雖然功能簡(jiǎn)單,但匯編寫起來(lái)就是這么長(zhǎng)。
注:原來(lái)的匯編代碼我沒(méi)有完全看懂,但后面的代碼一定要?jiǎng)h除或注釋,才能啟用卷軸功能。
在初始化階段別忘了加入 *pescroll = 1;
再次運(yùn)行,應(yīng)該可以看到背景動(dòng)起來(lái)了:

背景運(yùn)動(dòng)后,露出了第二個(gè)背景。第二個(gè)背景我們沒(méi)有設(shè)置,所以是黑色。
1、修改mylib.c文件。之前只有l(wèi)oad_full_name0和load_full_name1,沒(méi)有寫2號(hào)、3號(hào)名字表。給它補(bǔ)上:
2、在初始化階段,需要加載0號(hào)和2號(hào)名字表:
如果順利的話,到這里背景就可以動(dòng)起來(lái)了。
背景卷動(dòng)涉及的問(wèn)題確實(shí)很多,通過(guò)這篇文章應(yīng)該也能學(xué)到一些C語(yǔ)言指針技巧。下一期將是本系列的最終章。希望對(duì)FC有興趣的同學(xué)繼續(xù)捧場(chǎng)。
(本文作者?@goodorc_gamedev。歡迎加入游戲開(kāi)發(fā)群歡樂(lè)攪基:1082025059
對(duì)游戲開(kāi)發(fā)感興趣的童鞋可戳這里進(jìn)一步了解:http://www.levelpp.com/)