Inventory System Plugin
新输入增强系统
在cs文件中添加Module:

添加IMX和Action以及对应的回调函数:

先在BeginPlay中将输入添加到子系统中:

创建输入:



将Action添加到IMC中并选择按键:

在PlayerController中进行赋值:

LineTrace for Pickups
创建自定义Trace Channel,并初始化为Ignore All:

创建自定义Collision Preset给PickupItem,并将ItemTrace设置为Block:

添加Trace函数:

根据屏幕中心点获取世界位置,然后进行Line Trace,并判断上一个物品是否和当前物品相同:


将Item的Collision Presets设置为Item:

将Item Trace Channel设置为ItemTrace:

添加PickUpMessage
在HUDWidget中创建Show和Hide Message的方法,并在蓝图中实现:


在Trace中调用对应函数:

创建ActorComponent类作为Item的Component,并初始化Item的属性:

创建一个以UserWidget为父类的PickupMessageWidget:

将PickupMessage拖到HUD中:


在ItemComponent中添加Blueprintable,以便创建蓝图类:


在Item中添加刚刚创建的BP类ItemComponent:

效果:

添加高光效果
创建高光材质:

配置材质:

创建StaticMeshComponent用于设置高光:


创建Interface用于在其他地方也可以使用高光效果:


在Interface中创建 使用高光 和 关闭高光 的函数:

在MeshComponent中实现该函数:


在Trace中获取 实现了指定接口的组件,即MeshComponent,并调用接口中的Highlight方法:

创建MeshComponent的蓝图类


设置MeshComponent:

在Item中添加MeshComponent:

添加库存系统
添加InventoryComponent类:

添加一个InventoryWidget的基类:

创建子类SpatialInventoryWidget:


在Component中添加 初始化库存 和 打开关闭库存 函数:


在PlayerController中添加InputAction:

从蓝图中查找InventoryComponent并初始化,绑定Input Action:

创建蓝图类的SpatialInventoryWidget:



在蓝图中创建InventoryComponent:


将MenuClass设置为WBP_SpatialInventoryWidget:

在PlayerController中添加InventoryComponent:

绑定Input Action:


在PlayerController中配置对应Action:

添加不同类型的Grid以及Switcher Button
添加GridType.h:

添加Grid类:

初始化对应Gird的Category:

创建3个不同类型的Grid、Button以及Switcher,点击对应的Button时,禁用该Button并切换Grid:

创建Grid蓝图类:

暂时添加一个Text用于测试:

不同的Category对应不同的数字:

在InventoryWidget中创建3个Button,1个Switcher包含3个Grid,并设置3个Grid的Item Category:

效果:



添加Grid Slot
添加GridSlot Widget类:

添加Slot的Index以及 设置 和 获取Index函数:

添加Utils工具函数类,专门存放工具函数:

存放计算当前格子的索引值的工具函数:

在Grid中添加Grid Slot并添加Slot的行数、列数、大小,绑定CanvasPanel用于在上面添加Slot:

修改:
上面的行数和列数写反了:

上面的i和j写反了:

创建Slot蓝图类:


删除Inventory中的SwicherBackGround:


在Grid中添加BackGround并添加Canvas用于存储Slot:

在Grid中配置Slot对应的参数:

配置Slot:

还需要在Inventory中分别对3个Grid配置Grid Class:

效果:

Add Fast Array
创建FastArray文件:


创建InventoryItem:

添加NetCore Model:

设置FastArray:



添加委托:


Add No Room in Inventory
声明一个No Room的委托以及一个TryAddItem的函数,并在里面进行NoRoom Broadcast用于测试::

添加消息Widget类:

添加Text,并在蓝图中添加Show和Hide Message函数定义,通过SetMessage函数让Text在LifeTime后消失:

在HUD中创建并绑定InfoMessage,创建回调函数OnNoRoom并绑定委托:

在PlayerController中F键按下后,TryAddItem:

在蓝图中创建WBP_InfoMessage Widget:

为Text创建Fade Animation:

设置Show和Hide Message函数:

在HUD中添加WBP_InfoMessage:

效果:

Check Room for Item:
创建两个结构体用于存储数据:

在父类BaseInventory中声明是否有Room的函数,并返回空的SlotAvailabilityResult:

在子类SpatialIventory中定义该函数:

在TryAddItem中使用该函数判断是否有空间:

Item Manifest
创建ItemManifest类,用于存储Item的所有信息:


添加StructUtils Model:






在ItemComponent中设置Manifest中的Category:

Item Type Tags
添加Tag类:

添加GamePlayTags Model:

在.h中声明,在.cpp中定义Tag:

在Manifest中添加ItemType:

在ItemComponent中设置具体的Item Type:

On Item Added
添加获取ItemManifest的函数:

添加AddItem回调函数,若MatchesCategory则AddItem:

如果是服务器,则直接Broadcast:

设置FastArray的Component:

Item Fragment
创建ItemFragment类:


创建FragmentTags:


创建父类结构体Fragment,子类结构体GridFragment继承父类结构体:

在Manifest中创建Fragments变量:

定义Fragment Tags:

在蓝图中设置Fragments:

添加子结构体ImageFragment:



Has Room For Item
在Grid中添加HasRoomForItem函数并添加重载函数:

在SpatialInventory的HasRoomForItem函数中使用switch分别调用对应Grid的HasRoomForItem函数:

Add Item to Indices



Create Widget to add to the grid
创建Widget类:

绑定Image Icon:

添加Widget到AddItem中:

Add Slotted Items to Canvas
创建工具函数,通过Index获取Position:

将Slotted Items添加到Canvas中并设置大小和位置:

创建SlottedItem Widget蓝图类:


添加Image_Icon:

在Grid中设置Slotted Item Class:

在测试之前,需要先删除原先的Item,因为细节面板不会刷新,修改细节面板需要在对应物品的Instance中修改
效果:

Grid Slot Texture
在Slot中添加GridSlotState,并设置不同的Brush对应不同的State:

创建遍历二维网格的模板函数:

为每个Slot设置Texture:

在Slot中配置FSlateBrush:

效果:

Add Stack Count
创建一个新的子结构Stackable Fragment用于设置 物品的最大存储容量 和 物品的数量:

添加Tag:

在SlottedItem中添加Text用于显示StackCount:

用于测试的数据:

在创建SlottedItem时UpdateStackCount:

在蓝图中设置:

添加Text:

效果:

Update Grid Slot


Add Item in the inventory
获取FragmentOfType:

判断是否可以堆叠:





查找第一个与指定类型匹配的物品:


添加当前物品的堆叠总数


Pick up 后 Destroy
添加可以Mutable函数,即非const函数:

添加设置StackCount函数:

PickedUp函数:


在蓝图中将Item的Replicates打开,确保在客户端可以使用:

Add Stacks Count
添加委托,并在添加可堆叠物品时调用:


更新物品和槽位的堆叠数量:

效果:

创建Hover Item
创建Widget类:


创建Widget蓝图类:


配置Hover Item:

创建InputCore Model:

添加点击事件委托:


绑定委托:




效果:

添加Tile Parameters
添加枚举类型,用于判断鼠标处于哪个象限:

获取Widget的位置:

在Tick中获取画布位置和鼠标位置,并传递给函数用来更新Tile parameters:

Highlight and UnHighlight Hover Item
创建工具函数,用于获取Widget Size和判断鼠标是否处于Canvas内:

创建结构体,用于判断Hover时处于的格子是否有物品:









将GridSlot中bAvailable默认设置为true:

将CanvasPanel用Overlay包裹,不然无法计算:

效果:


Swap Item
添加StackCount = Count用于记录StackCount:

添加委托事件,用于处理鼠标进入,离开,点击GridSlot事件:












为3类Grid创建不同的鼠标指针:


为3类Grid分别配置Visible和Hidden Cursor Widget Class:

ItemPopUpMenu
创建ItemPopUp类:

创建3种委托:




判断物品是否为Consumable:

创建设置CanvasPanel的函数:

委托的回调函数:

绑定ItemPopUp:

点击时隐藏ItemPopUpMenu:


根据不同Item类型创建不同的ItemPopUpMenu:

设置CanvasPanel:

隐藏PopUpMenu:


创建ItemPopUp蓝图类:


添加SizeBox,Button,Split:

配置Item Pop Up Class:

Split,Drop,Consume Item
创建丢弃区域类:

创建委托,当在丢弃区域鼠标按下时触发:

创建丢弃函数:

设置ItemPopUp的GridIndex:


设置ItemManifest:

在ItemManifest中创建当前物品的Class,并添加生成Actor的函数:

在Spatial中创建丢弃区域类,并绑定委托,执行丢弃物品函数:

在Fragment中创建Consumable Fragment,并创建2个Consumable Fragment的子类:

创建Consumable的Tag:

将Component Replicates 设置为True:

添加Health Fragment 和 Pickup Actor Class:

Item Description
创建ItemDescription Widget类:

设置SizeBox:

在BaseWidget中创建父函数:

判断是否存在HoverItem:

从InventoryComponent中获取InventoryBaseWidget:

创建工具函数,调用OnItemHovered和OnItemUnHovered函数 并 创建获取控件位置的函数:

在SlottedItem中创建鼠标进入和离开函数,分别调用对应的工具函数:

在BaseWidget的子类SpatialWidget中添加继承父类的函数 并 添加描述界面的Class:

延迟一段时间后显示描述界面:


当物品被点击并处于Hover状态时,隐藏描述界面:

创建Item Description蓝图类:



设置Item Description Class:

Composite Pattern
创建UInv_CompositeBase基类,定义了组合模式中的通用接口和方法:

创建UInv_Composite组合类,继承自 UInv_CompositeBase:

创建UInv_Leaf叶子节点类,继承自 UInv_CompositeBase:

获取和设置标签,Collapse和Expand功能,应用函数(ApplyFunction)用于递归操作子节点

初始化时收集子节点,递归调用子节点的 ApplyFunction 和 Collapse

直接执行传入的函数(ApplyFunction)

将ItemDescription的父类改为Composite:

Assimilate Inventory Fragments
玩家悬停一个物品时,系统获取该物品的 Manifest(包含所有片段),通过 AssimilateInventoryFragments将片段同化到描述控件(DescriptionWidget)




Image Fragment
创建Image的叶子节点并继承自叶子类:

创建Image Icon并配置大小:

将ImageFragment的父类改为InventoryItemFragment并重写父类的同化函数:

创建Leaf_Image蓝图类:


在Description Widget中添加Leaf Icon Widget 并 配置Fragment Tag:

效果:

Text Fragment
创建Leaf_Text类:

创建Text:

创建Text Fragment,用于在Manifest中修改对应物品的属性:

创建FragmentTag,用于确保LeafText和Item中的TextFragment属性一致:

创建蓝图类:



设置Leaf_ItemName的FragmentTag:

设置ItemManifest的Text和FragmentTag:

效果:

Labeled Number Fragment
创建LabeledValue类:

设置Text和Value:

在父类中添加Manifest继承函数:

添加LabeledNumberFragment并重写父类的Manifest函数,用于在开始时随机初始化Value:

在Manifest中调用每个Fragment的Manifest函数:

创建PrimaryStatFragment:

创建蓝图类:


设置Tag:

添加到Description Widget中:

添加Item的Fragment并设置Tag:

效果:

添加Consume Modifiers并确保随机值Value与使用时相同
更改Consumable的父类为InventoryItemFragment,添加Consumable的子类ConsumeModifiers但子类继承自LabelNumberFragment,修改Health和Eat的父类为ConsumeModifiers:

添加3种属性标签:

添加一个新的LabeledValue Widget:



在Description中添加3个StaticModifier并配置对应的Tag:



在Item中删除原先的Health Fragment和Labeled Number Fragment 并 添加Consumable Fragment,添加两个Consume Modifiers:

效果:

Add more widget
添加更多的Fragment Tag:

添加更多的Widget:

添加到Description Widget中:

在Item中配置对应Fragment:

Add Equipped Grid Slots
创建以GridSlot为父类的EquippedGridSlot类:

在Grid中添加获取HoverItem的函数:

在BaseInventory中添加获取HoverItem的虚函数:

在Spatial中实现父类添加获取HoverItem的虚函数 并 创建数组以及点击的回调函数:

遍历所有Widget来获取EquippedGridSlot并绑定委托:

创建工具函数获取HoverItem:

在EquippedGridSlot中通过HoverItem是否与EquipmentTypeTag一致来判断进入或离开:

创建多个蓝图类:


设置每个的Equipment Type Tag:

添加到Spatial Widget中:

效果:

Equip the Cloak
创建EquippedSlottedItem Widget类并继承自SlottedItem类:

在GridSlot中创建函数用于Create EquippedSlottedItem Widget:

创建Equipped Fragment,与Consume Fragment类似:

设置EquippedSlottedItem并添加点击事件:

创建工具函数用于获取InventoryWidget:

在InventoryComponent中创建委托并创建EquipSlotClicked的多播函数:

在Spatial Widget中设置EquippedGridSlotClicked的绑定函数,并调用InventoryComponent的多播函数:

创建EquippedSlottedItem Widget的蓝图类:


为3个EquippedGridSlot都设置Equipped Slotted Item Class:

效果:

Equip and UnEquip Cloak
处理EquippedSlot的点击事件:



装备/卸下事件:

Bug:切换Gird或关闭库存会导致HoverItem丢失
在Component中创建委托,用于判断Inventory的开关:

创建将HoverItem放回去的函数,并为HasRoomForItem添加强制堆叠数量,从而确保HoverItem放回时的数量正确:

绑定函数,若库存关闭,则调用PutHoverItemBack,若没有Room则DropItem:

配置强制指定的数量:

若切换Grid,则调用PutHoverItemBack:

Bug:格子有物品却可以放下并重叠
添加判断,格子是否为空:

Bug:交换物品时,物品位置不对 并且 添加若被点击物品数量为最大值,则交换物品而不是只交换StackCount:

Bug:拾取物品时,若还有剩余,物品剩余数量却没有减少 并且 捡起新物品时,也应该判断是否会有剩余


Equip Component
创建Equip Component类:

通过InventoryComponent绑定委托,并在回调函数中调用EquipmentFragment的Equip函数:

创建EquipmentFragment Tag:

在EquipmentFragment中创建Manifest函数:

将清除HoverItem的函数移动到最后使用:

创建EquipComponent蓝图类:


添加到PlayerController中:

在Cloak中添加Equipment Fragment:

将Cloak改为Replicates:

效果:

Spawn Equip Actor
创建EquipActor类用于Spawn:

在EquipActor中添加EquipmentType:

在EquipmentFragment中添加要Spawn的EquipActorClass和EquipActor和SocketAttachPoint和EquipmentTag,以及Spawn和Destroy的函数:

在EquipComponent中添加Spawn和Remove的函数:

初始化Inventory Component:



添加EquipActor蓝图类:

cloak的Spawn Item类:

添加SkeletalMesh:

设置Equipment Tag为Red Cloak:

在Equipment Fragment中添加Equip Actor Class:

Proxy Mesh
创建ProxyMeshActor类:

在EquipComponent中为ProxyMesh设置函数:




创建ProxyMeshActor蓝图类:


效果:

Character Display
创建CharacterDisplay Widget类:

获取ProxyMeshActor的Mesh:

通过获取的Mesh创建新的Mesh并判断鼠标拖拽时,角色旋转:

在SpatialWidget中创建CharacterDisplay并在鼠标松开或关闭库存时设置停止拖拽:

取消ProxyMeshActor的复制:

创建蓝图类:


创建Render Target:


配置大小:

创建Material并将Texture改为Render Target:

为Material设置背景透明:

将CharacterDisplay的Image设置为刚刚的材质:

在Spatial Widget中添加CharacterDisplay Widget:

在ProxyMeshActor中添加SpringArm和SceneCaptureComponent2D,并将Texture设置为Render Target,并隐藏除了Skeletal Mesh以外的:

将ProxyMeshActor拖到世界中即可:
只有在打包后才会在多人游戏中正确运行 或者 取消Run Under One Process进行测试:

效果:

Bug:在设置另一个ItemDescription时,没有提前清除上一个的ItemDescription
获取所有的子类:

设置Visibility时,将所有子类先销毁:

调换两个函数位置,先销毁,后同化:

将PlayerController的内容移动到新的Actor Component:Inv_InteractComponent,并将其添加到PlayerController中:
All, with Sensei's permission, I am posting my changes to the plugin. I have moved all the functionality from the PlayerController into a separate component called Inv_InteractComponent. By separating this functionality from the player controller, this makes the plugin attachable to any existing PC with no changes to the PC, unless you have a functional conflict, like the LineTracing, etc. being done previously.
Instructions:
Important: If you have been modifying your own PC for your own project, you will need to remove all the course code from it for this to work! If you are worried about bricking your project because it is currently working for you, then don't do this on that project. Do it on a blank project like what we created for the course at the start. I am not liable for you screwing up your existing project - this is intended to augment Sensei Stephen's course as taught.
- Add the Inv_InteractComponent files to the InventoryManagement/Components public and private folders
- Replace your Inv_PlayerController files from the course with the empty ones I have attached if you want a quick replacement. Otherwise create your own empty Inv_PlayerController class, or remove all of the existing interaction code that we put into it.
- Compile and launch editor
- Make a blueprint of the Inv_InteractComponent class and fill in its fields in the Inventory category
- Attach the component to the player controller blueprint alongside the Inv_InventoryComponent
Important change:
6) Modify the close button blueprint to call Get Component By Class from the PlayerController, and select Inv_InteractComponent. Then call ToggleInventory from that. Pic is attached.

点击查看代码
// Fill out your copyright notice in the Description page of Project Settings.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Inv_InteractComponent.generated.h"
class UInv_InventoryComponent;
class UInv_HUDWidget;
class UInputMappingContext;
class UInputAction;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FShortItemDescription, UInv_ItemComponent*, ItemComponent);
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), Blueprintable)
class INVENTORYSYSTEM_API UInv_InteractComponent : public UActorComponent
{
GENERATED_BODY()
public:
UInv_InteractComponent();
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UFUNCTION(BlueprintCallable, Category = "Inventory")
void ToggleInventory();
FShortItemDescription CreateShortItemDescription;
FShortItemDescription DestroyShortItemDescription;
protected:
virtual void BeginPlay() override;
virtual void SetupInputComponent();
private:
void PrimaryInteract();
void CreateHUDWidget();
void TraceForItem();
TWeakObjectPtr<UInv_InventoryComponent> InventoryComponent;
UPROPERTY(EditDefaultsOnly, Category = "Inventory")
TObjectPtr<UInputMappingContext> DefaultIMC;
UPROPERTY(EditDefaultsOnly, Category = "Inventory")
TObjectPtr<UInputAction> PrimaryInteractAction;
UPROPERTY(EditDefaultsOnly, Category = "Inventory")
TObjectPtr<UInputAction> ToggleInventoryAction;
//assign the class for our HUD Widget in the editor
UPROPERTY(EditDefaultsOnly, Category = "Inventory")
TSubclassOf<UInv_HUDWidget> HUDWidgetClass;
UPROPERTY()
TObjectPtr<UInv_HUDWidget> HUDWidget;
UPROPERTY(EditDefaultsOnly, Category = "Inventory")
double TraceLength;
// Cannot expose an ENum directly for changing in the editor with UPROPERTY. It muSt be wrapped in a
// TEnumAsByte<> for it to appear as a list.
UPROPERTY(EditDefaultsOnly, Category = "Inventory")
TEnumAsByte<ECollisionChannel> ItemTraceChannel;
TWeakObjectPtr<AActor> ThisActor; //actor hit in this frame
TWeakObjectPtr<AActor> LastActor; //actor hit last frame
};
点击查看代码
// Fill out your copyright notice in the Description page of Project Settings.
#include "InventorySystem/InventoryManagement/Components/Inv_InteractComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "InventorySystem/InventoryManagement/Components/Inv_InventoryComponent.h"
#include "InventorySystem/Interaction/Inv_Highlightable.h"
#include "InventorySystem/Items/Components/Inv_ItemComponent.h"
#include "Kismet/GameplayStatics.h"
#include "InventorySystem/Widgets/HUD/Inv_HUDWidget.h"
#include "InventorySystem/Widgets/Utils/Inv_WidgetUtils.h"
class UEnhancedInputLocalPlayerSubsystem;
UInv_InteractComponent::UInv_InteractComponent()
{
PrimaryComponentTick.bCanEverTick = true;
TraceLength = 500.0f;
ItemTraceChannel = ECC_GameTraceChannel1;
}
void UInv_InteractComponent::BeginPlay()
{
Super::BeginPlay();
SetupInputComponent();
CreateHUDWidget();
InventoryComponent = GetOwner()->FindComponentByClass<UInv_InventoryComponent>();
}
// *********************************************************************************************************
// Actor Components do not have a SetupInputComponent function that can be overriden.
// Therefore, this is defined manually and called from BeginPlay.
// Get the PlayerController this is attached to and then bind actions to the PC's Enhanced Input Component
// *********************************************************************************************************
void UInv_InteractComponent::SetupInputComponent()
{
if (const APlayerController* PC = Cast<APlayerController>(GetOwner()))
{
if (const ULocalPlayer* LocalPlayer = PC->GetLocalPlayer())
{
if (UEnhancedInputLocalPlayerSubsystem* EISubSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
EISubSystem->AddMappingContext(DefaultIMC, 0);
}
}
// Retrieve the EnhancedInputComponent from the PC
if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PC->InputComponent))
{
// now bind exactly as we did in SetupInputComponent on the PC
EIC->BindAction(PrimaryInteractAction, ETriggerEvent::Started,this, &ThisClass::PrimaryInteract);
EIC->BindAction(ToggleInventoryAction, ETriggerEvent::Started,this, &ThisClass::ToggleInventory);
}
}
}
void UInv_InteractComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
//Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
TraceForItem();
}
void UInv_InteractComponent::PrimaryInteract()
{
if (!ThisActor.IsValid()) return;
UInv_ItemComponent* ItemComp = ThisActor->FindComponentByClass<UInv_ItemComponent>();
if (!IsValid(ItemComp) || !InventoryComponent.IsValid()) return;
InventoryComponent->TryAddItem(ItemComp);
}
void UInv_InteractComponent::CreateHUDWidget()
{
APlayerController* PC = Cast<APlayerController>(GetOwner());
if (!PC->IsLocalController()) return;
HUDWidget = CreateWidget<UInv_HUDWidget>(PC, HUDWidgetClass);
if (IsValid(HUDWidget))
{
HUDWidget->AddToViewport();
}
}
void UInv_InteractComponent::ToggleInventory()
{
if (!InventoryComponent.IsValid()) return;
InventoryComponent->ToggleInventoryMenu();
if (InventoryComponent->IsMenuOpen())
{
HUDWidget->SetVisibility(ESlateVisibility::Hidden);
}
else
{
// 将鼠标指针恢复到中心点
if (APlayerController* PC = Cast<APlayerController>(GetOwner()))
{
FVector2D ViewportSize;
GEngine->GameViewport->GetViewportSize(ViewportSize); // 获取视口大小
const FVector2D ViewportCenter = ViewportSize / 2.f; // 获取中心点位置
PC->SetMouseLocation(ViewportCenter.X, ViewportCenter.Y);
}
HUDWidget->SetVisibility(ESlateVisibility::HitTestInvisible);
}
}
void UInv_InteractComponent::TraceForItem()
{
if (!IsValid(GEngine) || !IsValid(GEngine->GameViewport)) return;
const APlayerController* PC = Cast<APlayerController>(GetOwner());
FVector2D ViewportSize;
GEngine->GameViewport->GetViewportSize(ViewportSize); // 获取视口大小
const FVector2D ViewportCenter = ViewportSize / 2.f; // 获取中心点位置
FVector TraceStart;
FVector Forward;
bool bSuccessful = UGameplayStatics::DeprojectScreenToWorld(PC, ViewportCenter, TraceStart, Forward); // 转换为世界位置
if (!bSuccessful) return;
const FVector TraceEnd = TraceStart + Forward * TraceLength;
FHitResult HitResult;
GetWorld()->LineTraceSingleByChannel(HitResult, TraceStart, TraceEnd, ItemTraceChannel); // Line Trace
LastActor = ThisActor;
ThisActor = HitResult.GetActor();
if (!ThisActor.IsValid())
{
// Hide Message
if (IsValid(HUDWidget)) HUDWidget->HidePickupMessage();
}
if (ThisActor == LastActor) return;
if (ThisActor.IsValid())
{
// High light
UActorComponent* Highlightable = ThisActor->FindComponentByInterface(UInv_Highlightable::StaticClass());
if (IsValid(Highlightable))
{
IInv_Highlightable::Execute_Highlight(Highlightable);
}
// Show Message
UInv_ItemComponent* ItemComponent = ThisActor->FindComponentByClass<UInv_ItemComponent>();
if (IsValid(ItemComponent))
{
if (IsValid(HUDWidget)) HUDWidget->ShowPickupMessage(ItemComponent->GetPickupMessage());
// Create Short ItemDescription
CreateShortItemDescription.Broadcast(ItemComponent);
}
}
if (LastActor.IsValid())
{
// UnHigh light
UActorComponent* Highlightable = LastActor->FindComponentByInterface(UInv_Highlightable::StaticClass());
if (IsValid(Highlightable))
{
IInv_Highlightable::Execute_UnHighlight(Highlightable);
}
UInv_ItemComponent* ItemComponent = LastActor->FindComponentByClass<UInv_ItemComponent>();
// Destroy Short ItemDescription
if (ItemComponent)
{
DestroyShortItemDescription.Broadcast(ItemComponent);
}
}
}
点击查看代码
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "Inv_PlayerController.generated.h"
/**
*
*/
UCLASS()
class INVENTORYSYSTEM_API AInv_PlayerController : public APlayerController
{
GENERATED_BODY()
public:
AInv_PlayerController();
virtual void Tick(float DeltaSeconds) override;
protected:
virtual void BeginPlay() override;
private:
};
点击查看代码
// Fill out your copyright notice in the Description page of Project Settings.
#include "InventorySystem/Player/Inv_PlayerController.h"
AInv_PlayerController::AInv_PlayerController()
{
PrimaryActorTick.bCanEverTick = true;
}
void AInv_PlayerController::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
void AInv_PlayerController::BeginPlay()
{
Super::BeginPlay();
}
Instructions
========================================
** Important: If you have been modifying your own PC for your own project, you will need to remove all the course code from it for this to work! If you are worried about bricking your project because it is currently working for you, don't do this on that project. Do it on a blank project like what we created for the course at the start. I am not liable for you screwing up your exiting project - this is intended to augment Sensei Stephen's course *as is*.
1) Add the Inv_InteractComponent files to the InventoryManagement/Components public and private folders
2) Replace your Inv_PlayerController files in the course with the empty ones I have attached if you want a quick replacement. Otherwise create your own empty PlayerController class.
3) Compile and launch editor
4) Make a blueprint of the Inv_InteractComponent class and fill in its fields in the Inventory category
5) Attach the component to the player controller blueprint alongside the Inv_InventoryComponent
****** Important change:
6) Modify the close button blueprint to call "Get Component By Class" from the PlayerController, and select Inv_InteractComponent. Then call ToggleInventory from that.
Once these changes are made, the plugin can be added to an project. Just make sure to add both components to the PC and you should be good.

浙公网安备 33010602011771号