0

I am pretty new to Unreal Engine and C++. I am creating an escape room in Unreal, but have come across error C4458 and am looking to see if anyone can help me see what I could do to fix it. Any help is appreciated!

No errors are shown in Visual Studio, only in Unreal Engine Compiler Log. When I try to compile C++ scripts, this error is shown:

Character_Controller.h(45): error C4458: declaration of 'item' hides class member Character_Controller.h(34): note: see declaration of 'FInventoryItem::item'

This is the Character_Controller.h script:

    // Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameFramework/Actor.h"
#include "GameFramework/Character.h"
#include "Components/InputComponent.h"
#include "Engine/DataTable.h"
#include "Engine/World.h"
#include "EscapeRoomGameModeBase.h"
#include "Item.h"
#include "Components/SphereComponent.h"
#include "Character_Controller.generated.h"

USTRUCT(BlueprintType)
struct FInventoryItem: public FTableRowBase
{
    GENERATED_BODY()

public:

    FInventoryItem()
    {
        name = FText::FromString("item");
        isVisible = false;
    }

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FName itemId;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        TSubclassOf<class AItem> item; <--- LINE 34

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FText name;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        bool isVisible;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        UTexture2D* image;

    bool operator==(const FInventoryItem& item) const <---- ERROR HERE
    {
        if (itemId == item.itemId)
            return true;
        else return false;
    }
};

UCLASS()
class ESCAPEROOM_API ACharacter_Controller : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    ACharacter_Controller();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    UFUNCTION(BlueprintCallable, Category = "Items")
        void Collect();

    UFUNCTION()
        void InventoryPlus();

    UFUNCTION()
        void InventoryMinus();

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
    void Horizontal_Movement(float axis);
    void Vertical_Movement(float axis);

    UFUNCTION(BlueprintCallable, Category = "Utilities")
        void AddToInventory(FName id);

    UFUNCTION(BlueprintCallable, Category = "Utilities")
        void RemoveFromInventory();

    UFUNCTION()
        void Wielding();

    UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
        TArray<FInventoryItem> inventory;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        int inventoryI;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
        class USphereComponent* collectionRange;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FInventoryItem wield;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        FInventoryItem empty;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        TArray<FInventoryItem> pickupableObjects;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Wield Items")
        TArray<AActor*> wieldObjects;

    FORCEINLINE class USphereComponent* GetCollectionRange() const { return collectionRange; }


};

Here is the Character_Controller.cpp script:

// Fill out your copyright notice in the Description page of Project Settings.


#include "Character_Controller.h"

// Sets default values
ACharacter_Controller::ACharacter_Controller()
{
    // 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;


    inventoryI = 0;
    empty.itemId = "0";

    collectionRange = CreateDefaultSubobject<USphereComponent>(TEXT("collectionRange"));
    collectionRange->AttachToComponent(RootComponent, FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true));
    collectionRange->AttachToComponent(RootComponent, FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true));
    collectionRange->SetSphereRadius(100.0f);

}

// Called when the game starts or when spawned
void ACharacter_Controller::BeginPlay()
{
    Super::BeginPlay();

    for (int i = 0; i < wieldObjects.Num(); i++)
    {
        if (wieldObjects[i])
        {
            wieldObjects[i]->SetActorHiddenInGame(true);
        }
    }
    
}

// Called every frame
void ACharacter_Controller::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void ACharacter_Controller::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    InputComponent->BindAxis("MoveX", this, &ACharacter_Controller::Vertical_Movement);
    InputComponent->BindAxis("MoveY", this, &ACharacter_Controller::Horizontal_Movement);

    InputComponent->BindAxis("CameraSide", this, &ACharacter_Controller::AddControllerYawInput);
    InputComponent->BindAxis("CameraUp", this, &ACharacter_Controller::AddControllerPitchInput);

    InputComponent->BindAction("Interaction", IE_Pressed, this, &ACharacter_Controller::Collect);
    InputComponent->BindAction("InteractionPlus", IE_Pressed, this, &ACharacter_Controller::InventoryPlus);
    InputComponent->BindAction("InteractionMinus", IE_Pressed, this, &ACharacter_Controller::InventoryMinus);
}

void ACharacter_Controller::Horizontal_Movement(float axis)
{
    if (axis)
    {
        AddMovementInput(GetActorRightVector(), axis);
    }
}

void ACharacter_Controller::Vertical_Movement(float axis)
{
    if (axis)
    {
        AddMovementInput(GetActorForwardVector(), axis);
    }
}

void ACharacter_Controller::Collect()
{
    TArray<AActor*> collectedItems;
    collectionRange->GetOverlappingActors(collectedItems);

    for (int i = 0; i < collectedItems.Num(); i++)
    {
        AItem* const testItem = Cast<AItem>(collectedItems[i]);
        if (testItem && testItem->GetActive())
        {
            testItem->Touched();
            AddToInventory(testItem->itemID);
            testItem->SetActive(false);
        }
    }
}

void ACharacter_Controller::InventoryPlus()
{
    inventoryI += 1;
    if (inventoryI >= 5)
    {
        inventoryI = 0;
    }
    Wielding();
}

void ACharacter_Controller::InventoryMinus()
{
    inventoryI -= 1;
    if (inventoryI < 0)
    {
        inventoryI = 4;
    }
    Wielding();
}

void ACharacter_Controller::AddToInventory(FName id)
{
    AEscapeRoomGameModeBase* gameMode = Cast<AEscapeRoomGameModeBase>(GetWorld()->GetAuthGameMode());
    UDataTable* itemTable = gameMode->GetItemsDB();

    if (gameMode)
    {
        if (itemTable)
        {
            FInventoryItem* itemAdded = itemTable->FindRow<FInventoryItem>(id, "");
            if (itemAdded)
            {
                inventory.Add(*itemAdded);
                Wielding();
            }
        }
    }
}

void ACharacter_Controller::RemoveFromInventory()
{
    if (inventory.Num() > inventoryI)
    {
        inventory.RemoveAt(inventoryI);
        Wielding();
    }
}

void ACharacter_Controller::Wielding()
{
    if (inventory.Num() > inventoryI)
    {
        wield = inventory[inventoryI];
        if (&wield)
        {
            FString wieldValue = wield.itemId.ToString();
            int wieldI = FCString::Atoi(*wieldValue);
            for (int i = 0; i < pickupableObjects.Num(); i++)
            {
                if (wield.itemId == pickupableObjects[i].itemId)
                {
                    if (wieldObjects[wieldI - 1])
                    {
                        wieldObjects[wieldI - 1]->SetActorHiddenInGame(false);
                    }
                }

                else
                {
                    if (wieldObjects[i])
                    {
                        wieldObjects[i]->SetActorHiddenInGame(true);
                    }
                }
            }
        }
        else
        {
            wield = empty;
        }

        if (wield == empty)
        {
            for (int i = 0; i < pickupableObjects.Num(); i++)
            {
                wieldObjects[i]->SetActorHiddenInGame(true);
            }
        }
    }
}
Alli
  • 1
  • 1
  • 4
    When you write `item` in the `operator==` function, is it meant to refer to the argument `item` or the data member `item` defined earlier? Call the argument something else. – Passerby Dec 02 '21 at 23:40
  • @Passerby In line 34 `(TSubclassOf item)` is meant to say what item the player is picking up. The bool operator is telling the system what the `== operator` means within the inventory items – Alli Dec 02 '21 at 23:48
  • What the compiler is saying is you can't have two things named `item` at the same time. If it matters, as in you do need both at the same time, you either jump through hoops or you change the name of one of them as passerby recommended. – user4581301 Dec 02 '21 at 23:50
  • The point is you have a data member of the class called `item` on line 34, and an argument called `item` on line 45. It's ambiguous, you're using the same name for two different things. – Passerby Dec 02 '21 at 23:50
  • Also think about the nastiness that can happen if you do a find and replace of a reused name. Or the annoyance of doing a search for where you use `item` while debugging and have to wade through false positives. – user4581301 Dec 02 '21 at 23:51
  • Unreal Engine Compiler treats warnings as errors. Why do not change the parameter or member name? Usually `other` or `rhl` parameter names used. – 273K Dec 02 '21 at 23:55
  • Okay, thank you all for your help. Do you think just changing the name to `items` on line 34 would work? Sorry if I sound dumb, I'm really new to C++. @user4581301 – Alli Dec 02 '21 at 23:58
  • @Passerby Ah okay I understand. So just changing the name in line 34 should work fine? – Alli Dec 02 '21 at 23:59
  • @S.M. Okay, I changed the name on line 34 to `items` instead and it works now. I'm going to input things in Unreal then see if it works. Thanks for your help! – Alli Dec 03 '21 at 00:00
  • 1
    Changing `item` to `items` is semantic not cosmetic. I don't know anything about Unreal but this strikes me as a mistake. That name is widely exposed whereas the argument is local to `operator==`, so I would consider changing the argument name instead, for example to `item_`. – Passerby Dec 03 '21 at 00:02
  • A couple coding styles I've followed in the past have marked differently scoped variables with prefixes, suffixes, and other arcane secrets. In one for example, `lvar` was a global variable with internal linkage, `gvar` for external linkage, `pvar` for a parameter, `mvar` for a member, and plain old `var` was a local. Nothing ever collided and sometimes seeing the scope in the name helped debugging. – user4581301 Dec 03 '21 at 00:10

0 Answers0