UIの追加 - ストアアイテム購入 - (Unreal Engineモジュール)
注釈:本資料はAI技術を用いて翻訳されています。
ゲームのセットアップ
実装を簡素化するため、Byte WarsにはUStoreItemPriceDataObjectというカスタムUObjectクラスが含まれており、アイテムの必須価格データのみを保存します。保存されるデータは以下の通りです:
UCLASS(BlueprintType)
class UStoreItemPriceDataObject : public UObject
{
// ...
private:
UPROPERTY(EditAnywhere)
ECurrencyType CurrencyType;
UPROPERTY(EditAnywhere)
int64 RegularPrice;
UPROPERTY(EditAnywhere)
int64 FinalPrice;
};
メニューの内容
このセクションでは、ゲーム内ストアからアイテムを購入するために使用されるウィジェットの準備方法を学びます。関連ファイルはリソースセクションで入手できます。
アイテム購入ボタン
ItemPurchaseButton: アイテムの詳細を表示するために使用されるC++クラスです。このメニューはすぐに使用できるコンポーネントとして提供されているため、変更する必要はありません。- ヘッダーファイル:
Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/Component/ItemPurchaseButton.h - CPPファイル:
Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/Component/ItemPurchaseButton.cpp - Blueprintウィジェット:
Content/TutorialModules/Monetization/StoreItemPurchase/UI/Components/W_ItemPurchaseButton.uasset
- ヘッダーファイル:
ItemPurchaseButtonは、アイテム価格ウィジェットコンポーネントを含むボタンです。後でこのウィジェットの押下イベントに購入リクエストをトリガーする関数をバインドしますが、ウィジェット自体には購入固有のロジックは含まれていません。
以下はItemPurchaseButton Blueprintウィジェットのプレビューです:

このウィジェットで使用されるコンポーネントは、ItemPurchaseButtonクラスのヘッダーファイルで定義されています。
private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UStoreItemPriceListEntry* W_Price;
このウィジェットを初期化するには、SetPrice()関数を使用します。この関数は、提供された価格データと数量乗数に基づいてUIコンポーネントを更新します。
public:
void SetPrice(const UStoreItemPriceDataObject* PriceData, const int32 PriceMultiplier = 1) const;
アイテム購入ウィジェット
ItemPurchaseWidget_Starter: アイテムの詳細を表示するために使用されるC++クラスです。このメニューはすぐに使用できるコンポーネントとして提供されているため、変更する必要はありません。- ヘッダーファイル:
Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/ItemPurchaseWidget_Starter.h - CPPファイル:
Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/ItemPurchaseWidget_Starter.cpp - Blueprintウィジェット:
Content/TutorialModules/Monetization/StoreItemPurchase/UI/W_StoreItemPurchase_Starter.uasset
- ヘッダーファイル:
以下はItemPurchaseWidget_Starter Blueprintウィジェットのプレビューです:

このウィジェットで使用されるコンポーネントは、ItemPurchaseWidget_Starterクラスのヘッダーファイルで定義されています。
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;
このウィジェットには、Byte Wars統合用にカスタマイズされた事前設定済みの変数とヘルパー関数が含まれています。
- この購入ウィジェットが表すアイテムデータを保存する変数。
private:
// ...
UPROPERTY()
UStoreItemDataObject* StoreItemDataObject;
void UItemPurchaseWidget_Starter::NativeOnActivated()
{
// ...
W_Parent = GetFirstOccurenceOuter<UStoreItemDetailWidget>();
ensure(W_Parent);
StoreItemDataObject = W_Parent->StoreItemDataObject;
ensure(StoreItemDataObject);
// ...
}
- アイテム購入ロジックを処理するサブシステムへの参照。
private:
UPROPERTY()
UStoreItemPurchaseSubsystem_Starter* PurchaseSubsystem;
void UItemPurchaseWidget_Starter::NativeOnActivated()
{
// ...
PurchaseSubsystem = GetGameInstance()->GetSubsystem<UStoreItemPurchaseSubsystem_Starter>();
ensure(PurchaseSubsystem);
// ...
}
- 購入完了後に他のオブジェクトが応答できるようにする静的デリゲート。このデリゲートはEntitlement Essentialsモジュールで使用されます。
public:
inline static TMulticastDelegate<void(const APlayerController*)> OnPurchaseCompleteMulticastDelegate;
- アイテム購入ボタンをセットアップする関数。
private:
void SetupPurchaseButtons(TArray<UStoreItemPriceDataObject*> Prices);
- 選択された数量に基づいて購入ボタンに表示される価格を更新する関数。
private:
// ...
void UpdatePrice(const int32 SelectedIndex);
- 現在選択されている数量を取得する関数。
private:
// ...
int32 GetSelectedAmount() const;
メニューの準備
-
ItemPurchaseWidget_Starterヘッダーファイルを開き、以下の関数宣言を追加します。private:
// ...
void OnClickPurchase(const int32 PriceIndex) const;
void OnPurchaseComplete(const FOnlineError& Error) const; -
ItemPurchaseWidget_StarterCPPファイルを開き、OnClickPurchase()関数を実装します。この段階では、ローディング状態を表示するだけです。後でこの関数で購入リクエストを呼び出します。void UItemPurchaseWidget_Starter::OnClickPurchase(const int32 PriceIndex) const
{
Ws_Root->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Loading);
// ...
} -
SetupPurchaseButtons()関数を見つけて、既存の実装を以下のコードに置き換えます。このコードは、OnClickPurchase()関数をアイテム購入ボタンにバインドし、表示する価格を設定します。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);
}
} -
OnPurchaseComplete()関数を実装します。この関数はOnPurchaseCompleteMulticastDelegateデリゲートをトリガーして、リクエストが完了するとすぐに他のオブジェクトが応答できるようにします。また、成功または失敗にかかわらず、結果を表示します。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);
}
} -
NativeOnActivated()関数を見つけて、既存の実装を以下のコードに置き換えます。このコードは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();
} -
NativeOnDeactivated()関数に移動し、既存の実装を以下のコードに置き換えます。このコードはOnSelectionChangedDelegateのバインドを解除して、ウィジェットが正常に閉じられるようにします。void UItemPurchaseWidget_Starter::NativeOnDeactivated()
{
Super::NativeOnDeactivated();
// ...
Ss_Amount->OnSelectionChangedDelegate.RemoveAll(this);
// ...
} -
プロジェクトをビルドし、完了したらUnreal Editorで開きます。
-
Content/TutorialModules/Monetization/StoreItemPurchase/DA_StoreItemPurchase.uassetを開き、Is Starter Mode Activeを有効にします。Data Assetを保存します。
リソース
- このチュートリアルセクションで使用されるファイルは、Byte Wars GitHubリポジトリで入手できます。
- AccelByteWars/Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/ItemPurchaseWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Monetization/StoreItemPurchase/UI/ItemPurchaseWidget_Starter.cpp
- AccelByteWars/Content/TutorialModules/Monetization/StoreItemPurchase/UI/W_StoreItemPurchase_Starter.uasset
- AccelByteWars/Content/TutorialModules/Monetization/StoreItemPurchase/DA_StoreItemPurchase.uasset