Pull to refresh

UENUM iteration in Unreal Engine

Level of difficultyEasy
Reading time3 min
Views533
Original author: MMadmer

Preface

I needed to create a category panel for placeable items in the UI — like the ones you see in city-building games. As a legacy, I inherited a ready-made UENUM, which may be modified in the future.

Naturally, I didn’t want to manually create and tweak every single widget — especially knowing that the list of categories might change later. I wanted something simple and reusable: just run a For each loop, generate everything on the fly, and ideally make it work for any enum, not just this one.

And there was a way! When you define a UENUM, Unreal automatically generates all the metadata and creates a corresponding UEnum object, which is a UObject. All you have to do is use that data properly.


Creating uenum iterator

For convenience, we will use UBlueprintAsyncActionBase, although it is not the only way.

Let's create an inheritor class UEnumIterateAction.

.h file
#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "EnumIterateAction.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnEnumIteration, const uint8, EnumValue);

/**
 * 
 */
UCLASS()
class YOUR_MODULE_API UEnumIterateAction : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()

public:
    /** Our execution output at each iteration.*/
	UPROPERTY(BlueprintAssignable)
	FOnEnumIteration OnEnumIteration;

    /** The function itself, which we will call(almost).*/
	UFUNCTION(BlueprintCallable, BlueprintInternalUseOnly)
	static UEnumIterateAction* IterateByEnum(UEnum* Enum, const bool SkipMax = true);

protected:
	virtual void Activate() override;

private:
	TWeakObjectPtr EnumToIterate;
	uint8 bSkipMax : 1;
};

What are we doing here?

I won’t dive deep into UBlueprintAsyncActionBase — this article isn’t really about that. I’ll just cover the relevant parts.

First, we create the IterateByEnum function, which acts as our constructor. The first argument is the UEnum we want to iterate through. Since enums created in Blueprints automatically get a hidden MAX value at the end, it’s a good idea to optionally skip it — so we’ll add a flag for that as the second argument.

The OnEnumIteration delegate will be triggered on each iteration. Think of it as the “async” execution pin. Just make sure to use a uint8 for the value, since that’s how we’ll represent enum entries and cast them back in Blueprints.

Next, we override the Activate function from the base class. That’s where the actual logic goes — the body of our callable node.

And because IterateByEnum works like a constructor, we need to store the input arguments for use in Activate. So, we’ll add two member fields: EnumToIterate and bSkipMax.

That’s all for setup — let’s move on to the implementation.

Iterator implementation

.cpp file
#include "AsyncActions/EnumIterateAction.h"

UEnumIterateAction* UEnumIterateAction::IterateByEnum(UEnum* Enum, const bool SkipMax)
{
	const auto Action = NewObject<UEnumIterateAction>();
	if (!IsValid(Action)) return nullptr;

	Action->EnumToIterate = Enum;
	Action->bSkipMax = SkipMax;

	return Action;
}

void UEnumIterateAction::Activate()
{
	Super::Activate();

	if (!EnumToIterate.IsValid()) return;

	for (int32 Index = 0; Index < EnumToIterate->NumEnums(); ++Index)
	{
        // Get the current enum value and check if it is maximal
        const int64 EnumValue = EnumToIterate->GetValueByIndex(Index);
        if (bSkipMax && EnumValue == EnumToIterate->GetMaxEnumValue()) continue;

        // Convert the enum value to byte, for conversion into blueprints
        const uint8 EnumValueAsByte = static_cast<uint8>(EnumValue);

        OnEnumIteration.Broadcast(EnumValueAsByte);
	}
}

What’s going on here?

The implementation of our IterateByEnum function is pretty straightforward. As mentioned earlier, it basically works like a constructor, so we won’t spend time on it here.

Inside the Activate function, we access the stored enum and loop through it using a standard for loop — just like you would with an array.

Unreal stores enum values as int64, so that’s the type we get when accessing them by index. But for our purposes, we need a Byte, since that’s the only type Blueprints can convert back into an enum value.

It’s also important to skip hidden enum entries — they’re usually not meant to be shown anyway.

We’ve also added a flag to optionally skip the auto-generated MAX entry, which often doesn’t hold any meaningful value either. Since MAX is also stored as an int64, we compare the raw EnumValue with the result of GetMaxEnumValue before converting it to a Byte.


Result

Call of the iterator function
Call of the iterator function
Output of enum values
Output of enum values
Initial enum values
Initial enum values

As you can see, everything works great!

Tags:
Hubs:
0
Comments0

Articles