mini: false, //迷你模式 autoplay: false, //自动播放 theme: '#FADFA3', //主题色 loop: 'all', //音频循环播放, 可选值: 'all'全部循环, 'one'单曲循环, 'none'不循环 order: 'random', //音频循环顺序, 可选值: 'list'列表循环, 'random'随机循环 preload: 'auto', //预加载,可选值: 'none', 'metadata', 'auto' volume: 0.7, //默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 mutex: true, //互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 listFolded: false, //列表默认折叠 listMaxHeight: 90, //列表最大高度 lrcType: 3, //歌词传递方式

New Inventory System Plugin

通过 Item的SphereComponent + LineTrace结合起来 检测物体

原理:先进行SphereOverlap检测所有重叠的Item并存储到OverlappingItems,
然后再进行射线检测,因为射线检测可以穿墙,所以射线检测只检测OverlappingItems里面的物品,
如果检测到则将CurrentItem设置为检测到的值,否则设置为OverlappingItems[0]的值

创建InteractComponent,放置在PlayerController上:
屏幕截图 2025-11-12 104633
创建USceneComponent,放置在Item上,USceneComponent可以设置SphereComponent:
屏幕截图 2025-11-15 102838
创建HUD,用于设置中心圆点和PickupMessage:
屏幕截图 2025-11-12 223335
在ProjectSetting中创建ItemTraceChannel和Item的Preset,用于射线检测:
屏幕截图 2025-11-12 224921
屏幕截图 2025-11-12 224908
创建Component:
屏幕截图 2025-11-15 105218
配置InteractComponent:
屏幕截图 2025-11-15 105550
将BPC_Inv_ItemComponent添加到Item中:
屏幕截图 2025-11-15 105157
将Item的StaticMesh的CollisionPreset设置为Item:
屏幕截图 2025-11-15 105618
将BPC_Inv_InteractComponent添加到PlayerController中:
{A49777BD-4335-4C3F-A1A5-11388ECC0B66}
添加PostProcessVolume并设置Material从而达到高亮效果:
屏幕截图 2025-11-15 111655
Inv_InteractComponent.h:
屏幕截图 2025-11-15 101227
Inv_InteractComponent.cpp:
屏幕截图 2025-11-15 101256
屏幕截图 2025-11-15 101309
屏幕截图 2025-11-15 101434
屏幕截图 2025-11-15 101442
Inv_ItemComponent.h:
屏幕截图 2025-11-15 101455
Inv_ItemComponent.cpp:
屏幕截图 2025-11-15 101524
Inv_HUD.h:
屏幕截图 2025-11-15 101535
Inv_HUD.cpp:
屏幕截图 2025-11-15 101541

创建SpatialInventory,InventoryGrid,GridSlot三个Widget并通过创建InventoryComponent实现开关库存操作

创建BaseInventory用作父类:
屏幕截图 2025-11-15 170010
创建子类SpatialInventory并继承BaseInventory:
屏幕截图 2025-11-15 170201
创建UUSerWidget类的InventoryGrid:
屏幕截图 2025-11-15 173951
创建UUSerWidget类的GridSlot:
屏幕截图 2025-11-15 174411
创建InventoryComponent用于切换库存:
屏幕截图 2025-11-15 170324

InventoryComponent.h:
初始化SpatialInventory并设置ToggleInventory函数用于切换库存
屏幕截图 2025-11-15 221218
InventoryComponent.cpp:
屏幕截图 2025-11-15 221239
屏幕截图 2025-11-30 210413
InventoryGrid.h:
在InventoryGrid中创建具体行数和列数的GridSlot:
屏幕截图 2025-11-15 221305
InventoryGrid.cpp:
屏幕截图 2025-11-15 221326
GridSlot.h:
在GridSlot中存储当前的Index:
屏幕截图 2025-11-15 221337
InteractComponent.cpp:
在InteractComponent中创建ToggleInventory动作并存储InventoryComponent然后调用InventoryComponent中的ToggleInventory:
屏幕截图 2025-11-15 221404
创建三个Widget:
屏幕截图 2025-11-15 213035
设置SpatialInventory:
屏幕截图 2025-11-15 213054
设置InventoryGrid:
屏幕截图 2025-11-15 213105
设置GridSlot:
屏幕截图 2025-11-15 213138
设置InventoryComponent:
屏幕截图 2025-11-15 213214
将InventoryComponent添加到PlayerController上:
屏幕截图 2025-11-15 213232

创建UObject的抽象类用于存储数据

屏幕截图 2025-11-18 164536

创建Fast Array Serialize

屏幕截图 2025-11-18 164923
根据FastArraySerializer的步骤来建立FastArray:
{99611DE7-8862-428F-95BC-43CCD5794BA1}
将InventoryItem作为存储数据放在Entry的结构体中
在FastArray结构体中声明Entries用于存储所有Entry,
添加AddEntry和RemoveEntry的函数
添加自带的PostReplicateAdd和PreReplicatedRemove函数,用于在复制新添加/新删除的元素前调用:

{187C3683-FE3B-493E-AB0A-60CFB6CBF127}
在PostReplicateAdd和PreReplicatedRemove函数中调用InventoryComponent的委托:
{8162BC8B-122C-4FFD-A982-933A720C233B}
在InventoryComponent中创建InventoryItemChange和NoRoomInInventory的委托,并添加TryAddItem的函数:
{7D8D6D79-C3C7-46FC-B02B-902EC1655329}
创建TryAddItem函数并调用OnNoRoomInInventory的委托:
{C6F577CB-35C1-4CF9-8E03-4518E47DB672}
在InteractComponent中调用TryAddItem函数:
{67A87A59-EF4F-4089-9348-E6D4F00AB2F0}
创建InfoMessage用于显示NoRoom的Message:
{9FD85204-C36B-4EFD-961C-FBE36F97308D}
{BFFE5B90-08F7-4517-9AFD-3C8AEBC1C6CA}
创建FadeAnimation:
屏幕截图 2025-11-18 210726
在蓝图中实现ShowInfoMessage和HideInfoMessage的函数:
屏幕截图 2025-11-18 210902
将InfoMessage添加到HUD中:
屏幕截图 2025-11-18 210937
在HUD中初始化委托并设置InfoMessage:
屏幕截图 2025-11-19 143832
屏幕截图 2025-11-19 143839

创建SlotAvailability和GridAvailabilityResult来判断库存是否有空间

GridAvailabilityResult用来判断整个库存还能放下多少个该物品(TotalRoomToFill)、是否可堆叠、还有多少放不下(Remainder)并列出具体要放置的槽位SlotAvailabilities
SlotAvailability计算不同的格子要放多少个该物品,指出目标索引、是否已有物品、还能填多少(AmountToFill)
FInv_SlotAvailability 加起来的放置数量就等于GridAvailabilityResult的总的AmountToFill数量

{BCF7475A-D8A4-4A9B-8B0E-8D53F21DC72C}
在BaseInventory中创建判断库存中是否有空间:
屏幕截图 2025-11-19 172835
在SpatialInventory中继承父类函数:
屏幕截图 2025-11-19 172841

创建ItemManifest描述Item的属性

拾取物 (UInv_ItemComponent) 在蓝图中设置 FInv_ItemManifest
当要把物品放进玩家 UInv_InventoryComponent 时,会通过 FInv_FastArray::AddEntry 新建 UInv_InventoryItem,复制 Manifest 数据 并 注册成可复制子对象

在ItemComponent中创建ItemManifest并在蓝图中设置:
{79AC8419-C8A8-4965-A2FA-F707FA344AEB}
在InventoryItem中创建用来保存 FInv_ItemManifest 的实例,并添加设置该实例的函数,以及获取ItemManifest的函数:
{A833DDB9-909E-43E7-9C0E-63CFD3C7B591}
在ItemManifest中创建CreateInventoryItem的函数,创建InventoryItem 并 把当前的ItemManifest数据复制进新对象:
{DD2A49B6-989A-41DE-9CE5-FF55222EE626}
在InventoryComponent中创建FastArray并添加AddRepSubObject函数和Server函数:
屏幕截图 2025-11-19 211635
将子对象加入复制队列,确保客户端能收到该子对象
屏幕截图 2025-11-19 211706
完善FastArray中的AddEntry(UInv_ItemComponent ItemComponent)函数,通过ItemComponent中的Manifest中的CreateInventoryItem函数来新建 UInv_InventoryItem,并在该函数中复制 Manifest 数据,并注册成可复制子对象:*
屏幕截图 2025-11-19 211822

创建FGameplayTag类型的ItemType

屏幕截图 2025-11-20 132945
屏幕截图 2025-11-20 142508
屏幕截图 2025-11-20 142517
在ItemManifest中创建FGameplayTag类型的变量并限制Categories只能为Items:
屏幕截图 2025-11-20 142547
在ItemComponent中的Manifest中设置ItemType:
屏幕截图 2025-11-20 140911

创建AddItem函数绑定委托,并让其在客户端和服务器都能被调用

由于FastArray的PostReplicatedAdd和PreReplicatedRemove只会在客户端调用并调用OnInventoryItemAdded委托的Broadcast,所以需要在服务器上单独Broadcast:
屏幕截图 2025-11-20 160354
在AddEntry之后,只在服务器单独调用Broadcast:
屏幕截图 2025-11-20 160443
在InventoryComponent开头初始化InventoryList的OwnerComponent为InventoryComponent:
屏幕截图 2025-11-20 160601
在InventoryGrid中创建用于绑定的委托函数AddItem:
屏幕截图 2025-11-20 160529
屏幕截图 2025-11-20 163318

创建ItemFragment用于设置加入网格的物品的属性

添加BaseClass和ChildClass,由于Struct存在继承,所以在BaseClass中设置析构函数
创建FragmentTag用于确定当前的Fragment类型
GridFragment用于设置物品添加到网格的大小是1x1还是2x3
ImageFramgent用于设置物品添加到网格的图标:

屏幕截图 2025-11-22 213127
屏幕截图 2025-11-22 213136
屏幕截图 2025-11-22 213148
在Manifest中创建ItemFragments的实例化数组并排除父类选项:
屏幕截图 2025-11-22 213223
在Manifest中添加Fragments:
屏幕截图 2025-11-22 213635

设置HasRoomForItem函数

在Grid中创建执行具体逻辑的HasRoomForItem函数,然后在SpatialInventory中创建具体的Grid并调用该Grid的HasRoomForItem函数:
创建3个重载函数,其中以Manifest为参数的函数作为执行具体逻辑的函数,其他两个函数直接调用Manifest函数:
屏幕截图 2025-11-22 225429
在AddItem中调用HasRoomForItem函数来获取Result从而获取物品应该放在网格位置的具体信息:
屏幕截图 2025-11-22 225450
在SpatialInventory中创建具体的Grid:
屏幕截图 2025-11-22 225456
HasRoomForItem函数调用具体Grid的HasRoomForItem函数:
屏幕截图 2025-11-22 225501

Add SlottedItem To Canvas

在Manifest中创建模板函数,用于通过Tag来获取具体的Fragment(例如GridFragment,ImageFragment):
屏幕截图 2025-11-23 170527
创建SlottedItem Widget,用于将物品图标添加到Canvas:
屏幕截图 2025-11-23 120743
屏幕截图 2025-11-23 170714
屏幕截图 2025-11-23 170721
在InventoryGrid中创建SlottedItemClass和用于存储的SlottedItems:
屏幕截图 2025-11-23 170545
在AddItem函数中调用AddItemToIndices,将物品添加到需要添加的每个索引(堆叠物品分散到不同槽位,则会有多个Availability)
如果是多格物品,只会在左上角索引创建一个SlottedItem
在AddItemAtIndex函数中通过Manifest获取GridFragment和ImageFragment
通过Fragment来设置SlottedItem的位置和图标
调用AddSlottedItemToCanvas将SlottedItem添加到Canvas:

屏幕截图 2025-11-23 170652
在InventoryGrid中的HasRoomForItem函数中暂时创建Index为0的SlotAvailability用于测试:
屏幕截图 2025-11-23 170707
在蓝图中创建SlottedItem类的Widget:
屏幕截图 2025-11-23 173114
在InventoryGrid中设置SlotteItem类:
屏幕截图 2025-11-23 173123
效果:
屏幕截图 2025-11-23 173139

添加GridSlot占用Texture

在GridSlot中创建背景图片,并创建GridSlotState的枚举类:
屏幕截图 2025-11-23 223806
对于不同的State,设置不同的背景Brush:
屏幕截图 2025-11-23 223816
在AddItemToIndices中创建UpdateGridSlotsState函数用于更新Slot的状态
若为多格物品,则设置每个格子索引的State为占用:

屏幕截图 2025-11-26 130449
效果:
屏幕截图 2025-11-23 223848

创建StackCount

创建StackableFragment,用于设置物品的 单格最大堆叠数 和 捡起一个物品的堆叠数:
屏幕截图 2025-11-24 185932
创建用于StackableFragment的Tags:
屏幕截图 2025-11-24 185938
屏幕截图 2025-11-24 185942
在SlottedItem中创建Text用于显示堆叠数:
屏幕截图 2025-11-24 185949
创建更新堆叠数的函数:
屏幕截图 2025-11-24 185953
在创建SlottedItem的函数中调用UpdateStackCount函数:
屏幕截图 2025-11-24 190031
在HasRoomForItem函数中暂时硬编码创建GridAvailabilityResult:
屏幕截图 2025-11-24 190044
在蓝图中创建Stackable Fragment:
屏幕截图 2025-11-24 190701
在蓝图中添加Text_StackCount:
屏幕截图 2025-11-24 190630
效果:
{E271C4C5-DB5C-4174-870B-D16524DB3AFD}

Update GridSlot

由于一个物品可能会占用多个网格,
需要将被占用的网格标记为不可用
并且左上角格子记录堆叠数:

在GridSlot中添加StackCount、UpperLeftIndex、bAvailable:
屏幕截图 2025-11-25 195921
在UpdateGridSlotsState中设置对应的Slot:
屏幕截图 2025-11-25 195936

完善HasRoomForItem函数

完善HasRoomForItem的检查:
{F29F9504-EF84-46E9-A663-308ACF0C8BCA}
在HasRoomForItem中先判断是否存在可堆叠的同类物品,如果有,直接填充:
屏幕截图 2025-12-03 154816
Result中的InventoryItem是用于判断当前库存中是否存在相同类型的物品才会设置这个变量:
屏幕截图 2025-11-27 120648
在FastArray中添加查找第一个类型匹配的物品的函数:
屏幕截图 2025-11-27 120728
通过FindByPredicate查找:
屏幕截图 2025-11-27 121349
在TryAddItem函数中,如果在FastArray中找到相同类型的物品,则设置Result中的InventoryItem,并执行Server_AddStacksToItem,否则执行Server_AddNewItem:
屏幕截图 2025-11-27 121501

完善AddStackToItem函数

在InventoryItem中创建TotalStackCount用于记录库存中当前Item的堆叠总数:
屏幕截图 2025-11-27 212800
屏幕截图 2025-11-27 212833
在ItemComponent中创建DestroyItem函数用于销毁Item:
屏幕截图 2025-11-27 212900
在InventoryComponent中创建委托,用于当StackChange时,改变库存Widget:
屏幕截图 2025-11-27 212933
在添加StacksToItem之前调用委托:
屏幕截图 2025-11-27 213022
更新TotalStackCount,如果有Remainder,则更新剩余物品的StackableFragment,否则销毁Item:
屏幕截图 2025-11-27 213036
绑定委托,遍历SlotAvailabilities,如果当前格子有物品,则直接更新SlottedItem的StackCount,否则添加新的SlottedItem:
屏幕截图 2025-11-27 213105
将物品的Replicates设置为True:
屏幕截图 2025-11-27 180525

设置拖拽、合并

在GridSlot中添加鼠标进入和离开事件,用于鼠标移动到对应格子时,格子会高亮:
屏幕截图 2025-12-02 113601
屏幕截图 2025-12-02 113620
在SlottedItem中添加鼠标按下,进入和离开事件,用于拖拽SlottedItem,创建委托并在InventoryGrid中设置委托:
屏幕截图 2025-12-02 115301
鼠标按下时调用检测拖拽,在拖拽时创建用于视觉效果的SlottedItem:
屏幕截图 2025-12-02 121023
InventoryGrid中创建用于委托的函数:
屏幕截图 2025-12-02 223123
拖拽委托被触发时,将bIsDragging设置为true,用于在Tick中实现拖拽:
取消拖拽委托被触发时,将判断是否可以放置或交换:
屏幕截图 2025-12-03 154359
交换物品:
屏幕截图 2025-12-03 154423
移除Inventory中的SlottedItem:
屏幕截图 2025-12-03 154430
在Tick中执行拖拽逻辑,先通过鼠标所在象限和物品尺寸计算物品左上角起始坐标,然后判断是否可以放置或交换:
屏幕截图 2025-12-03 154502
屏幕截图 2025-12-03 154515
判断是否可以放置或交换:
屏幕截图 2025-12-03 154639
屏幕截图 2025-12-03 154659
通过鼠标所在象限和物品尺寸计算物品左上角起始坐标:
屏幕截图 2025-12-03 154729
计算鼠标在哪个格子并且计算在当前格子的左半边和上半边:
屏幕截图 2025-12-03 154743

创建PopUpMenu和SplitMenu

创建PopUpMenu的Widget:
屏幕截图 2025-12-12 174237
绑定Consume和Drop的函数:
屏幕截图 2025-12-12 174249
创建Split的Widget:
屏幕截图 2025-12-12 174307
绑定Split和Cancel的函数:
屏幕截图 2025-12-12 174317
再SlottedItem中创建RightButtonDown的函数,用于判断是否在SlottedItem上按下右键:
屏幕截图 2025-12-12 174334
屏幕截图 2025-12-12 174401
在InventoryComponent中创建DropItem和ConsumeItem的服务器函数,并创建SpawnDroppedItem函数:
屏幕截图 2025-12-12 174428
在服务器更新Consume和Drop后的库存变化:
屏幕截图 2025-12-12 174450
在Manifest中声明PickupActorClass用于Drop到世界:
屏幕截图 2025-12-12 174513
在ItemFragment中创建Consume的Fragment:
屏幕截图 2025-12-12 174533
屏幕截图 2025-12-12 174552
创建ConsumableFragment的Tag:
屏幕截图 2025-12-12 174557
屏幕截图 2025-12-12 174603
在SpatialInventory中创建CanvasPanel,创建关闭PopUpMenu和SplitMenu的函数:
屏幕截图 2025-12-12 174624
屏幕截图 2025-12-12 174638
在Grid中获取Consumable的Tag用于判断物品是否可以Consume,创建PopUpMenu和SplitMenu:
屏幕截图 2025-12-12 174723
屏幕截图 2025-12-12 174820
绑定SlottedItem的RightButtonDown,创建PopUpMenu并判断是否是Consumable
屏幕截图 2025-12-12 174912
按键按下时,调用Server函数,并在本地更新网格占用:
屏幕截图 2025-12-12 174942
放置物品时,先判断是否可以Split:
屏幕截图 2025-12-12 175142
如果Shift按下,则可以Split:
屏幕截图 2025-12-13 171134
Split和Cancel的按钮按下:
屏幕截图 2025-12-13 155917
将ItemComponent设置为可复制的:
屏幕截图 2025-12-12 175220
创建PopUpMenu:
屏幕截图 2025-12-12 180450
创建SplitMenu:
屏幕截图 2025-12-12 180456
设置Grid:
屏幕截图 2025-12-12 180530
为可以Consume的物品添加具体的Consumable Fragment ———— Heal Consumable Fragment:
屏幕截图 2025-12-12 180608
设置ItemComponent为可复制的:
屏幕截图 2025-12-12 180639

添加ItemDescription

创建ItemDescription Wiget类:
屏幕截图 2025-12-13 212750
屏幕截图 2025-12-14 104556
在SlottedItem中创建鼠标进入和离开事件:
屏幕截图 2025-12-14 104613
在鼠标事件中调用BaseInventory的函数:
屏幕截图 2025-12-14 104705
在BaseInventory中创建虚函数:
屏幕截图 2025-12-14 104719
在SpatialInvventory中实现虚函数:
屏幕截图 2025-12-14 104846
在SpatialInventory中的Canvas中创建ItemDescription,并根据鼠标位置和Canvas的大小来设置Widget的位置,确保Widget不会超过边界:
屏幕截图 2025-12-14 110351
当Hover时,延迟出现,当UnHover时,隐藏:
屏幕截图 2025-12-14 110357

完善ItemDescription

复合模式:
1.CompositeBase(复合基类)
·定义所有组件的公共接口
·声明 DoWork() 等操作
2.Composite(复合类)
·包含子复合类Composite 或 叶子节点Leaf(Children)
·DoWork() 遍历子组件并调用它们的 DoWork()
3.Leaf(叶子节点)
·实现基础操作,不包含子组件
·DoWork() 执行实际工作
屏幕截图 2025-12-14 112701



创建所有的复合Widget的类:
屏幕截图 2025-12-19 101501
屏幕截图 2025-12-19 101531
屏幕截图 2025-12-19 101555
在CompositeBase中创建关闭和显示Widget的函数,并创建ApplyFunction函数:
屏幕截图 2025-12-20 134209
屏幕截图 2025-12-20 134213
在Composite中创建Children数组,并继承Base中所有的函数:
屏幕截图 2025-12-20 134225
通过WidgetTree来设置Children,ApplyFunction和Collapse让所有的Children调用对应的函数:
屏幕截图 2025-12-20 134230
在Leaf中创建对应的FragmentTag,以及ApplyFunction:
屏幕截图 2025-12-20 134236
真正调用Function的位置:
屏幕截图 2025-12-20 134241
将ItemDescription改为继承自Composite:
屏幕截图 2025-12-20 134253

posted @ 2025-11-15 10:25  pone1  阅读(4)  评论(0)    收藏  举报