程序作品(6)————平面開(kāi)放世界游戲
4. 背包及掉落物
4.1 挖掘方塊生成掉落物
在我的游戲中,玩家需要連續(xù)點(diǎn)擊一個(gè)方塊若干下以挖掘這個(gè)方塊。這個(gè)功能非常好實(shí)現(xiàn),只需要給表示方塊的類中增加一個(gè)clickmark變量表示上一次點(diǎn)擊的時(shí)間(時(shí)間的定義參考之前的文章),再增加一個(gè)clicktimes變量表示當(dāng)前連點(diǎn)的次數(shù)即可。為了給每個(gè)方塊賦予不同的硬度,我又新建了一個(gè)叫做obj_hardness的字典,用來(lái)將方塊的名字和其硬度一一對(duì)應(yīng)。
每點(diǎn)擊一個(gè)方塊一次,程序需要判斷當(dāng)前時(shí)間與該方塊的clickmark的差值是否過(guò)大,如果過(guò)大,則將clicktimes的值改成一,否則將clicktimes的值加一(如果玩家拿著稿子的話,則根據(jù)稿子材質(zhì)的不同適當(dāng)增加每次加的值的大小)。如果某次點(diǎn)擊后clicktimes的值大于該方塊的硬度,則將該方塊變成掉落物,并隨機(jī)生成一個(gè)方塊填補(bǔ)該方塊的位置(并且如果玩家拿著稿子的話,給稿子的耐久值減少一點(diǎn))。
那么該如何將一個(gè)方塊變成掉落物呢?
我定義了一個(gè)表示掉落物的類,里面含有表示這個(gè)掉落物種類、數(shù)量、位置等信息的變量。然后又給存儲(chǔ)每個(gè)區(qū)塊的列表中新增一個(gè)子列表用來(lái)存儲(chǔ)這個(gè)區(qū)塊中的所有掉落物。這樣一來(lái)一旦有新的掉落物生成,我們只需要往對(duì)應(yīng)的區(qū)塊的列表中塞一個(gè)表示掉落物的類的實(shí)例即可。
4.2 撿起掉落物
我在前面的文章里說(shuō)過(guò)撿起掉落物需要很大的算力,現(xiàn)在我收回這句話。
在前面的文章中我之所以這么說(shuō)是因?yàn)楫?dāng)時(shí)我對(duì)掉落物和玩家之間的距離的判斷依然使用的是將掉落物一一遍歷這樣的低效方法。然而現(xiàn)在我采用的是上一篇文章中所講到的區(qū)塊算法。與判斷子彈和生物之間的距離類似,由于同一個(gè)小區(qū)塊里存在兩個(gè)掉落物的概率非常少,因此判斷撿起掉落物的時(shí)間復(fù)雜度基本上就是O(1)。
撿起掉落物后,我們要從該區(qū)塊中刪除這個(gè)掉落物的數(shù)據(jù),并且將這個(gè)掉落物所代表的物體移到我們的背包里。
4.3 背包
為了存儲(chǔ)背包,我定義了一個(gè)類用來(lái)表示背包的一個(gè)格子。這個(gè)類中包含了一個(gè)格子中物品的種類、數(shù)量、耐久度等信息(耐久度不是每個(gè)物品都需要用到,所以有時(shí)候可能會(huì)為None)。接下來(lái)我定義了一個(gè)叫做pack_list的列表,用來(lái)表示背包。列表分為五行九列(最后一行有十列),前四行用來(lái)存儲(chǔ)背包中的物品,最后一行用來(lái)控制合成。每個(gè)列表的元素都是一個(gè)表示背包格子的類的實(shí)例。
4.3.1?移動(dòng)背包內(nèi)的物品
為了移動(dòng)背包里的物品,我們首先要把用戶在屏幕上點(diǎn)擊的坐標(biāo)信息轉(zhuǎn)換成所對(duì)應(yīng)的背包的具體格子(即映射)。截至目前為止,我的游戲中的背包看起來(lái)是這樣的:

可以看到,整個(gè)背包由下面四行的存儲(chǔ)區(qū)和上面十格的合成區(qū)組成。下面四行的映射工作非常簡(jiǎn)單,只需要將用戶點(diǎn)擊的坐標(biāo)減去左下角格子的左下角頂點(diǎn)的坐標(biāo),再除以每個(gè)格子的邊長(zhǎng)后取整即可。但是上面的合成區(qū)的映射就相對(duì)來(lái)說(shuō)有一點(diǎn)難度。
為此,我定義了一個(gè)叫做yingshe()的函數(shù),專門用來(lái)做合成區(qū)的映射工作。以用戶點(diǎn)擊的x、y坐標(biāo)作為參數(shù),yingshe()函數(shù)判斷這個(gè)坐標(biāo)是否在合成區(qū)的范圍內(nèi),如果是,則返回映射結(jié)果,否則返回None。
將這樣的復(fù)雜判斷定義成一個(gè)函數(shù)不僅有助于簡(jiǎn)化我的程序,使其變得更加易讀,而且由于合成區(qū)的方塊移動(dòng)規(guī)則和存儲(chǔ)區(qū)有一點(diǎn)不一樣,這樣做還可以幫助我在后面的代碼中判斷用戶點(diǎn)擊在合成區(qū)還是存儲(chǔ)區(qū)。
在對(duì)用戶的點(diǎn)擊坐標(biāo)做好映射之后,我們只需要記錄用戶第奇數(shù)次點(diǎn)擊背包的坐標(biāo),再在用戶第偶數(shù)次點(diǎn)擊背包的時(shí)候?qū)⑦@兩個(gè)坐標(biāo)所對(duì)應(yīng)的方格中的方塊互換即可。
此外,我也增加了對(duì)半分功能。如果用戶第偶數(shù)次點(diǎn)擊是用的右鍵且所點(diǎn)擊的方格中沒(méi)有方塊,那么就將上一次點(diǎn)擊的方格中的方塊分一半出來(lái)放到這次點(diǎn)擊的方塊中。
4.3.2 合成
合成是使我的世界這款游戲變得更加開(kāi)放的元素之一。利用合成這一功能,玩家可以使用已采集的方塊在背包的合成區(qū)內(nèi)合成新的方塊。那么這一功能是怎么實(shí)現(xiàn)的呢?
首先,為了方便我們之后的講解,我們來(lái)給合成區(qū)的十個(gè)格子命名一下。合成區(qū)中組成3*3的矩陣的那九個(gè)格子我將其命名為輸入?yún)^(qū),而單獨(dú)的那一個(gè)格子我將其命名為輸出區(qū)。
在合成的過(guò)程中,玩家需要按照合成配方在輸入?yún)^(qū)放入特定數(shù)量的方塊,并且從輸出區(qū)拿走合成的方塊。在拿走合成的方塊的同時(shí),方式在輸入?yún)^(qū)的方塊的數(shù)量應(yīng)當(dāng)按照合成配方減少。此外,為了防止合成的時(shí)候方塊被“吞掉”,我們規(guī)定玩家不能向輸出區(qū)中放置方塊。
現(xiàn)在的問(wèn)題就是如何判斷玩家放置在輸入?yún)^(qū)內(nèi)的方塊能否合成某種物品呢?寫特別多的if是不可取的,因?yàn)檫@么做不僅會(huì)降低代碼的可讀性和可擴(kuò)展性,也會(huì)增加程序的時(shí)間復(fù)雜度。我選擇將所有的合成配方都存儲(chǔ)在一個(gè)列表中,然后在每次玩家向輸入?yún)^(qū)中放置方塊之后檢查輸入?yún)^(qū)是否滿足列表中的某一個(gè)合成配方。如果有滿足,則將這個(gè)合成配方所對(duì)應(yīng)的合成物生成在輸出區(qū)中(注意此時(shí)不應(yīng)減少輸入?yún)^(qū)中的方塊,以便給玩家反悔的機(jī)會(huì))。一旦玩家取走輸出區(qū)的方塊,則相應(yīng)減少輸出區(qū)中的物品數(shù)量。
截止到目前,我所做出的合成配方包括木板、木棍、稿子、弓箭等,其中稿子和弓箭等道具也可以發(fā)揮它們的用處(稿子可以加快挖掘速度,弓箭可以射從小白那里撿來(lái)的箭)
后期改進(jìn)將在下一期公示
注:
我已經(jīng)將這個(gè)項(xiàng)目的源代碼和exe文件上傳到百度網(wǎng)盤中,點(diǎn)擊“閱讀原文”即可下載
鏈接:https://pan.baidu.com/s/1uSC3Xkf54w_iMkbIBzBK_Q?pwd=4l84
提取碼:4l84
從網(wǎng)頁(yè)版bilibili復(fù)制的鏈接會(huì)自動(dòng)加上出處和作者,粘貼在搜索欄中時(shí)記得刪除出處和作者,否則會(huì)提示鏈接無(wú)效