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

すべてをまとめる - チャレンジ - (Unreal Engine モジュール)

Last updated on February 4, 2026

注釈:本資料はAI技術を用いて翻訳されています。

チャレンジを表示するための UI の接続

  1. ChallengeWidget_Starter クラスの CPP ファイルを開き、GetChallengeGoalList() 関数を以下のコードに置き換えます。この実装では、先ほど作成したサブシステムを使用して期間別にチャレンジを取得し、そのチャレンジコードを使用してゴールのリストを取得して表示し、「すべて受け取る」ボタンを切り替えます。

    void UChallengeWidget_Starter::GetChallengeGoalList()
    {
    if (!GetOwningPlayer())
    {
    UE_LOG_CHALLENGE_ESSENTIALS(Warning, TEXT("Failed to get challenge goal list. Invalid Player Controller."));
    return;
    }

    const ULocalPlayer* LocalPlayer = GetOwningPlayer()->GetLocalPlayer();
    if (!LocalPlayer)
    {
    UE_LOG_CHALLENGE_ESSENTIALS(Warning, TEXT("Failed to get challenge goal list. Invalid Local Player."));
    return;
    }

    const FUniqueNetIdPtr UserId = LocalPlayer->GetPreferredUniqueNetId().GetUniqueNetId();
    if (!UserId)
    {
    UE_LOG_CHALLENGE_ESSENTIALS(Warning, TEXT("Failed to get challenge goal list. Invalid User ID."));
    return;
    }

    Ws_Challenge->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Loading);
    Lv_Challenge->ClearListItems();

    // Get challenge by period.
    ChallengeEssentialsSubsystem->GetChallengeByPeriod(
    Period,
    FOnGetChallengeCodeComplete::CreateWeakLambda(this, [this, UserId](bool bWasSuccessful, const FString& ErrorMessage, const FAccelByteModelsChallenge& Challenge)
    {
    if (!bWasSuccessful)
    {
    Ws_Challenge->ErrorMessage = FText::FromString(ErrorMessage);
    Ws_Challenge->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
    return;
    }

    // Get and display challenge goal list.
    ChallengeEssentialsSubsystem->GetChallengeGoalList(
    UserId,
    Challenge,
    FOnGetChallengeGoalsComplete::CreateWeakLambda(this, [this]
    (bool bWasSuccessful, const FString& ErrorMessage, const TArray<UChallengeGoalData*>& Goals)
    {
    if (!bWasSuccessful)
    {
    Ws_Challenge->ErrorMessage = FText::FromString(ErrorMessage);
    Ws_Challenge->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Error);
    return;
    }

    if (Goals.IsEmpty())
    {
    Ws_Challenge->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Empty);
    return;
    }

    Lv_Challenge->SetListItems(Goals);
    Ws_Challenge->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Not_Empty);

    UpdateClaimAllButton();
    }));
    }));
    }
  2. 次に、OnClaimAllButtonClicked() 関数を以下のコードに置き換えて、すべての報酬 ID を収集し、それらをすべて受け取るリクエストを送信します。

    void UChallengeWidget_Starter::OnClaimAllButtonClicked()
    {
    Btn_ClaimAll->SetIsEnabled(false);
    if (AllClaimableRewardIds.IsEmpty())
    {
    return;
    }

    GetPromptSubystem()->ShowLoading(CLAIMING_ALL_CHALLENGE_REWARDS_MESSAGE);

    ChallengeEssentialsSubsystem->ClaimChallengeGoalRewards(
    AllClaimableRewardIds,
    FOnClaimChallengeGoalRewardsComplete::CreateWeakLambda(this, [this](bool bWasSuccessful, const FString& ErrorMessage)
    {
    Btn_ClaimAll->SetIsEnabled(!bWasSuccessful);
    GetPromptSubystem()->HideLoading();

    // If failed, display a push notification to show the error message.
    if (!bWasSuccessful)
    {
    GetPromptSubystem()->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorMessage));
    }
    // If success, refresh the challenge list.
    else
    {
    GetChallengeGoalList();
    }
    }));
    }
  3. 次に、ChallengeWidgetEntry_Starter クラスの CPP ファイルを開き、事前定義された NativeOnListItemObjectSet() 関数内のコードを以下に置き換えます。このコードは、チャレンジゴール情報を表示してエントリウィジェットをセットアップします。

    void UChallengeWidgetEntry_Starter::NativeOnListItemObjectSet(UObject* ListItemObject)
    {
    Super::NativeOnListItemObjectSet(ListItemObject);

    GoalData = Cast<UChallengeGoalData>(ListItemObject);
    if (!GoalData)
    {
    UE_LOG_CHALLENGE_ESSENTIALS(Warning, TEXT("Failed to set challenge widget entry. Invalid data."));
    return;
    }

    const FAccelByteModelsChallengeGoal Goal = GoalData->Goal;
    const FAccelByteModelsChallengeGoalProgress Progress = GoalData->Progress;
    const bool bIsCompleted = Progress.Status == EAccelByteModelsChallengeGoalProgressStatus::COMPLETED;
    const bool bIsRewardsClaimed = Progress.ToClaimRewards.IsEmpty();

    // Display goal basic information.
    Tb_Goal->SetText(FText::FromString(Goal.Name));
    Tb_RemainingTime->SetText(FText::FromString(GoalData->GetEndTimeDuration()));
    Cb_ChallengeStatus->SetCheckedState(bIsCompleted ? ECheckBoxState::Checked : ECheckBoxState::Unchecked);

    // Display rewards
    Deb_Reward->Reset(true);
    for (const FChallengeGoalRewardData& Reward : GoalData->Rewards)
    {
    if (UChallengeGoalRewardWidgetEntry* Entry = Deb_Reward->CreateEntry<UChallengeGoalRewardWidgetEntry>())
    {
    Entry->Setup(Reward);
    }
    }

    // Display claim reward button.
    Btn_Claim->SetIsEnabled(!bIsRewardsClaimed);
    Btn_Claim->SetButtonText(bIsRewardsClaimed ? CLAIMED_CHALLENGE_REWARD_LABEL : CLAIMABLE_CHALLENGE_REWARD_LABEL);
    Ws_Progress->SetActiveWidget(bIsCompleted ? Cast<UWidget>(Btn_Claim) : Cast<UWidget>(Hb_Progress));

    /* Select the progress with the highest progress value, as Byte Wars displays only one.
    * If there is no player progress, set the default goal progress value from the requirement group.
    * Else, use the actual player progress value. */
    int32 CurrentProgress = 0, TargetProgress = 0;
    if (Progress.Status == EAccelByteModelsChallengeGoalProgressStatus::NOT_STARTED)
    {
    TArray<FAccelByteModelsChallengeGoalRequirementPredicate> Predicates{};
    Algo::ForEach(Progress.Goal.RequirementGroups, [&Predicates](const FAccelByteModelsChallengeGoalRequirement& Group){ Predicates.Append(Group.Predicates); });

    const FAccelByteModelsChallengeGoalRequirementPredicate* Requirement =
    Algo::MaxElementBy(Predicates, &FAccelByteModelsChallengeGoalRequirementPredicate::TargetValue);
    TargetProgress = Requirement ? Requirement->TargetValue : 0;
    }
    else
    {
    const FAccelByteModelsChallengeGoalProgressRequirement* Requirement =
    Algo::MaxElementBy(Progress.RequirementProgressions, &FAccelByteModelsChallengeGoalProgressRequirement::CurrentValue);
    CurrentProgress = Requirement ? Requirement->CurrentValue : 0;
    TargetProgress = Requirement ? Requirement->TargetValue : 0;
    }
    Tb_Progress->SetText(FText::FromString(FString::Printf(TEXT("%d/%d"), CurrentProgress, TargetProgress)));

    OnListItemObjectSet.Broadcast();
    }
  4. 同じファイル内で、事前定義された OnClaimButtonClicked() 関数内のコードを以下に置き換えます。このコードは、先ほど作成したサブシステムを使用してチャレンジゴールの報酬を受け取ります。

    void UChallengeWidgetEntry_Starter::OnClaimButtonClicked()
    {
    if (!GoalData || !ChallengeEssentialsSubsystem)
    {
    UE_LOG_CHALLENGE_ESSENTIALS(Warning, TEXT("Failed to claim challenge reward. Invalid data and interface."));
    return;
    }

    // Collect claimable reward IDs.
    TArray<FString> ClaimableRewardIds{};
    Algo::Transform(GoalData->Progress.ToClaimRewards, ClaimableRewardIds, [](const FAccelByteModelsChallengeClaimableUserReward Reward) { return Reward.Id; });

    // Claim rewards.
    Btn_Claim->SetIsEnabled(false);
    Btn_Claim->SetButtonText(CLAIMING_CHALLENGE_REWARD_LABEL);
    ChallengeEssentialsSubsystem->ClaimChallengeGoalRewards(
    ClaimableRewardIds,
    FOnClaimChallengeGoalRewardsComplete::CreateWeakLambda(this, [this](bool bWasSuccessful, const FString& ErrorMessage)
    {
    Btn_Claim->SetIsEnabled(!bWasSuccessful);
    Btn_Claim->SetButtonText(bWasSuccessful ? CLAIMED_CHALLENGE_REWARD_LABEL : CLAIMABLE_CHALLENGE_REWARD_LABEL);

    // If failed, display a push notification to show the error message.
    if (!bWasSuccessful)
    {
    GetPromptSubystem()->ShowMessagePopUp(ERROR_PROMPT_TEXT, FText::FromString(ErrorMessage));
    }
    // If success, clear the cached claimable rewards.
    else
    {
    GoalData->Progress.ToClaimRewards.Empty();
    }

    OnIndividualChallengeRewardsClaimed.ExecuteIfBound(bWasSuccessful, ErrorMessage);
    }));
    }

リソース