先拋開(kāi)UI部分暫且不論琅坡,需要什么:
- 在世界中存在的能夠被拾取的Actor
- 角色能夠知道附近有哪些Actor能夠被拾取
- 存儲(chǔ)已拾取的忧勿,裝進(jìn)背包的Actor
- 能夠?qū)⒈嘲械牡腁ctor扔出去
-
使用Interface標(biāo)記Actor將能實(shí)現(xiàn)最靈活的配置阀蒂,
新建一個(gè)藍(lán)圖接口命名為PickupInterface。
添加兩個(gè)函數(shù)分別是【Pickup】【Discard】
Pickup函數(shù)輸入值新建一個(gè)PlayerController袭厂,輸出則為一個(gè)布爾值计济,判斷是否成功拾取
Pickup函數(shù)
Discard則只需要一個(gè)為布爾變量的輸出值,作用也是判斷是否成功丟掉
Discard -
在角色藍(lán)圖中創(chuàng)建一個(gè)碰撞組件用于檢測(cè)實(shí)現(xiàn)了PickupInterface接口的Actor
我這里使用的是Box碰撞體各吨。
Collision
將它的碰撞預(yù)設(shè)改為OverlapAllDynamic枝笨,并添加兩個(gè)事件
CheckPickupCollision
在角色藍(lán)圖中新建一個(gè)Actor數(shù)組變量,這個(gè)值不需要同步揭蜒,用于存儲(chǔ)附近的實(shí)現(xiàn)了PickupInterface接口的Actor横浑。
添加兩個(gè)自定義事件,檢測(cè)傳入的Actor值是否實(shí)現(xiàn)了PickupInterface接口屉更。
Nearby
在BoxCollision的Begin Overlap和End Overlap事件中分別使用:
BoxCollision -
已拾取的Actor徙融,背包中的Actor存儲(chǔ)使用PlayerState來(lái)實(shí)現(xiàn)。
PlayerState
創(chuàng)建一個(gè)Actor數(shù)組并將復(fù)制模式設(shè)為Replicated瑰谜,復(fù)制條件設(shè)為OwnerOnly(只在服務(wù)器和所屬客戶端復(fù)制欺冀,可有有效減少網(wǎng)絡(luò)傳輸量树绩,缺點(diǎn)也很明顯,其他客戶端沒(méi)有更新)
實(shí)現(xiàn)添加Pickup和移除Pickup的函數(shù):
前綴帶[Server]字樣的函數(shù)是RPC函數(shù)隐轩,他們的復(fù)制屬性為在服務(wù)器上運(yùn)行并設(shè)為可靠函數(shù)(網(wǎng)絡(luò)的傳輸非常多樣化饺饭,可靠傳輸意味著一定會(huì)執(zhí)行,但相較于不可靠函數(shù)职车,會(huì)損失一定的時(shí)間性能)
RPC函數(shù)
代碼層的框架已經(jīng)ok了瘫俊。
分析絕地求生的UI
我們能夠顯而易見(jiàn)的分成三部分(背包與附近裝備列表[左],角色的實(shí)時(shí)顯示[中]悴灵,武器裝備[右])
這篇教程就先實(shí)現(xiàn)左邊的扛芽。
我們?cè)侔炎筮吔o拆開(kāi)分析
綠框中的是顯示背包容積的進(jìn)度條[Progress Bar]
紅框中的是兩個(gè)能夠滑動(dòng)的控件[Scroll Box]
我們可以把紅框中顯示裝備列表給封裝起來(lái),封裝的目的是可復(fù)用性积瞒,其使用方法就跟我們使用普通的小控件如滑動(dòng)條川尖,還可以在游戲中動(dòng)態(tài)的創(chuàng)建控件。
列表中都是由一個(gè)個(gè)這個(gè)封裝起來(lái)的
而item又分為三部分茫孔,分別是左邊的圖片叮喳,中間的名字,右邊的數(shù)量银酬,如果為不可以合并的裝備則會(huì)隱藏掉。
最小控件Item的制作 [ActionItem]
由上圖分析出控件的排列為左右結(jié)構(gòu)筐钟,我們可以使用[Horizontal Box] (Panel Widget:不會(huì)渲染出來(lái)揩瞪,用于對(duì) Child Widget 進(jìn)行布局)。左右空間還有不同的不透明度篓冲,使用[Border]李破。具體的文字圖片為[Text][Image]
關(guān)于細(xì)節(jié):
- 窗口尺寸變成長(zhǎng)條形,其目的僅僅是方便顯示我們能夠直觀看出效果
- 中間用于顯示名字的控件將使用填充作為父控件的計(jì)算方式
- 啟用[Text]AutoWrapText自動(dòng)換行壹将,垂直居中
- 子控件的Padding默認(rèn)為(4,2)嗤攻,如有必要請(qǐng)歸零
-
打開(kāi)子控件的Is Varible
外觀
層次結(jié)構(gòu)
每個(gè)控件的具體參數(shù)下載示例查看。
觀察上圖诽俯,我們需要幾個(gè)參數(shù): - Image 顯示的圖標(biāo)
-
Name 子項(xiàng)的名字
創(chuàng)建一個(gè)結(jié)構(gòu)體方便傳遞和使用
ActionItemInfo
參數(shù)
回到PickupInterface添加一個(gè)函數(shù)【GetActionInfo】
在ActionItem中添加PickupActor的引用并在生成時(shí)顯示:
ActionItem
在其構(gòu)造事件中:
ActionItem
拖拽
在ActionItem中實(shí)現(xiàn)拖拽的檢測(cè)和創(chuàng)建拖拽時(shí)使用的對(duì)象
需要覆寫(xiě)如下2個(gè)函數(shù)分別實(shí)現(xiàn)檢測(cè)和創(chuàng)建【OnMouseButtonDown】【OnDragDetected】
列表的創(chuàng)建
由于我們需要在列表中覆寫(xiě)OnDrop事件,但是[附近的]與[背包中的]它們的OnDrop處理事件是不同的暴区,所以我要分開(kāi)來(lái)寫(xiě)闯团。
InventoryList
藍(lán)圖方面創(chuàng)建一個(gè)更新列表的函數(shù)房交,也只需要這一個(gè)函數(shù),因?yàn)榱斜淼墓芾聿皇怯蒞idget進(jìn)行管理的伐割,Widget僅僅是起到一個(gè)通知(給玩家)的作用:
InventoryList與NearbyList都是有如上部分的候味,唯一的不同就是OnDrop的處理刃唤,在InventoryList是添加進(jìn)庫(kù)存,而在NearbyList中是移除:
我們先在MyCharacter中添加如下兩個(gè)函數(shù):
回到InventoryList白群,覆寫(xiě)OnDrap:
之后復(fù)制一份InventoryList重命名為【NearbyList】尚胞,修改OnDrap:
MainInventoryWidget的制作:
在MyCharacter中顯示背包
并在MyPlayerState中使用通知接口:
使用示例
創(chuàng)建一個(gè)Actor辐真,重命名為PickupActor,啟用復(fù)制和復(fù)制移動(dòng)屬性崖堤,并添加一個(gè)StaticMesh (把mesh隨便設(shè)置一個(gè)侍咱,我設(shè)置的是cube),
打開(kāi)類設(shè)置并實(shí)現(xiàn)接口PickupInterface
創(chuàng)建一個(gè)自定義事件密幔,并設(shè)置復(fù)制為多路傳送楔脯,啟用可靠函數(shù):
實(shí)現(xiàn)接口的函數(shù):
接下來(lái)你就可以拖進(jìn)場(chǎng)景使用了,
還有很多細(xì)節(jié)未修復(fù)胯甩,比如釋放actor值的位置昧廷,應(yīng)該是放在地板上。等等
也有很多的功能尚未實(shí)現(xiàn)(比如網(wǎng)絡(luò)延遲情況下的處理偎箫,類似于子彈多個(gè)數(shù)據(jù)的打包)木柬,我會(huì)在接下來(lái)的教程一一完善