圖形用戶界面編程入門

本文介紹Don't Starve 圖形用戶界面(Graphical User Interface,簡(jiǎn)稱GUI)編程的基本概念,并給出簡(jiǎn)單的操作實(shí)例。

實(shí)例下載

基本概念

在Don't Starve中,圖形界面的核心由兩個(gè)大類組成:WidgetScreen。Widget是用于界面上的小組件的,比如說(shuō)一個(gè)物品欄,物品欄上的一個(gè)單元,都是一個(gè)簡(jiǎn)單的widget。Screen則是一整個(gè)界面,比如說(shuō)選項(xiàng)界面,小地圖界面等等。一個(gè)Screen里可以包含多個(gè)widget,一個(gè)widget也可以內(nèi)含許多widget。在游戲中,widget和screen并沒(méi)有明確的分界線,這里說(shuō)的概念也僅僅是一種邏輯上的區(qū)分而已。由于在GUI編程中,Widget是Screen開(kāi)發(fā)的基礎(chǔ),而且實(shí)際開(kāi)發(fā)中使用的頻率遠(yuǎn)遠(yuǎn)高于Screen,所以這里主要講解Widget,而把Screen作為拓展內(nèi)容。

Widget和Screen都只是一個(gè)基本類,要實(shí)現(xiàn)諸如按鈕,文字輸入等功能,則需要進(jìn)行擴(kuò)展,也就是繼承Widget或Screen類,在此基礎(chǔ)上更進(jìn)一步增加新的東西。官方已經(jīng)做好了一些常用功能的擴(kuò)展,包括按鈕,文字,圖片,動(dòng)畫等等。在聯(lián)機(jī)版里,為了進(jìn)一步節(jié)約開(kāi)發(fā)時(shí)間,官方還做了一些常用模板。這些模板是為固定情景而設(shè)計(jì)好的完整的Widget,可以簡(jiǎn)單地通過(guò)一兩句代碼調(diào)用,而無(wú)需再自行編寫復(fù)雜的Widget。

Child

在圖形編程中,常常會(huì)用到一個(gè)函數(shù)AddChild。這個(gè)函數(shù)會(huì)將傳遞進(jìn)來(lái)的對(duì)象設(shè)置成執(zhí)行這個(gè)函數(shù)的對(duì)象(我們稱為Parent)的一個(gè)Child。從而在Parent執(zhí)行一些操作時(shí),會(huì)讓Child同步執(zhí)行。
比如說(shuō),當(dāng)Parent的坐標(biāo)變化時(shí),Child的坐標(biāo)也會(huì)跟著變化。再比如說(shuō),Child的原點(diǎn)會(huì)被設(shè)置成Parent的坐標(biāo),從而使得Child的坐標(biāo)變成相對(duì)坐標(biāo),在調(diào)整時(shí)無(wú)需關(guān)心Child的屏幕坐標(biāo),只需要關(guān)心它相對(duì)于Parent的位置偏移就行了。這就使得Parent和Child變成一個(gè)緊密相連的整體,大大簡(jiǎn)化了相關(guān)的操作。

Hello Widget

大多數(shù)編程的學(xué)習(xí),都是從最簡(jiǎn)單的Hello World開(kāi)始,我們這里就從編寫一個(gè)可以在游戲內(nèi)頂部居中顯示"Hello Klei"的Widget開(kāi)始。
這需要做兩件事:

  1. 編寫一個(gè)Widget
  2. 把這個(gè)Widget加載到游戲里去

創(chuàng)建Widget

創(chuàng)建Widget是十分容易的,你只需要為你的widget想一個(gè)名字,比如Hello,然后在mod根目錄/scripts/widgets文件夾下創(chuàng)建一個(gè)lua文件hello.lua。然后寫一個(gè)類,繼承Widget類或它的一個(gè)子類即可。
一般來(lái)說(shuō),推薦直接繼承Widget,對(duì)于想要使用的特別功能,使用組合的方式來(lái)實(shí)現(xiàn)。這是因?yàn)?,在MOD制作者編寫的Widget通常是復(fù)合型的,比如可能同時(shí)含有按鈕和文本,這時(shí)候,無(wú)論是繼承Button類還是Text類,在邏輯上都是不合適的。正確的做法是,繼承Widget類,再在成員變量里按需要添加Button和Text。

首先,創(chuàng)建一個(gè)mod項(xiàng)目,然后在mod根目錄/scripts/widgets文件夾下創(chuàng)建一個(gè)lua文件hello.lua,然后,編寫代碼如下:

-- 首先,在文件的頭部寫上需要加載的Widget類
local Widget = require "widgets/widget" --Widget,所有widget的祖先類
local Text = require "widgets/text" --Text類,文本處理

local Hello = Class(Widget, function(self) -- 這里定義了一個(gè)Class,第一個(gè)參數(shù)是父類,第二個(gè)參數(shù)是構(gòu)造函數(shù),函數(shù)的參數(shù)第一個(gè)固定為self,后面的參數(shù)可以不寫,也可以自定義。
    Widget._ctor(self, "Hello") --這一句必須寫在構(gòu)造函數(shù)的第一行,否則會(huì)報(bào)錯(cuò)。
    --這表明調(diào)用父類的構(gòu)造函數(shù)(此處是Widget,如果繼承Text,則應(yīng)該寫Text._ctor),第一個(gè)參數(shù)是固定的self,后面的參數(shù)同這個(gè)父類的構(gòu)造函數(shù)的參數(shù),此處寫的是Widget的名字。
    --
    self.text = self:AddChild(Text(BODYTEXTFONT, 30,"Hello Klei")) --添加一個(gè)文本變量,接收Text實(shí)例。
end)

return Hello

如此就完成了Hello Widget的編寫。

加載Widget

Widget實(shí)質(zhì)上是一個(gè)小部件,它需要依附于screen才能使用。游戲里通過(guò)FrontEnd來(lái)調(diào)度不同的screen,從而顯示出不同的Widget供玩家查看和操作。
不過(guò),一般來(lái)說(shuō),用于MOD的widget,多數(shù)不需要直接依附于screen,而只需要依附于screen下的一個(gè)widget就行了。
以最常見(jiàn)的,為游戲中的操作界面添加widget為例,screen是HUD,但我們不需要讓自己編寫的widget直接依附在HUD上,只需要依附在controls這個(gè)widget上就行了。controls是一個(gè)大型的綜合性widget,玩家操作界面的物品欄,制作欄,狀態(tài)欄等等,都是由這個(gè)widget統(tǒng)一進(jìn)行管理的。

下面就來(lái)把Hello Widget添加到這個(gè)controls里。

在modmain.lua里添加如下內(nèi)容:

local hello = GLOBAL.require("widgets/hello") --加載hello類
local function addHelloWidget(self)
    self.hello = self:AddChild(hello())-- 為controls添加hello widget。
    self.hello:SetHAnchor(0) -- 設(shè)置原點(diǎn)x坐標(biāo)位置,0、1、2分別對(duì)應(yīng)屏幕中、左、右
    self.hello:SetVAnchor(1) -- 設(shè)置原點(diǎn)y坐標(biāo)位置,0、1、2分別對(duì)應(yīng)屏幕中、上、下
    self.hello:SetPosition(70,-50,0) -- 設(shè)置hello widget相對(duì)原點(diǎn)的偏移量,70,-50表明向右70,向下50,第三個(gè)參數(shù)無(wú)意義。
end
AddClassPostConstruct("widgets/controls", addHelloWidget) -- 這個(gè)函數(shù)是官方的MOD API,用于修改游戲中的類的構(gòu)造函數(shù)。第一個(gè)參數(shù)是類的文件路徑,根目錄為scripts。第二個(gè)自定義的修改函數(shù),第一個(gè)參數(shù)固定為self,指代要修改的類。

成果展示

開(kāi)啟MOD,隨便選個(gè)角色進(jìn)入游戲,你會(huì)在屏幕上方看到Hello Klei的字樣

demo.jpg

常用Widget

官方已經(jīng)編寫好了大量可用的Widget,包含了大量基本功能,聯(lián)機(jī)版更有許多模板可以直接使用。我們進(jìn)行圖形界面編程時(shí),通常不需要再費(fèi)時(shí)費(fèi)力地從頭編寫一個(gè)全新的Widget,大多數(shù)時(shí)候只需要使用官方提供的Widget進(jìn)行組合,甚至直接使用模板就足夠了。
這里只介紹一些常用的Widget及其子類,說(shuō)明基本功能和使用場(chǎng)景。在后續(xù)教程里會(huì)對(duì)常用的Widget和模板進(jìn)行詳細(xì)介紹,并提供可參考的實(shí)例。


Text/文本

文本類Text主要用于文本呈現(xiàn)和處理。
基類為Text,有一個(gè)擴(kuò)展子類:TextEdit

核心函數(shù)

構(gòu)造函數(shù)
: 文本類的主要功能就是文本呈現(xiàn),而類的構(gòu)造函數(shù)可以直接定義文本該以怎樣的形式呈現(xiàn)(字體,大小,內(nèi)容,顏色)

Text/文本

Text只提供文本呈現(xiàn)功能,能夠設(shè)置文本的字體,大小,內(nèi)容和顏色。Text的使用范圍十分廣泛,任何需要呈現(xiàn)文字的地方都需要用到Text。

TextEdit/文本編輯

TextEdit在文本呈現(xiàn)的基礎(chǔ)上,額外提供了文本編輯功能,主要用于各種輸入框,如聊天輸入框,控制臺(tái)輸入框等等。
它還有一個(gè)很特殊的擴(kuò)展子類TextEditLinked,用于禮品兌換碼的輸入框,一般不使用。

FollowText/跟隨文本

跟隨文本類FollowText,和Text很像,但不是Text的子類。與Text的區(qū)別在于它的位置是動(dòng)態(tài)變化的。常見(jiàn)應(yīng)用于顯示動(dòng)作的名字,比如,當(dāng)你手持斧頭時(shí),把光標(biāo)移動(dòng)到樹(shù)上,會(huì)出現(xiàn)兩個(gè)字——砍樹(shù)。


Image/圖片

圖片類Image,主要用于圖片呈現(xiàn),沒(méi)有子類。

核心函數(shù)

構(gòu)造函數(shù)
: 圖片類和文本類相似,主要功能就是圖片呈現(xiàn),可以定義圖片的atlas文件和tex名。


Button/按鈕

按鈕類Button主要提供一個(gè)點(diǎn)擊操作。通過(guò)設(shè)定點(diǎn)擊操作觸發(fā)的函數(shù),讓玩家可以通過(guò)執(zhí)行某些功能。

類名 描述
ImageButton 圖片按鈕,最常用
TextButton 文字按鈕,偶爾會(huì)用
ListCursor 列表游標(biāo),和拖動(dòng)條聯(lián)合使用。常用場(chǎng)景為服務(wù)器列表
AnimButton 動(dòng)畫按鈕,極少使用
UIAnimButton 界面動(dòng)畫按鈕,極少使用

基類為Button,子類如下表:

類名 描述
ImageButton 圖片按鈕,最常用
TextButton 文字按鈕,偶爾會(huì)用
ListCursor 列表游標(biāo),和拖動(dòng)條聯(lián)合使用。常用場(chǎng)景為服務(wù)器列表
AnimButton 動(dòng)畫按鈕,極少使用
UIAnimButton 界面動(dòng)畫按鈕,極少使用

基類Button僅僅定義了點(diǎn)擊觸發(fā)函數(shù)的功能,但沒(méi)有定義它該以何種形式來(lái)呈現(xiàn)在玩家操作界面上。在實(shí)際使用中,通常不直接使用基類Button,而是根據(jù)情況使用它的各種子類,其中最為常用的是ImageButton。

核心函數(shù)

按鈕的主要功能就是在點(diǎn)擊后觸發(fā)函數(shù),因此設(shè)置點(diǎn)擊觸發(fā)函數(shù)的函數(shù)就是核心函數(shù)。

SetOnDown( fn )
: 設(shè)置按下按鈕彈起前觸發(fā)的函數(shù)

SetOnClick(fn)
: 設(shè)置按下按鈕彈起后觸發(fā)的函數(shù)

以上兩個(gè)設(shè)置函數(shù)里設(shè)置的fn,是沒(méi)有參數(shù)的。

ImageButton/圖片按鈕

大多數(shù)按鈕都屬于圖片按鈕,可以直接在構(gòu)造圖片按鈕實(shí)例時(shí)傳入atlas(該按鈕圖片的統(tǒng)一管理xml文件), normal(一般狀態(tài)下的圖片,下面的類似), focus(聚焦?fàn)顟B(tài)), disabled(不可用狀態(tài)), down(按下?tīng)顟B(tài)), selected(選中狀態(tài)), image_scale(圖片縮放大?。? image_offset(圖片偏移量)等一系列參數(shù)。
對(duì)于缺失的參數(shù),會(huì)使用缺省值代替。所以在使用時(shí),不寫任何參數(shù)也是可以的。


Badge/徽章

徽章類Badge,主要用于呈現(xiàn)一個(gè)圓形物體的動(dòng)畫,常見(jiàn)應(yīng)用是各種指示器:饑餓度、精神度、血量、木頭值(吳迪),通過(guò)設(shè)置動(dòng)畫播放的百分比來(lái)指示某個(gè)數(shù)值的多少。

特別提醒:Badge使用的動(dòng)畫通常是逆過(guò)來(lái)的,也就是100%的狀態(tài)在開(kāi)端,0%的狀態(tài)在結(jié)尾。這是為了保證狀態(tài)為100%時(shí)一定能播放出相應(yīng)的動(dòng)畫關(guān)鍵幀。(動(dòng)畫的0幀一定能播放出來(lái),但最后一幀則不一定)。

類名 描述
HungerBadge 饑餓指示器
SanityBadge 精神指示器
HealthBadge 血量指示器
BeaverBadge 木頭值指示器

基類為Badge,子類如下表:

類名 描述
HungerBadge 饑餓指示器
SanityBadge 精神指示器
HealthBadge 血量指示器
BeaverBadge 木頭值指示器

核心函數(shù)

構(gòu)造函數(shù)
: animname, states分別指明要使用的動(dòng)畫build/bank名(build和bank名必須一致)和anim名。通常的使用方式是,拓展成一個(gè)新的子類,在父類構(gòu)造函數(shù)中填寫animname和states,具體可以參考已有的官方子類。

SetPercent(val, max)
: 設(shè)置動(dòng)畫播放的百分比。

最后編輯于
?著作權(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)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評(píng)論 25 708
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,692評(píng)論 4 61
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 7,389評(píng)論 0 17
  • 漢代·劉向《新序·雜事五》:“葉公子高好龍,鉤以寫龍,鑿以寫龍,屋室雕文以寫龍。于是天龍聞而下之,窺頭于牖,施尾于...
    清凈墨蓮閱讀 543評(píng)論 0 0
  • 學(xué)生公寓樓下掛著一個(gè)牌子: 請(qǐng)畢業(yè)生盡快搬離學(xué)生公寓并到值班處退還寢室鑰匙。 今年夏天悄然而至,如同往常一樣,沒(méi)有...
    大白兔奶精閱讀 6,064評(píng)論 11 27

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