第四十五章 筑基
于是乎,灰太狼移動(dòng)的函數(shù)也跟著變樣:
int move(int keyCode)
{
int xOffset =(keyCode - 39)% 2;
int yOffset =(keyCode - 38)% 2;
int x1 =灰太狼當(dāng)前位置x+ xOffset;
int y1 =灰太狼當(dāng)前位置y+ yOffset;
int x2 =灰太狼當(dāng)前位置x+ xOffset * 2;
int y2 =灰太狼當(dāng)前位置y+ xOffset * 2;
/*移動(dòng)判斷邏輯*/
}
這樣一來,可比老爹剛剛暗中偷取取巧的雞賊辦法看上去了高大上多了。
雖然看到這兩行代碼不能像老爹之前那種方法一目了然地明白意圖所在,不過我和小弦子都很是滿意,六叔叔也微微點(diǎn)了點(diǎn)頭,想來也是認(rèn)可這種結(jié)果的。
「不對(duì)呀,老爹,你只說了說了答案,都沒有傳授我們是如何推導(dǎo)出算法的方法呢!古人不是云過么?授人以魚不如授人以漁?!?p> 我突然意識(shí)到這個(gè)嚴(yán)重的問題,老爹要是不把他推導(dǎo)的過程說出來的話,下一次遇到這種問題我是不會(huì)?。?p> 「這個(gè)還真不是我不跟你們說,而是我當(dāng)初也是連蒙帶猜出來的?!?p> 老爹笑了笑,臉上難得露出了不好意思的表情。
「我不信!」
老爹的回答比剛剛那個(gè)投機(jī)取巧的算法還讓人難以接受,這次他壓根兒連巧都懶得取了。
老爹是誰?資深級(jí)別的程序員,這種看起來也不是好復(fù)雜的算法怎么可能是他猜出來的嘛!「猜」這個(gè)字簡直對(duì)不起他的專業(yè)素養(yǎng)。
「是真的,就像你們數(shù)學(xué)考試,不是經(jīng)常給出前面幾個(gè)數(shù)字,然后讓你們按照規(guī)律填寫后面的數(shù)字么?
這也沒有什么固定的方法可言,最有效的方法就是把所有能夠想到的套路都拿來嘗試一下,興許就能夠發(fā)現(xiàn)其中的規(guī)律。要是一時(shí)之間沒有方向,基本上很難看出規(guī)律來。
不過當(dāng)你們看過的套路多了,自然而然就有感覺了。」
老爹無奈道。
既然老爹都這么說了,雖然我還是有點(diǎn)難以接受,但也沒有其他辦法了。畢竟數(shù)學(xué)老師在講那種找規(guī)律的題是,解題思路和老爹的說法別無二致。
到了現(xiàn)在這階段,灰太狼移動(dòng)的這部分邏輯算是大局已定。為了培養(yǎng)我和小弦子建立「自上而下」的編程思維,老爹從功能劃分的角度將推箱子這個(gè)游戲重新解析了一遍。
所謂的「自上而下」的編程思維,就是說當(dāng)我們要實(shí)現(xiàn)一個(gè)項(xiàng)目的時(shí)候,首先要做的并不是具體的代碼應(yīng)該怎么寫,而是按照之前老爹講的程序哲學(xué)三連問將程序分成幾大模塊,并分析出模塊與模塊之間的聯(lián)系。
而所謂的聯(lián)系,實(shí)際上就是數(shù)據(jù)的交互。
接下來就是將每個(gè)大模塊又分成一個(gè)個(gè)小模塊,這個(gè)時(shí)候的小模塊就是功能相對(duì)獨(dú)立函數(shù)了。
最后一步,這才是考慮具體某個(gè)函數(shù)的代碼應(yīng)該怎么寫
于是這些功能獨(dú)立的函數(shù)組合在一起形成了一個(gè)大的模塊,而所有的模塊組合在一起,就是一個(gè)完整的程序了。
這樣做有幾個(gè)好處,最大的好處就是將程序分成塊兒了之后可以多人分工合作,當(dāng)然前提在對(duì)程序分塊兒的時(shí)候就要定義好對(duì)外的函數(shù)的接口,如函數(shù)的名字、參數(shù)列表以及返回值類型。
其次就是方便維護(hù),如果要增加或者修改功能,就只需要修改某一部分,只要對(duì)外的函數(shù)接口不變,其他模塊就不會(huì)受到影響。
由于我和小弦子初次接觸這種理念,老爹事無巨細(xì),一一為我們解釋得清清楚楚。這么一個(gè)小游戲程序在老爹解剖之下被分為了三大模塊:地圖加載、人物移動(dòng)、狀態(tài)保存和過關(guān)判定。
地圖加載又分為從文件中讀取地圖數(shù)據(jù)到地圖二維數(shù)組和從根據(jù)二維數(shù)組加載圖片元素。
人物移動(dòng)分為地圖二維數(shù)組中元素的變換和圖片元素的變化顯示。
狀態(tài)保存是為了降低游戲難度,每次地圖二維數(shù)組的元素發(fā)生了改變時(shí),就將數(shù)據(jù)保存在本地文件中,當(dāng)游戲玩家按了返回上一步按鈕后,就從本地文件中讀取數(shù)據(jù),重新加載地圖,從而達(dá)到「后悔」功能的效果。
不然的話一旦操作錯(cuò)了一步,就得重新開始關(guān)卡。原本推算過關(guān)方法就是一件令人心里煩躁的事情,如果還需要重頭再來,很容易讓玩家產(chǎn)生砸電腦的沖動(dòng)。
過關(guān)判定還是和原來一樣,沒有什么變化。
除此之外,老爹還讓我們把一些用的地方比較多,且值固定的數(shù)據(jù)定義成全局常量,比如說圖片尺寸,這樣以后如果圖片的尺寸發(fā)生了改變,只需要修改一個(gè)地方就可以了。
老爹將所有的東西:各個(gè)模塊的函數(shù)接口,模塊下的各個(gè)小模塊的函數(shù)定義,全局變量和常量都用一個(gè)文檔記錄得清清楚楚,然后分發(fā)給了我和小弦子。
「剛剛我?guī)缀踅o你們演示了開發(fā)一個(gè)軟件的全部過程,這份文檔也算得上是設(shè)計(jì)概要了,現(xiàn)在就由你們倆合作,將這個(gè)程序給敲出來。
其中涉及到文件保存和讀取的地方先定義一個(gè)什么都不做的函數(shù)放在那兒,等到我們明天學(xué)習(xí)了文件指針后再添加上去就好了。」
老爹布置完任務(wù),隨即宣布今天的課程結(jié)束。
今天的內(nèi)容倒是不多,但是都很重要。主要講了關(guān)鍵字static、external的用法,C語言內(nèi)存分區(qū),提取相似的代碼封裝成函數(shù),和算法的第一次接觸以及自上而下程序設(shè)計(jì)理念。
基本上都是一些摸不著的理論知識(shí),并且只有通過一定量的代碼累積才能夠體會(huì)到這其中的好處。
但是這些知識(shí)卻無處不在,影響著程序開發(fā)的方方面面。就拿自上而下的程序設(shè)計(jì)理念來說,如果一個(gè)程序的模塊劃分得好,不禁能夠提高程序開發(fā)的效率,同時(shí)也方便日后的維護(hù)工作。
「寫代碼不是功能實(shí)現(xiàn)了就算是結(jié)束,其實(shí)寫程序也算是一種藝術(shù),在追求高效的同時(shí)也要追求優(yōu)雅。代碼說到底不過是一種文檔,既然是文檔,那自然是給人看的,所以注釋是必不可少的!一個(gè)好的代碼文檔,里面的注釋可能會(huì)占到整個(gè)篇幅的50%以上。
當(dāng)代碼寫出來之初,世界上只有兩個(gè)知道是什么意思,一個(gè)是程序員自己,另外一個(gè)是上帝。如果沒有注釋的話,在半個(gè)月后世界上就只有一個(gè)人知道是什么意思了,知道是誰么?」
老爹笑著問道。