先抛开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值的位置,应该是放在地板上。等等
也有很多的功能尚未实现(比如网络延迟情况下的处理,类似于子弹多个数据的打包),我会在接下来的教程一一完善
网友评论