Challenges #

Challenges enable social and competitive experiences by allowing players to compete in time-bound events with friends. Learn more in the Challenges concept guide.

Overview #

Challenges provide time-bound competitive experiences where players can:

  • Compete against friends or other players
  • Track progress through leaderboards
  • Earn rewards for participation and performance

Prerequisites #

  • Unreal project set up with Hiro SDK
  • Nakama System integrated

Managing Challenges #

Creating a Challenge #

Create new challenges with custom parameters:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
FHiroChallengeCreateRequest CreateRequest;
CreateRequest.TemplateId = TEXT("daily_race");
CreateRequest.Name = TEXT("Daily Race Challenge");
CreateRequest.Description = TEXT("Compete for top daily times");
CreateRequest.Invitees = { TEXT("player2"), TEXT("player3") };
CreateRequest.Open = true;
CreateRequest.MaxScores = 3;
CreateRequest.StartDelaySec = 0; // Start immediately
CreateRequest.DurationSec = 86400; // 24 hours
CreateRequest.MaxParticipants = 10;
CreateRequest.Category = TEXT("racing");

FHiroOnChallengeCreate OnChallengeCreate;
OnChallengeCreate.AddDynamic(this, &AMyActor::OnChallengeCreate);
FOnError OnError;

HiroClient->ChallengeCreate(Session, CreateRequest, OnChallengeCreate, OnError);

void AMyActor::OnChallengeCreate(const FHiroChallenge& Challenge)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *Challenge.ToJson());
}

Parameters:

  • Open: Allow any player to join without an invitation
  • MaxScores: Max submissions per player
  • DurationSec: 0 = unlimited duration

Listing Challenges #

Get active challenges with optional filtering:

1
2
3
4
5
6
7
8
9
FHiroChallengeListRequest Request;
Request.Categories.Add(TEXT("racing"));
Request.WithScores = true;

FHiroOnChallengesList OnChallengesList;
OnChallengesList.AddDynamic(this, &AMyActor::OnChallengesList);
FOnError OnError;

HiroClient->ChallengesList(Session, Request, OnChallengesList, OnError);

Searching Challenges #

Find public challenges by name/category:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FHiroChallengeSearchRequest SearchRequest;
SearchRequest.Name = TEXT("weekly");
SearchRequest.Category = TEXT("racing");
SearchRequest.Limit = 5;

FHiroOnChallengesSearch OnChallengesSearch;
OnChallengesSearch.AddDynamic(this, &AMyActor::OnChallengesSearch);
FOnError OnError;

HiroClient->ChallengesSearch(Session, SearchRequest, OnChallengesSearch, OnError);

Inviting Players #

Add participants to existing challenges:

1
2
3
4
5
6
7
8
9
FHiroChallengeInviteRequest InviteRequest;
InviteRequest.ChallengeId = TEXT("CHALLENGE_123");
InviteRequest.Invitees = { TEXT("player4") };

FHiroOnChallengeInvite OnChallengeInvite;
OnChallengeInvite.AddDynamic(this, &AMyActor::OnChallengeInvite);
FOnError OnError;

HiroClient->ChallengeInvite(Session, InviteRequest, OnChallengeInvite, OnError);

Tracking Progress #

Submitting Scores #

Update player standings in a challenge:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
FHiroChallengeSubmitScoreRequest SubmitScoreRequest;
SubmitScoreRequest.ChallengeId = TEXT("CHALLENGE_123");
SubmitScoreRequest.Score = 1500;
SubmitScoreRequest.Subscore = 0;
SubmitScoreRequest.Metadata = TEXT("{\"lap_times\":[120]}");

FHiroOnChallengeSubmitScore OnSubmitScore;
OnSubmitScore.AddDynamic(this, &AMyActor::OnSubmitScore);
FOnError OnError;

HiroClient->ChallengeSubmitScore(Session, SubmitScoreRequest, OnSubmitScore, OnError);

Joining/Leaving #

Manage player participation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// Join an open challenge
FHiroChallengeJoinRequest JoinRequest;
JoinRequest.ChallengeId = TEXT("CHALLENGE_456");

FHiroOnChallengeJoin OnChallengeJoin;
OnChallengeJoin.AddDynamic(this, &AMyActor::OnChallengeJoin);
FOnError OnError;

HiroClient->ChallengeJoin(Session, JoinRequest, OnChallengeJoin, OnError);

// Leave a challenge
FHiroChallengeLeaveRequest LeaveRequest;
LeaveRequest.ChallengeId = TEXT("CHALLENGE_456");

FHiroOnChallengeLeave OnChallengeLeave;
OnChallengeLeave.AddDynamic(this, &AMyActor::OnChallengeLeave);

HiroClient->ChallengeLeave(Session, LeaveRequest, OnChallengeLeave, OnError);

Rewards #

Claiming Rewards #

Claim earned rewards after challenge completion:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
FHiroChallengeClaimRequest ClaimRequest;
ClaimRequest.ChallengeId = TEXT("CHALLENGE_123");

FHiroOnChallengeClaim OnChallengeClaim;
OnChallengeClaim.AddDynamic(this, &AMyActor::OnChallengeClaim);
FOnError OnError;

HiroClient->ChallengeClaim(Session, ClaimRequest, OnChallengeClaim, OnError);

// Refresh the economy system to see new rewards
HiroClient->EconomyRefresh(Session, OnEconomyRefresh, OnError);