先拋開UI部分暫且不論,需要什么:
- 在世界中存在的能夠被拾取的Actor
- 角色能夠知道附近有哪些Actor能夠被拾取
- 存儲已拾取的,裝進背包的Actor
- 能夠將背包中的的Actor扔出去
-
使用Interface標記Actor將能實現最靈活的配置,
新建一個藍圖接口命名為PickupInterface。
添加兩個函數分別是【Pickup】【Discard】
Pickup函數輸入值新建一個PlayerController,輸出則為一個布爾值,判斷是否成功拾取
Pickup函數
Discard則只需要一個為布爾變量的輸出值,作用也是判斷是否成功丟掉
Discard -
在角色藍圖中創建一個碰撞組件用于檢測實現了PickupInterface接口的Actor
我這里使用的是Box碰撞體。
Collision
將它的碰撞預設改為OverlapAllDynamic,并添加兩個事件
CheckPickupCollision
在角色藍圖中新建一個Actor數組變量,這個值不需要同步,用于存儲附近的實現了PickupInterface接口的Actor。
添加兩個自定義事件,檢測傳入的Actor值是否實現了PickupInterface接口。
Nearby
在BoxCollision的Begin Overlap和End Overlap事件中分別使用:
BoxCollision -
已拾取的Actor,背包中的Actor存儲使用PlayerState來實現。
PlayerState
創建一個Actor數組并將復制模式設為Replicated,復制條件設為OwnerOnly(只在服務器和所屬客戶端復制,可有有效減少網絡傳輸量,缺點也很明顯,其他客戶端沒有更新)
實現添加Pickup和移除Pickup的函數:
前綴帶[Server]字樣的函數是RPC函數,他們的復制屬性為在服務器上運行并設為可靠函數(網絡的傳輸非常多樣化,可靠傳輸意味著一定會執行,但相較于不可靠函數,會損失一定的時間性能)
RPC函數
代碼層的框架已經ok了。
分析絕地求生的UI
我們能夠顯而易見的分成三部分(背包與附近裝備列表[左],角色的實時顯示[中],武器裝備[右])
這篇教程就先實現左邊的。
我們再把左邊給拆開分析
綠框中的是顯示背包容積的進度條[Progress Bar]
紅框中的是兩個能夠滑動的控件[Scroll Box]
我們可以把紅框中顯示裝備列表給封裝起來,封裝的目的是可復用性,其使用方法就跟我們使用普通的小控件如滑動條,還可以在游戲中動態的創建控件。
列表中都是由一個個這個封裝起來的
而item又分為三部分,分別是左邊的圖片,中間的名字,右邊的數量,如果為不可以合并的裝備則會隱藏掉。
最小控件Item的制作 [ActionItem]
由上圖分析出控件的排列為左右結構,我們可以使用[Horizontal Box] (Panel Widget:不會渲染出來,用于對 Child Widget 進行布局)。左右空間還有不同的不透明度,使用[Border]。具體的文字圖片為[Text][Image]
關于細節:
- 窗口尺寸變成長條形,其目的僅僅是方便顯示我們能夠直觀看出效果
- 中間用于顯示名字的控件將使用填充作為父控件的計算方式
- 啟用[Text]AutoWrapText自動換行,垂直居中
- 子控件的Padding默認為(4,2),如有必要請歸零
-
打開子控件的Is Varible
外觀
層次結構
每個控件的具體參數下載示例查看。
觀察上圖,我們需要幾個參數: - Image 顯示的圖標
-
Name 子項的名字
創建一個結構體方便傳遞和使用
ActionItemInfo
參數
回到PickupInterface添加一個函數【GetActionInfo】
在ActionItem中添加PickupActor的引用并在生成時顯示:
ActionItem
在其構造事件中:
ActionItem
拖拽
在ActionItem中實現拖拽的檢測和創建拖拽時使用的對象
需要覆寫如下2個函數分別實現檢測和創建【OnMouseButtonDown】【OnDragDetected】
列表的創建
由于我們需要在列表中覆寫OnDrop事件,但是[附近的]與[背包中的]它們的OnDrop處理事件是不同的,所以我要分開來寫。
InventoryList
藍圖方面創建一個更新列表的函數,也只需要這一個函數,因為列表的管理不是由Widget進行管理的,Widget僅僅是起到一個通知(給玩家)的作用:
InventoryList與NearbyList都是有如上部分的,唯一的不同就是OnDrop的處理,在InventoryList是添加進庫存,而在NearbyList中是移除:
我們先在MyCharacter中添加如下兩個函數:
回到InventoryList,覆寫OnDrap:
之后復制一份InventoryList重命名為【NearbyList】,修改OnDrap:
MainInventoryWidget的制作:
在MyCharacter中顯示背包
并在MyPlayerState中使用通知接口:
使用示例
創建一個Actor,重命名為PickupActor,啟用復制和復制移動屬性,并添加一個StaticMesh (把mesh隨便設置一個,我設置的是cube),
打開類設置并實現接口PickupInterface
創建一個自定義事件,并設置復制為多路傳送,啟用可靠函數:
實現接口的函數:
接下來你就可以拖進場景使用了,
還有很多細節未修復,比如釋放actor值的位置,應該是放在地板上。等等
也有很多的功能尚未實現(比如網絡延遲情況下的處理,類似于子彈多個數據的打包),我會在接下來的教程一一完善