Hello all. I have been using Unreal Engine for a few months now, and for the past month or so I’ve started to work on my own project in C++. I’m having issues some custom classes I created, called Item, Equipment (which inherits from Item), and InventoryComponent (Actor Component to attach to player). The first issue I have is with Equipment/Item. I made a child BP from Equipment called BP_Sword with a mesh and put it into the world, but when I try to press play, the editor crashes, due to an access violation with a function called GetInventory() that’s on my player (it just returns the private InventoryComponent* Inventory).
Item.h:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"
class UInventoryComponent;
class UStaticMeshComponent;
UCLASS()
class PROJECTFIRSTPASS_API AItem : public AActor
{
GENERATED_BODY()
private:
public:
// Sets default values for this actor's properties
AItem();
UWorld* World;
UInventoryComponent* OwningInventory;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UStaticMeshComponent* Mesh;
};
Item.cpp:
#include "Item.h"
#include "InventoryComponent.h"
#include "Components/StaticMeshComponent.h"
// Sets default values
AItem::AItem()
{
PrimaryActorTick.bCanEverTick = false;
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
Mesh->SetupAttachment(RootComponent);
}
// Called when the game starts or when spawned
void AItem::BeginPlay()
{
Super::BeginPlay();
this->Tags.Add(FName("Item"));
}
Equipment.h:
#pragma once
#include "CoreMinimal.h"
#include "Item.h"
#include "Equipment.generated.h"
class AMeleeCharacter;
class UInventoryComponent;
UCLASS()
class PROJECTFIRSTPASS_API AEquipment : public AItem
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Inventory", meta = (AllowPrivateAccess = "true"))
FName SocketEquipped;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Inventory", meta = (AllowPrivateAccess = "true"))
FName SocketUnequipped;
ACharacter* PlayerCharacter;
AMeleeCharacter* PlayerRef;
UInventoryComponent* InventoryRef;
public:
AEquipment();
void EquipUnequip(AMeleeCharacter* Character);
protected:
bool bEquipped;
virtual void BeginPlay() override;
};
Equipment.cpp:
#include "Equipment.h"
#include "InventoryComponent.h"
#include "MeleeCharacter.h"
#include "Kismet/GameplayStatics.h"
AEquipment::AEquipment()
{
PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
PlayerRef = Cast<AMeleeCharacter>(PlayerCharacter);
}
void AEquipment::EquipUnequip(AMeleeCharacter* Character)
{
if (!bEquipped)
{
this->AttachToActor(Character, FAttachmentTransformRules::SnapToTargetIncludingScale, SocketEquipped);
}
else
{
if (SocketUnequipped == "")
{
this->Destroy();
}
this->AttachToActor(Character, FAttachmentTransformRules::SnapToTargetIncludingScale, SocketUnequipped);
}
}
void AEquipment::BeginPlay()
{
Super::BeginPlay();
InventoryRef = PlayerRef->GetInventory();
if (InventoryRef->Items.Find(this))
{
this->bEquipped = false;
this->AttachToActor(PlayerRef, FAttachmentTransformRules::SnapToTargetIncludingScale, SocketUnequipped);
}
this->Tags.Add(FName("Equipment"));
}
InventoryComponent.h:
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Delegates/Delegate.h"
#include "InventoryComponent.generated.h"
//Blueprints will bind this to update the UI
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInventoryUpdated);
class AItem;
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class PROJECTFIRSTPASS_API UInventoryComponent : public UActorComponent
{
GENERATED_BODY()
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Sets default values for this component's properties
UInventoryComponent();
bool AddItem(AItem* Item);
UPROPERTY(BlueprintAssignable, Category = "Inventory")
FOnInventoryUpdated OnInventoryUpdated;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Items")
TArray<AItem*> Items;
UPROPERTY(EditDefaultsOnly, Instanced)
TArray<AItem*> DefaultItems;
};
InventoryComponent.cpp:
#include "InventoryComponent.h"
#include "Item.h"
#include "Equipment.h"
// Sets default values for this component's properties
UInventoryComponent::UInventoryComponent()
{
}
// Called when the game starts
void UInventoryComponent::BeginPlay()
{
Super::BeginPlay();
for (auto& Item : DefaultItems)
{
AddItem(Item);
}
}
bool UInventoryComponent::AddItem(AItem* Item)
{
if(!Item){ return false;}
Item->OwningInventory = this;
Item->World = GetWorld();
Items.Add(Item);
OnInventoryUpdated.Broadcast();
return true;
}
Relevant MeleeCharacter.h:
class UInventoryComponent;
UCLASS()
class PROJECTFIRSTPASS_API AMeleeCharacter : public ACharacter
{
GENERATED_BODY()
private:
.....
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Inventory", meta = (AllowPrivateAccess = "true"))
UInventoryComponent* Inventory;
......
public:
UInventoryComponent* GetInventory();
Relevant MeleeCharacter.cpp:
#include "MeleeCharacter.h"
#include "InventoryComponent.h"
#include "Item.h"
// Sets default values
AMeleeCharacter::AMeleeCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Inventory = CreateDefaultSubobject<UInventoryComponent>(TEXT("Equipment"));
}
UInventoryComponent* AMeleeCharacter::GetInventory()
{
return Inventory;
}
So like I said. Putting the object BP_Sword into the world (which is a child of Equipment) and pressing play crashes the editor. I also cannot add BP_Sword (which is a child of Equipment and therefore technically of type Item) to the TArray DefaultItems that’s in the player character I have in my world. Not sure what to do. And honestly since I’m so new my approach to making an inventory might be pretty terrible in which case I’m open to tossing it if I’m just heading in the completely wrong direction. But if fixable I would like to know how. Thanks to anyone who can help