Don'tStarve Mod編程綜述

概述

這篇文章會(huì)闡述Don'tStarve代碼的整體框架,幫助Mod新手們快速了解Don'tStarve Mod能實(shí)現(xiàn)哪些功能,需要做哪些基本的配置,以利于有目的有針對(duì)性地進(jìn)行學(xué)習(xí)。
首先從整體上來了解一下Don'tStarve MOD的概念。

能干什么

你能夠添加自己制作的內(nèi)容(物品,人物,生物等等),新的屏幕界面/操作(Widget,Screen),也能夠修改游戲原有的內(nèi)容,甚至連其它MOD的內(nèi)容都能修改(只要它們?cè)谟螒蛑斜粏?dòng)并接入了游戲系統(tǒng))。Don'tStarve是個(gè)高度開放的游戲,除了底層引擎和部分十分消耗資源的操作外,大部分的游戲內(nèi)容都是用Lua語言編寫的。它們被公開地集中存放在游戲根目錄/data/scripts下。這就意味著,只要你懂得如何尋找lua文件,并能夠讀懂源代碼,你就能自己實(shí)現(xiàn)、或者修改游戲里的已有內(nèi)容。也就是說饑荒的MOD上限是非常高的,隨著你的能力增長(zhǎng),你就能夠大幅度地修改Don'tStarve,甚至重造一個(gè)全新的世界。

怎么實(shí)現(xiàn)

這是通過游戲提供的一系列API實(shí)現(xiàn)的。下面的基本原理一節(jié)會(huì)提到API是什么。

如何學(xué)習(xí)

學(xué)習(xí)MOD制作知識(shí),最終目的就是為了制作并發(fā)布我們自己的MOD。與其漫無目的進(jìn)行學(xué)習(xí),不如用項(xiàng)目驅(qū)動(dòng)學(xué)習(xí),更有目的性也更清楚自己到底掌握了什么知識(shí)。
所以,我們以0基礎(chǔ)為起點(diǎn),完成并發(fā)布一個(gè)自己想要的MOD為終點(diǎn),來說明MOD制作知識(shí)的學(xué)習(xí)流程。

流程.png

這里所指的游戲邏輯是豐富而復(fù)雜的,短時(shí)間內(nèi)全部學(xué)習(xí)完是不現(xiàn)實(shí)也是不必要的。我們要學(xué)習(xí)的是與自己想要實(shí)現(xiàn)的功能相關(guān)的游戲邏輯,知道如何進(jìn)行修改或者添加,然后再掌握相應(yīng)的MOD API來進(jìn)行修改。從想法萌發(fā)到完全實(shí)現(xiàn)并發(fā)布,中間的距離有多遠(yuǎn)?你可以根據(jù)這個(gè)流程圖來大致估計(jì)一下。在這里面,知識(shí)量最大,也最為重要的部分,就是游戲邏輯。如果你熟悉游戲,并且充滿想象力,那么就很容易將你想要實(shí)現(xiàn)的功能與游戲里的某些功能聯(lián)系起來。進(jìn)而可以通過閱讀相關(guān)的源碼來獲得更多的細(xì)節(jié)信息。

預(yù)備知識(shí)

Don'tStarve MOD是用Lua語言編寫的,很顯然,在正式開始寫MOD之前,你需要了解一些基本的Lua語法,否則,看不懂代碼,寫就無從談起。但編寫入門級(jí)的Don'tStarve Mod,只需要了解編程語言通用的基礎(chǔ)知識(shí)就足夠了(數(shù)據(jù)類型,變量,循環(huán),流程控制,函數(shù),運(yùn)算符,數(shù)組,表)。菜鳥驛站的教程能夠幫助你短時(shí)間內(nèi)快速入門。在這篇文章中我并不打算講解代碼的基本含義。能夠自行閱讀源碼,是一個(gè)打算做Mod編程的人所必需掌握的能力。源碼的閱讀能力取決于你的編程基礎(chǔ),以及你積累的Don'tStarve API知識(shí)的多少。

基本原理

運(yùn)行

游戲利用Lua語言的特性,為每一個(gè)啟動(dòng)了的MOD提供一個(gè)獨(dú)立的運(yùn)行環(huán)境,不僅獨(dú)立于其它MOD,也獨(dú)立于游戲本身的運(yùn)行環(huán)境,這意味著,游戲系統(tǒng)以及不同的MOD下的同名的(MOD語義下的)全局變量,不會(huì)對(duì)彼此形成干擾。游戲的制作者們?yōu)镸OD制作提供了大量的API,利用這些API,MOD制作者們可以修改游戲本身的內(nèi)容,獲取其它MOD的信息甚至修改它們。也可以向游戲添加各種新的內(nèi)容。

API

接觸編程不久的人可能會(huì)疑惑什么是API。在Don'tStarve MOD的語境下,API主要是指官方提供的一系列預(yù)定義了訪問規(guī)則的公共函數(shù)。我們只要了解這些函數(shù)的訪問規(guī)則(傳入什么參數(shù),獲得什么樣的效果,返回值是什么),就可以很輕松地使用它,而不必關(guān)心這個(gè)函數(shù)時(shí)如何被實(shí)現(xiàn)的。
Don'tStarve MOD中的API分為兩種類型。一種類型是寫在modutil.lua文件下的API,這種API必須在mod提供的運(yùn)行環(huán)境下運(yùn)行,不妨稱之為MOD API。它們提供了一系列接入游戲環(huán)境的接口。但本身并不具備修改功能。你只是通過這個(gè)接口,獲取了游戲系統(tǒng)的某些內(nèi)容。對(duì)這些內(nèi)容的修改,會(huì)由MOD API保存下來。除了修改,你還可以增加或刪除內(nèi)容,但本質(zhì)上并無區(qū)別:增加或刪除內(nèi)容,在一個(gè)更大的層次上也可以看作對(duì)更大范圍的內(nèi)容的修改。
第二種類型則是游戲系統(tǒng)的API,一般是指component或widget,以及一些公有的工具函數(shù)。這類API是游戲系統(tǒng)邏輯的組成部分。你不僅可以使用它們,甚至還可以通過MOD API來修改它們。饑荒的游戲邏輯并不完美,直到現(xiàn)在,仍然有很多的Bug。而你如果熟悉游戲系統(tǒng)邏輯,就可以通過MOD API來修補(bǔ)這些Bug。在熟悉游戲邏輯的情況下,你甚至可以通過MOD API提供的接口來重構(gòu)游戲系統(tǒng)邏輯。

結(jié)構(gòu)

了解游戲的代碼組織結(jié)構(gòu),才能更有效率地學(xué)習(xí)游戲邏輯。
Don'tStarve 這個(gè)游戲世界,是由一個(gè)一個(gè)prefab類的對(duì)象組成的。我們大部分的修改,都是在prefab的基礎(chǔ)上進(jìn)行的。Prefab本身只具備一些基本的功能,要想實(shí)現(xiàn)更多的功能,需要給Prefab添加各種不同的component。簡(jiǎn)單地說,prefab描述了一個(gè)東西是什么,而component則描述了這個(gè)東西能干什么。一個(gè)prefab搭載多個(gè)不同的component,就足以完成Don'tStarve 里最基本的東西了。

我們可以從這個(gè)基本的prefab-components的構(gòu)成結(jié)構(gòu)引出一種非常實(shí)用的MOD編寫技術(shù)——遷移法。這種方式是每個(gè)有志于制作出高級(jí)Don'tStarve MOD的人都必須掌握的技術(shù),這是了解游戲邏輯的基礎(chǔ)。

遷移法:當(dāng)我們想要在某個(gè)物品上添加一項(xiàng)功能而不知道該怎么實(shí)現(xiàn)的時(shí)候,可以思考一下這個(gè)功能是否在游戲中已經(jīng)存在或者有類似的存在。如果有的話,再看一下是哪個(gè)物品擁有這項(xiàng)功能,然后閱讀這個(gè)物品的源碼,看看它由哪些component構(gòu)成,找出想要實(shí)現(xiàn)的功能對(duì)應(yīng)的component,再仿照相關(guān)代碼來寫,就能得到想要的結(jié)果了。

在這個(gè)最基本的東西上,如果一個(gè)Prefab的動(dòng)畫、聲音很多,為了方便管理不同狀態(tài)下的不同動(dòng)畫、聲音表現(xiàn),就需要添加StateGraph。如果是一個(gè)需要表現(xiàn)出一定智能的生物,就需要添加Brain。另外,如果要表達(dá)某些特征,就需要使用Tag系統(tǒng)。還有事件監(jiān)聽,環(huán)境檢測(cè)等等系統(tǒng),都需要依附于Prefab來進(jìn)行。而人物的操作很多時(shí)候需要借助交互面板,比如說物品欄,裝備欄,制作欄等等,這就涉及到了widget了,如果widget更大一些,比如占到了全屏幕或者半個(gè)屏幕,而且玩家在使用這個(gè)交互的時(shí)候處于長(zhǎng)時(shí)間閑置的狀態(tài),那就可以轉(zhuǎn)為screen。

下面來展開詳細(xì)講講各個(gè)部分。

Component(組件)

為什么要先從component(組件)開始講呢?因?yàn)檫@更符合我們的游戲認(rèn)知。對(duì)于游戲,我們?cè)诿枋鲆粋€(gè)物品的時(shí)候,通常都是在描述它的屬性以及和屬性密切相關(guān)的功能。我們要做一個(gè)物品或者修改一個(gè)物品,也主要是從功能入手。在Don'tStarve的系統(tǒng)中,這被抽象成了component,不同的屬性用不同的component來實(shí)現(xiàn)。
一個(gè)物品可能有很多種屬性,就可以用不同的component來描述。比如說人物,擁有三項(xiàng)基本屬性-饑餓,精神和健康,這在Don't Starve里被分別抽象成三個(gè)組件hunger,sanity和health。
Component在本質(zhì)上只是一個(gè)類,它儲(chǔ)存一些變量,提供一些方法對(duì)這些變量進(jìn)行操作。官方制作者們還提供了一些約定的函數(shù)供我們重寫使用,如OnSave函數(shù),可以用于在游戲退出時(shí)保存組件中的變量,OnLoad函數(shù),可以讀取OnSave保存的結(jié)果,OnUpdate函數(shù),則可以在執(zhí)行了StartUpdatingComponent后持續(xù)被執(zhí)行,從而實(shí)現(xiàn)高頻更新。
總而言之,component可以理解為物體的某一個(gè)功能或某一類功能。

Prefab(預(yù)設(shè)物)

正如現(xiàn)實(shí)生活中要描述一個(gè)功能必須要借助一個(gè)物體,在游戲中,組件也必須要依附于一個(gè)物體才能發(fā)揮功能。在游戲里,這樣的物體被抽象成一個(gè)類,Prefab。Prefab是源自Unity3D的術(shù)語,翻譯為預(yù)設(shè)物。Prefab的出現(xiàn),使得我們免去了大量編寫類的煩惱。我們不再需要為每一把武器,每一個(gè)工具單獨(dú)寫一個(gè)類,只需要把他們統(tǒng)統(tǒng)歸為Prefab,然后在各自的構(gòu)造函數(shù)中設(shè)置不同的組件來讓它們擁有不同的功能就行了。比如說武器擁有weapon組件,表明了自己是一個(gè)武器,能戰(zhàn)斗,為人物提供額外的攻擊力;再比如說斧頭擁有tool組件,表明自己是一個(gè)工具,能砍樹。

弄明白Prefab和Component已經(jīng)足夠做出簡(jiǎn)單的MOD了。下面的內(nèi)容較深,需要有一定的MOD經(jīng)驗(yàn)才能明白,初入門的讀者可以先按簡(jiǎn)單教程做出一些簡(jiǎn)單的東西之后再來深入研究。

StateGraph(狀態(tài)圖)

這個(gè)概念并不是那么好理解,因?yàn)樗醋杂谟?jì)算機(jī)理論中的Graph(圖)。
讓我們從wilson開始談起。wilson在進(jìn)入游戲,經(jīng)過開場(chǎng)動(dòng)畫之后,會(huì)站著一動(dòng)不動(dòng)。實(shí)際上這時(shí)候他的動(dòng)畫控制器(AnimState)在播放名為"idle"的動(dòng)畫。過了幾秒之后,根據(jù)周圍環(huán)境以及自身狀態(tài)的不同,會(huì)播放以下動(dòng)畫之一:發(fā)抖動(dòng)畫(環(huán)境氣溫較低),擦汗動(dòng)畫(氣溫較高),捂肚子動(dòng)畫(饑餓度較低),捂頭動(dòng)畫(精神較低),踢石頭動(dòng)畫(不滿足前面的特殊條件)。如果你讓wilson去檢查某件物品,他就會(huì)說話,
播放人物的聲音,以及說話的動(dòng)畫。
我們很容易在上面這段場(chǎng)景中,將人物分為三種不同的狀態(tài),第一種是剛進(jìn)入游戲時(shí)的,一動(dòng)不動(dòng)的閑置狀態(tài)。第二種是閑置(idle)狀態(tài)下不進(jìn)行操作,幾秒之后自動(dòng)進(jìn)入的趣味閑置(funny_idle)狀態(tài),第三種是檢查物品時(shí)進(jìn)入的說話狀態(tài)(talk)。
游戲制作者把狀態(tài)抽象成了一個(gè)類-State,這個(gè)類定義在stategraph.lua文件下。可以設(shè)置多項(xiàng)屬性,讓你能夠描述一個(gè)狀態(tài)的全過程,并且,可以借助EventHandler來完成狀態(tài)之間的連結(jié)。一個(gè)個(gè)State,就構(gòu)成了StateGraph的基礎(chǔ),在圖論里,State可以被視為Node(結(jié)點(diǎn))。idle,是游戲開始時(shí)人物所處的狀態(tài),也就是初始狀態(tài)結(jié)點(diǎn),每一次進(jìn)入StateGraph,都是從idle開始的。官方設(shè)定的StateGraph,大多數(shù)狀態(tài)結(jié)點(diǎn)在執(zhí)行完一整套流程后,也會(huì)回歸idle結(jié)點(diǎn)。有了結(jié)點(diǎn),自然還需要有連接結(jié)點(diǎn)的方式,這在圖論里叫做Edge(邊)。所為連接,就是定義如何由一個(gè)結(jié)點(diǎn)跳轉(zhuǎn)到另一個(gè)結(jié)點(diǎn)。這是通過StateGraph提供的名為GoToState的函數(shù)實(shí)現(xiàn)的,你可以使用這個(gè)函數(shù)來跳轉(zhuǎn)到任意一個(gè)state上。下一個(gè)問題是,要在什么時(shí)候進(jìn)行跳轉(zhuǎn)。這一般可以通過ActionHandler或者EventHandler來設(shè)置。ActionHandler通過action來觸發(fā)處理函數(shù),比如說你吃東西,觸發(fā)了進(jìn)食動(dòng)作,就會(huì)跳轉(zhuǎn)到進(jìn)食狀態(tài)。EventHandler通過事件來觸發(fā)處理函數(shù)。最常用的就是"animover"或"animqueueover",前者表示當(dāng)前動(dòng)畫結(jié)束,后者表示當(dāng)前動(dòng)畫序列結(jié)束。
總的來說,StateGraph就是一個(gè)典型的Graph,結(jié)點(diǎn)是State,邊是GoToState。要了解更多更詳細(xì)的信息,可以參考stategraph.lua文件下定義的StateGraph類,實(shí)例可以在stategraphs文件夾下隨意找一個(gè)SGxxx打開,比較適合學(xué)習(xí)的是SGwilson。

Brain(AI)

這個(gè)概念比StateGraph更難理解。它的主要作用是為生物設(shè)置AI。Brain是以行為樹(BehaviourTree)的方式實(shí)現(xiàn)的,不了解什么是行為樹的話,你就很難去閱讀Brain的代碼,更別說去寫自己的AI了。行為樹是很復(fù)雜的,我在這方面積累的經(jīng)驗(yàn)也遠(yuǎn)遠(yuǎn)不夠,沒有辦法通過三言兩語講明白,以后有時(shí)間再寫一篇文章專門進(jìn)行講解。

Widget和Screen

這兩個(gè)概念的分界并不是十分明顯,連官方都會(huì)把他們混淆在一起(某些Screen子類放在了widgets文件夾下),所以我就一起說了。這兩個(gè)概念都是用于游戲界面編寫的,接觸過圖形界面編程的讀者,對(duì)這一方面應(yīng)該比較容易理解。一般來說,小部件比如一個(gè)按鈕,一個(gè)對(duì)話框,可以當(dāng)作是一個(gè)widget,多個(gè)widget也可以組合成一個(gè)大的widget。而如果占用的屏幕范圍比較大,甚至引起游戲暫停(如切換顯示地圖),就可以歸為Screen了。由于官方?jīng)]有給出任何規(guī)范,因此你完全可以隨意地進(jìn)行使用。widgets文件夾下有各種widget類,他們都有共同的祖先類-Widget,screens文件夾下的各種screen類則是繼承自Screen類。游戲里已經(jīng)提供了足夠豐富的基本類,比如Button,Text等。你可以在這些基本類上進(jìn)行繼承擴(kuò)展,也可以使用游戲原本就提供的擴(kuò)展類,甚至可以使用它們提供的模板類(在widgets/templates.lua下)。
游戲界面的編寫也是值得再開一篇文章講的,這里不再贅述。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這一章講解Prefab。Prefab是饑荒世界構(gòu)成的基礎(chǔ),也是Mod技術(shù)的基本內(nèi)容。 Prefab,中文譯名叫預(yù)制...
    LongFei_aot閱讀 16,812評(píng)論 6 40
  • 這個(gè)系列教程很長(zhǎng),涉及到很多編程、游戲方面的概念。與其讓你云里霧里地看著看著就放棄,不如先教你如何快速入門,通過模...
    LongFei_aot閱讀 13,713評(píng)論 9 77
  • 本章的目的是為了幫助你了解Mod知識(shí)的全貌,把握學(xué)習(xí)的節(jié)奏。如果你急著學(xué)習(xí)更多的技術(shù)知識(shí),可以先跳過本章,不會(huì)影響...
    LongFei_aot閱讀 4,235評(píng)論 3 27
  • 饑荒分為單機(jī)版和聯(lián)機(jī)版,一般來說,內(nèi)容相同的MOD,聯(lián)機(jī)版相對(duì)單機(jī)版來說,總是要多一些對(duì)網(wǎng)絡(luò)數(shù)據(jù)的處理,總歸是要復(fù)...
    LongFei_aot閱讀 8,768評(píng)論 1 17
  • 這一章的目標(biāo)是介紹Mod基本結(jié)構(gòu),讓你能夠更好地組織代碼和各種靜態(tài)資源。 饑荒Mod采用了隔離良好的設(shè)計(jì),每個(gè)Mo...
    LongFei_aot閱讀 7,532評(píng)論 0 26

友情鏈接更多精彩內(nèi)容