はじめに
「UE5でEpic Online Services(EOS)を使ってみる」の続きです。
ログインの実装が必要なので、未実装の方は準備編・ログイン編をご確認ください。
統計データはユーザーが行った行動の統計情報を集計して、ユーザーごとに保持できます。
また、統計データごとに実績やリーダーボードが作成できます。
今回は、SCOREが加算されていく項目を作成します。
目次
この章では、統計データ機能に必要な実装を行っていきます。
ポータルサイトにて統計データに必要な設定を行い、
必要なクラスを作成してC++を実装し、Blueprintで実行出来る状態にしてテストを行います。
1.Developer Portal
Developer Portalで値を格納するための項目を作成します。
ゲームサービス>統計データから統計を作成を開き、統計データ名をSCORE_SUM、集計の種類にSUMを指定します。
統計データ名は全て大文字にします。
EOS_OSSプラグイン上では、名称は大文字と小文字を区別しないFNameが使用されるため、大文字にする必要があるそうです。
2.クラス作成
更新・取得用のクラスを作成します。
OnlineBlueprintCallProxyBaseを親クラスに指定して、EOS_SetStatsとEOS_GetStatsをC++クラスで作成します。
3.C++
C++を以下で実装します。
EOS_DataDefinition.h(以下を追加)
USTRUCT(BlueprintType) struct FStatData { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite) FString StatName; UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 Value; };
EOS_SetStats.h
#pragma once #include "CoreMinimal.h" #include "Net/OnlineBlueprintCallProxyBase.h" #include "Interfaces/OnlineStatsInterface.h" #include "EOS_SetStats.generated.h" UCLASS() class EOS_API UEOS_SetStats : public UOnlineBlueprintCallProxyBase { GENERATED_BODY() UPROPERTY(BlueprintAssignable) FEmptyOnlineDelegate OnSuccess; UPROPERTY(BlueprintAssignable) FEmptyOnlineDelegate OnFailure; UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"), Category = "EOS") static UEOS_SetStats* SetStats(UObject* WorldContextObject, FString StatName, int32 StatValue); virtual void Activate() override; private: void OnSetStatsComplete(const FOnlineError& Result); private: UWorld* World; TWeakObjectPtr<UObject> WorldContextObject; FString StatName; int32 StatValue; };
EOS_SetStats.cpp
#include "OnlineSubsystemUtils.h" #include "EOS_SetStats.h" UEOS_SetStats* UEOS_SetStats::SetStats(UObject* WorldContextObject,FString StatName, int32 StatValue) { UEOS_SetStats* Stats = NewObject<UEOS_SetStats>(); Stats->WorldContextObject = WorldContextObject; Stats->StatName = StatName; Stats->StatValue = StatValue; return Stats; } void UEOS_SetStats::Activate() { World = GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull); if (!World) { UE_LOG(LogTemp, Error, TEXT("UpdateStat:Worldの取得に失敗")); OnFailure.Broadcast(); return; } IOnlineSubsystem* SubsystemRef = Online::GetSubsystem(World); IOnlineIdentityPtr IdentityPointerRef = SubsystemRef->GetIdentityInterface(); IOnlineStatsPtr StatsPointerRef = SubsystemRef->GetStatsInterface(); FOnlineStatsUserUpdatedStats StatVar = FOnlineStatsUserUpdatedStats(IdentityPointerRef->GetUniquePlayerId(0).ToSharedRef()); StatVar.Stats.Add(StatName, FOnlineStatUpdate(StatValue, FOnlineStatUpdate::EOnlineStatModificationType::Unknown)); TArray<FOnlineStatsUserUpdatedStats> StatArray; StatArray.Add(StatVar); if (StatsPointerRef) { StatsPointerRef->UpdateStats( IdentityPointerRef->GetUniquePlayerId(0).ToSharedRef(), StatArray, FOnlineStatsUpdateStatsComplete::CreateUObject(this, &UEOS_SetStats::OnSetStatsComplete) ); return; } OnFailure.Broadcast(); } void UEOS_SetStats::OnSetStatsComplete(const FOnlineError& Result) { if (Result == FOnlineError::Success()) { UE_LOG(LogTemp, Warning, TEXT("Stat更新成功")); OnSuccess.Broadcast(); } else { UE_LOG(LogTemp, Error, TEXT("Stat更新失敗")); OnFailure.Broadcast(); } }
UEOS_GetStats.h
#pragma once #include "CoreMinimal.h" #include "Net/OnlineBlueprintCallProxyBase.h" #include "Interfaces/OnlineStatsInterface.h" #include "EOS_DataDefinition.h" #include "EOS_GetStats.generated.h" DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnStatsRetrieved, const TArray<FStatData>&, Stats); UCLASS() class EOS_API UEOS_GetStats : public UOnlineBlueprintCallProxyBase { GENERATED_BODY() UPROPERTY(BlueprintAssignable) FOnStatsRetrieved OnSuccess; UPROPERTY(BlueprintAssignable) FOnStatsRetrieved OnFailure; UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"), Category = "EOS") static UEOS_GetStats* GetStats(UObject* WorldContextObject, TArray<FString> StatNames); virtual void Activate() override; private: void OnGetStatsComplete(const FOnlineError& ResultState, const TArray<TSharedRef<const FOnlineStatsUserStats>>& UserStats); private: UWorld* World; TWeakObjectPtr<UObject> WorldContextObject; TArray<FString> StatNames; TArray<FStatData> Stats; };
UEOS_GetStats.cpp
#include "OnlineSubsystemUtils.h" #include "EOS_GetStats.h" UEOS_GetStats* UEOS_GetStats::GetStats(UObject* WorldContextObject,TArray<FString> StatNames) { UEOS_GetStats* Stats = NewObject<UEOS_GetStats>(); Stats->WorldContextObject = WorldContextObject; Stats->StatNames = StatNames; return Stats; } void UEOS_GetStats::Activate() { Stats.Empty(); World = GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull); if (!World) { UE_LOG(LogTemp, Error, TEXT("GetStat:Worldの取得に失敗")); OnFailure.Broadcast(Stats); return; } IOnlineSubsystem* SubsystemRef = Online::GetSubsystem(World); IOnlineIdentityPtr IdentityPointerRef = SubsystemRef->GetIdentityInterface(); IOnlineStatsPtr StatsPointerRef = SubsystemRef->GetStatsInterface(); TArray<TSharedRef<const FUniqueNetId>> Users; Users.Add(IdentityPointerRef->GetUniquePlayerId(0).ToSharedRef()); if (StatsPointerRef) { StatsPointerRef->QueryStats( IdentityPointerRef->GetUniquePlayerId(0).ToSharedRef(), Users, StatNames, FOnlineStatsQueryUsersStatsComplete::CreateUObject(this, &UEOS_GetStats::OnGetStatsComplete) ); return; } OnFailure.Broadcast(Stats); } void UEOS_GetStats::OnGetStatsComplete(const FOnlineError& ResultState, const TArray<TSharedRef<const FOnlineStatsUserStats>>& UserStats) { if (ResultState.WasSuccessful()) { Stats.Empty(); for (auto StatsVar : UserStats) { for (auto StoredValueRef : StatsVar->Stats) { FString Keyname = StoredValueRef.Key; int32 Value; StoredValueRef.Value.GetValue(Value); FStatData StatData; StatData.StatName = Keyname; StatData.Value = Value; Stats.Add(StatData); UE_LOG(LogTemp, Warning, TEXT("Stats名:%s 値:%s"), *Keyname, *FString::FromInt(Value)); } } OnSuccess.Broadcast(Stats); } else { UE_LOG(LogTemp, Error, TEXT("Stats取得失敗 - %s"), *ResultState.ToLogString()); OnFailure.Broadcast(Stats); } }
4.Blueprint
Blueprintを以下で実装します。
EOS_Gameinstanceに各カスタムイベントを用意し、以下で実装します。
SetStats:指定された統計データに入力された値を送信します。
GetStats:指定された統計データを取得します。複数の統計データを一度に取得することができます。
5.テスト
5-1.更新
ログイン後、SetStatsを実行します。
5-2.取得
GetStatsを実行します。
5-3.再度更新
SetStatsとGetStatsを交互に実行します。
値が増えているならば、統計データの更新と取得が問題なく行われていることが確認できます。
5-4.Developer Portal
ゲームサービス>統計データから「プレーヤーの統計データをリセットする」を開き、プレーヤー検索画面でユーザーを検索します。
プレーヤーが保持している値を確認でき、値のリセットが行えます。
プレーヤーカウントIDはDevAuthToolから確認できます。
おわり
お疲れ様です。
以上で統計データ編は終わりです、次はリーダーボード編です。