Since I cannot see how you’re initializing the variables it is difficult to tell exactly what is going wrong with your code. However, here is a very quick mock-up that works. Try to compare it with your code.
//Header
//----------------------------
UENUM(Blueprintable)
enum EResourceType
{
default,
metal,
wood,
brick
};
UCLASS()
class ANSWERHUB_API ATestActor : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
TMap<TEnumAsByte<EResourceType>, int32> resources;
public:
// Sets default values for this actor's properties
ATestActor();
protected:
virtual void BeginPlay() override;
};
//CPP
//----------------------------
// Sets default values
ATestActor::ATestActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
}
void ATestActor::BeginPlay()
{
Super::BeginPlay();
//Initialise the resources map and add some default values
resources.Add(EResourceType::brick, 10);
resources.Add(EResourceType::metal, 20);
resources.Add(EResourceType::wood, 30);
//Loop through each of the resource entries
for (auto& resource : resources)
{
//Local variable to read the KEY of the current element
TEnumAsByte<EResourceType> resourceKey = resource.Key;
//Local variable to read the VALUE of the current element
int32 resourceValue = resource.Value;
//Print out the locally stored data for the current KEY and VALUE
UE_LOG(LogTemp, Log, TEXT("The key is %s, the value is %d"), *UEnum::GetValueAsString(resourceKey.GetValue()), resourceValue);
}
}
Hope this helps. If you have any questions, let me know.
Nice, your example works, thanks. But could you please explain why result of resource.Value is correct and if I change it to resources.Find(resourceKey) it gives me weird numbers?
Because that’s what’s documentation says about Find() function.
Find the value associated with a specified key.
Returns a pointer to the value associated with the specified key, or nullptr if the key isn’t contained in this map. The pointer is only valid until the next change to any key in the map.
Doesn’t that mean exactly what I’m doing - getting a value based on a key? And I definitely do not modify any of the map’s keys between
UE_LOG(LogTemp, Log, TEXT("The key is %s, the value is %d"), *UEnum::GetValueAsString(resourceKey.GetValue()), resourceValue);
I’ll explain why I am trying to do this with Find() function instead of just getting the Value directly.
I want to compare recources left with the resources cost of the building and return bool of comparison.
I got 2 TMap of the same type, 1 for ResourcesLeft, the other one for resources cost of a building.
Here is the function I’m stuck with
bool ATDPlayerControllerBase::IsEnoughResourcesForBuild(TMap<EResourceType, int32> ResourcesCost;)
{
/*
TMap<EResourceType, int32> ResourcesCost;
is created in the Editor and passed as an arguments to the function,
TMap<EResourceType, int32> ResourcesLeft;
is a public member of the class and is set in the Editor as well. And I've checked - both of them contain correct values
*/
for(auto& ResourceCost :ResourcesCost)
{
if(ResourceCost.Value > ResourcesLeft.Find(ResourceCost.Key))
{
return false;
}
}
return true;
}
Unfortunately epic have got their meanings the wrong way round with the Find() and the FindRef() methods in TMap.
TMap::Find() will return a pointer (address in memory).
TMap::FindRef() will return the value assigned.
If you are want to retrieve a value from a pointer, you need to use the * symbol.
I have amended my previous example to demonstrate. Note I called my second map “inventory” just so it’s easier to distinguish.
Here is the output in my log:
LogTemp: brick has a value less than the inventory
LogTemp: metal has a value equal or greater than the inventory
LogTemp: wood has a value equal or greater than the inventory
Code:
void ATestActor::BeginPlay()
{
Super::BeginPlay();
resources.Add(EResourceType::brick, 10);
resources.Add(EResourceType::metal, 20);
resources.Add(EResourceType::wood, 30);
inventory.Add(EResourceType::brick, 30);
inventory.Add(EResourceType::metal, 20);
inventory.Add(EResourceType::wood, 10);
for (auto& resource : resources)
{
TEnumAsByte<EResourceType> resourceKey = resource.Key;
int32 resourceValue = resource.Value;
if (resourceValue < *inventory.Find(resourceKey))
{
UE_LOG(LogTemp, Log, TEXT("%s has a value less than the inventory"), *UEnum::GetValueAsString(resourceKey.GetValue()));
}
else
{
UE_LOG(LogTemp, Log, TEXT("%s has a value equal or greater than the inventory"), *UEnum::GetValueAsString(resourceKey.GetValue()));
}
}
}