先抛开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
![](https://img.haomeiwen.com/i12516875/99f74381bb88fbc4.png)
我们能够显而易见的分成三部分(背包与附近装备列表[左],角色的实时显示[中],武器装备[右])
这篇教程就先实现左边的。
我们再把左边给拆开分析
![](https://img.haomeiwen.com/i12516875/1d2109f3187ec9c6.png)
绿框中的是显示背包容积的进度条[Progress Bar]
红框中的是两个能够滑动的控件[Scroll Box]
我们可以把红框中显示装备列表给封装起来,封装的目的是可复用性,其使用方法就跟我们使用普通的小控件如滑动条,还可以在游戏中动态的创建控件。
列表中都是由一个个这个封装起来的
![](https://img.haomeiwen.com/i12516875/d7595de8f1ec0546.png)
而item又分为三部分,分别是左边的图片,中间的名字,右边的数量,如果为不可以合并的装备则会隐藏掉。
最小控件Item的制作 [ActionItem]
![](https://img.haomeiwen.com/i12516875/d7595de8f1ec0546.png)
由上图分析出控件的排列为左右结构,我们可以使用[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】
![](https://img.haomeiwen.com/i12516875/ad3945c41a36afe3.png)
![](https://img.haomeiwen.com/i12516875/61392c57bb9a6157.png)
![](https://img.haomeiwen.com/i12516875/2ac183ac4682cefa.png)
列表的创建
由于我们需要在列表中覆写OnDrop事件,但是[附近的]与[背包中的]它们的OnDrop处理事件是不同的,所以我要分开来写。
InventoryList
![](https://img.haomeiwen.com/i12516875/c99fed7dac772036.png)
![](https://img.haomeiwen.com/i12516875/03c56734c47a4be2.png)
蓝图方面创建一个更新列表的函数,也只需要这一个函数,因为列表的管理不是由Widget进行管理的,Widget仅仅是起到一个通知(给玩家)的作用:
![](https://img.haomeiwen.com/i12516875/6b88cb6a11e1ebb7.png)
InventoryList与NearbyList都是有如上部分的,唯一的不同就是OnDrop的处理,在InventoryList是添加进库存,而在NearbyList中是移除:
我们先在MyCharacter中添加如下两个函数:
![](https://img.haomeiwen.com/i12516875/473803bd42c28060.png)
回到InventoryList,覆写OnDrap:
![](https://img.haomeiwen.com/i12516875/02a3bb488c28e15b.png)
之后复制一份InventoryList重命名为【NearbyList】,修改OnDrap:
![](https://img.haomeiwen.com/i12516875/8da632155221108c.png)
MainInventoryWidget的制作:
![](https://img.haomeiwen.com/i12516875/21d7b5af98a13350.png)
![](https://img.haomeiwen.com/i12516875/2de3c09af1650d41.png)
![](https://img.haomeiwen.com/i12516875/e4c01d9ddd06f38c.png)
在MyCharacter中显示背包
![](https://img.haomeiwen.com/i12516875/77ca371ec9e43cd1.png)
![](https://img.haomeiwen.com/i12516875/62dd4c629f983bed.png)
![](https://img.haomeiwen.com/i12516875/dc3b245b268bc9f3.png)
并在MyPlayerState中使用通知接口:
![](https://img.haomeiwen.com/i12516875/7c521eaeb5ebf5c3.png)
![](https://img.haomeiwen.com/i12516875/002d2a3548da6b55.png)
![](https://img.haomeiwen.com/i12516875/38dc86a04da0f315.png)
使用示例
创建一个Actor,重命名为PickupActor,启用复制和复制移动属性,并添加一个StaticMesh (把mesh随便设置一个,我设置的是cube),
![](https://img.haomeiwen.com/i12516875/9faaeaffd546a6b9.png)
打开类设置并实现接口PickupInterface
![](https://img.haomeiwen.com/i12516875/d0b3361d030a55ff.png)
创建一个自定义事件,并设置复制为多路传送,启用可靠函数:
![](https://img.haomeiwen.com/i12516875/27ed6ec2c6d6a68a.png)
实现接口的函数:
![](https://img.haomeiwen.com/i12516875/1e7cc6dc9fc261c0.png)
![](https://img.haomeiwen.com/i12516875/4770d603bc8cc430.png)
![](https://img.haomeiwen.com/i12516875/7bd084173fe5d1b2.png)
![](https://img.haomeiwen.com/i12516875/162397d272924c98.png)
接下来你就可以拖进场景使用了,
还有很多细节未修复,比如释放actor值的位置,应该是放在地板上。等等
也有很多的功能尚未实现(比如网络延迟情况下的处理,类似于子弹多个数据的打包),我会在接下来的教程一一完善
网友评论