メインコンテンツまでスキップ

Adding UI - Store Item Purchase - (Unreal Engine module)

Last updated on July 28, 2025

Game setup

To simplify the implementation, Byte Wars includes a custom UObject class named UStoreItemPriceDataObject, which stores only the essential price data for items. The data stored is shown below:

UCLASS(BlueprintType)
class UStoreItemPriceDataObject : public UObject
{
// ...
private:
UPROPERTY(EditAnywhere)
ECurrencyType CurrencyType;

UPROPERTY(EditAnywhere)
int64 RegularPrice;

UPROPERTY(EditAnywhere)
int64 FinalPrice;
};

What's on the menu

In this section, you'll learn how to prepare the widgets used to purchase items from the in-game store. The related files are available in the Resources section.

Item purchase button

  • ItemPurchaseButton: A C++ class used to display item details. You won't need to modify this menu, as it’s provided as a ready-to-use component.
    • Header file: Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/Component/ItemPurchaseButton.h
    • CPP file: Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/Component/ItemPurchaseButton.cpp
    • Blueprint widget: Content/TutorialModules/Monetization/StoreItemPurchase/UI/Components/W_ItemPurchaseButton.uasset

The ItemPurchaseButton is a button that includes an item price widget component. You’ll later bind a function to trigger the purchase request to this widget’s pressed event, but the widget itself does not contain purchase-specific logic.

Here is a preview of the ItemPurchaseButton Blueprint widget:

Item purchase widget preview

The components used in this widget are defined in the ItemPurchaseButton class header file.

private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UStoreItemPriceListEntry* W_Price;

To initialize this widget, use the SetPrice() function. It updates the UI components based on the provided price data and amount multiplier.

public:
void SetPrice(const UStoreItemPriceDataObject* PriceData, const int32 PriceMultiplier = 1) const;

Item purchase widget

  • ItemPurchaseWidget_Starter: A C++ class used to display item details. You won't need to modify this menu, as it’s provided as a ready-to-use component.
    • Header file: Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/ItemPurchaseWidget_Starter.h
    • CPP file: Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/ItemPurchaseWidget_Starter.cpp
    • Blueprint widget: Content/TutorialModules/Monetization/StoreItemPurchase/UI/W_StoreItemPurchase_Starter.uasset

Here is a preview of the ItemPurchaseWidget_Starter Blueprint widget:

Item purchase widget preview

The components used in this widget are defined in the ItemPurchaseWidget_Starter class header file.

private:
// ...
UPROPERTY()
UStoreItemDetailWidget* W_Parent;

UPROPERTY(EditAnywhere)
TSubclassOf<UItemPurchaseButton> PurchaseButtonClass;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UAccelByteWarsWidgetSwitcher* Ws_Root;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UPanelWidget* W_PurchaseButtonsOuter;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_Success;

UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_Error;

This widget includes pre-configured variables and helper functions tailored for Byte Wars integration.

  • Variable that stores the item data represented by this purchase widget.
private:
// ...
UPROPERTY()
UStoreItemDataObject* StoreItemDataObject;
void UItemPurchaseWidget_Starter::NativeOnActivated()
{
// ...
W_Parent = GetFirstOccurenceOuter<UStoreItemDetailWidget>();
ensure(W_Parent);

StoreItemDataObject = W_Parent->StoreItemDataObject;
ensure(StoreItemDataObject);
// ...
}
  • Reference to the subsystem that handles the item purchase logic.
private:
UPROPERTY()
UStoreItemPurchaseSubsystem_Starter* PurchaseSubsystem;
void UItemPurchaseWidget_Starter::NativeOnActivated()
{
// ...
PurchaseSubsystem = GetGameInstance()->GetSubsystem<UStoreItemPurchaseSubsystem_Starter>();
ensure(PurchaseSubsystem);
// ...
}
  • Static delegate that lets other objects respond after a purchase is completed. This delegate will be used in the Entitlement Essentials module.
public:
inline static TMulticastDelegate<void(const APlayerController*)> OnPurchaseCompleteMulticastDelegate;
  • Function to set up the item purchase buttons.
private:
void SetupPurchaseButtons(TArray<UStoreItemPriceDataObject*> Prices);
  • Function to update the price shown on the purchase buttons based on the selected amount.
private:
// ...
void UpdatePrice(const int32 SelectedIndex);
  • Function to get the currently selected amount.
private:
// ...
int32 GetSelectedAmount() const;

Ready the menu

  1. Open the ItemPurchaseWidget_Starter header file and add the following function declarations.

    private:
    // ...
    void OnClickPurchase(const int32 PriceIndex) const;
    void OnPurchaseComplete(const FOnlineError& Error) const;
  2. Open the ItemPurchaseWidget_Starter CPP file and implement the OnClickPurchase() function. At this stage, it only shows the loading state. You’ll call the purchase request in this function later.

    void UItemPurchaseWidget_Starter::OnClickPurchase(const int32 PriceIndex) const
    {
    Ws_Root->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Loading);
    // ...
    }
  3. Find the SetupPurchaseButtons() function and replace the existing implementation with the code below. This code binds the OnClickPurchase() function to the item purchase button and set up the price to be shown.

    void UItemPurchaseWidget_Starter::SetupPurchaseButtons(TArray<UStoreItemPriceDataObject*> Prices)
    {
    W_PurchaseButtonsOuter->ClearChildren();
    for (int i = 0; i < Prices.Num(); ++i)
    {
    UItemPurchaseButton* Entry = CreateWidget<UItemPurchaseButton>(this, PurchaseButtonClass);
    ensure(Entry);

    Entry->SetPrice(Prices[i], GetSelectedAmount());
    Entry->OnClicked().AddUObject(this, &ThisClass::OnClickPurchase, i);
    W_PurchaseButtonsOuter->AddChild(Entry);
    }
    }
  4. Implement the OnPurchaseComplete() function. This function triggers the OnPurchaseCompleteMulticastDelegate delegate so that other objects can respond as soon as the request completes. It also displays the result, whether it succeeded or failed.

    void UItemPurchaseWidget_Starter::OnPurchaseComplete(const FOnlineError& Error) const
    {
    OnPurchaseCompleteMulticastDelegate.Broadcast(GetOwningPlayer());
    Ws_Root->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Not_Empty);

    if (Error.bSucceeded)
    {
    Tb_Success->SetVisibility(ESlateVisibility::Visible);
    Tb_Error->SetVisibility(ESlateVisibility::Collapsed);

    // update wallet
    if (TWeakObjectPtr<UAccelByteWarsActivatableWidget> Widget = W_Parent->GetBalanceWidget(); Widget.IsValid())
    {
    Widget->DeactivateWidget();
    Widget->ActivateWidget();
    }
    }
    else
    {
    Tb_Error->SetText(FText::FromString(Error.ErrorRaw));

    Tb_Success->SetVisibility(ESlateVisibility::Collapsed);
    Tb_Error->SetVisibility(ESlateVisibility::Visible);
    }
    }
  5. Find the NativeOnActivated() function and replace the existing implementation with the code below. This code resets the UI.

    void UItemPurchaseWidget_Starter::NativeOnActivated()
    {
    Super::NativeOnActivated();

    W_Parent = GetFirstOccurenceOuter<UStoreItemDetailWidget>();
    ensure(W_Parent);

    StoreItemDataObject = W_Parent->StoreItemDataObject;
    ensure(StoreItemDataObject);

    PurchaseSubsystem = GetGameInstance()->GetSubsystem<UStoreItemPurchaseSubsystem_Starter>();
    ensure(PurchaseSubsystem);
    // ...
    // Setup UI
    SetupPurchaseButtons(StoreItemDataObject->GetPrices());
    Ws_Root->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Not_Empty);
    Tb_Success->SetVisibility(ESlateVisibility::Collapsed);
    Tb_Error->SetVisibility(ESlateVisibility::Collapsed);
    Ss_Amount->SetSelectedIndex(0);
    Ss_Amount->OnSelectionChangedDelegate.AddUObject(this, &ThisClass::UpdatePrice);

    // Show amount if consumable
    Ss_Amount->SetVisibility(StoreItemDataObject->GetIsConsumable() ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
    // ...
    // Set focus
    if (W_PurchaseButtonsOuter->HasAnyChildren())
    {
    W_PurchaseButtonsOuter->GetChildAt(0)->SetUserFocus(GetOwningPlayer());
    }

    FTUESetup();
    }
  6. Navigate to the NativeOnDeactivated() function and replace the existing implementation with the code below. This code unbinds the OnSelectionChangedDelegate to ensure the widget is cleanly closed.

    void UItemPurchaseWidget_Starter::NativeOnDeactivated()
    {
    Super::NativeOnDeactivated();
    // ...
    Ss_Amount->OnSelectionChangedDelegate.RemoveAll(this);
    // ...
    }
  7. Build the project and open it with the Unreal Editor once it's done.

  8. Open Content/TutorialModules/Monetization/StoreItemPurchase/DA_StoreItemPurchase.uasset and enable the Is Starter Mode Active. Save the Data Asset.

    Data Asset changes preview Unreal Byte Wars Store Item Purchase

Resources