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

SDK を使用して統計データを設定しクエリを実行する - 統計データを追跡し表示する - (Unity モジュール)

Last updated on February 4, 2026

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

ラッパーを開く

このチュートリアルでは、AccelByte Gaming Services (AGS) Software Development Kit (SDK) を使用して AGS 統計データを実装する方法を学びます。Byte Wars には、StatsEssentialsWrapper クラスで定義されたゲームインスタンスラッパーがあります。このラッパーは、AGS 統計データ値を操作するためのラッパーとして機能します。

このチュートリアルでは、StatsEssentialsWrapper クラスのスターターバージョンである StatsEssentialsWrapper_Starter ラッパーを使用して統計データ値を操作します。

スターターパックの内容

このチュートリアルを進めるには、StatsEssentialsWrapper_Starter というスターターラッパークラスを使用します。このラッパーは以下のファイルで定義されています:

  • C# ファイル: Assets/Resources/Modules/Storage/StatsEssentials/Scripts/StatsEssentialsWrapper_Starter.cs

また、以下のファイルにヘルパー関数と変数を含むモデルクラスも定義されています:

  • C# ファイル: Assets/Resources/Modules/Storage/StatsEssentials/Scripts/StatsEssentialsModels.cs

StatsEssentialsWrapper_Starter クラスには、以下のいくつかの事前定義されたコンポーネントがあります。

  • AGS SDK インターフェースを参照するためのヘルパー変数。これらの変数は、ラッパーが初期化されるときに割り当てられます。

    private Statistic statistic;
    private ServerStatistic serverStatistic;

    void Start()
    {
    statistic = AccelByteSDK.GetClientRegistry().GetApi().GetStatistic();
    #if UNITY_SERVER
    serverStatistic = AccelByteSDK.GetServerRegistry().GetApi().GetStatistic();
    #endif
    }

StatsEssentialsModels クラスには、以下のヘルパーがあります。

  • Byte Wars でサポートされている各ゲームモードの統計データコードを返すヘルパークラス。これにより、統計データ値を更新する際にハードコードする必要がなくなり、アクセスが簡素化されます。これらの統計データコードは、前のセクションで Admin Portal で設定したものと同じです。

    public class GameStatsData
    {
    public struct GameStatsModel
    {
    public string StatCode;
    public string DisplayName;

    public GameStatsModel(string codeName, string displayName)
    {
    StatCode = codeName;
    DisplayName = displayName;
    }
    }

    public InGameMode GameMode { get; private set; }
    public GameStatsModel HighestScoreStats { get; private set; }
    public GameStatsModel TotalScoreStats { get; private set; }
    public GameStatsModel MatchesPlayedStats { get; private set; }
    public GameStatsModel MatchesWonStats { get; private set; }
    public GameStatsModel KillCountStats { get; private set; }
    public GameStatsModel DeathStats { get; private set; }
    public ReadOnlyCollection<string> StatsCodes { get; }
    public ReadOnlyCollection<GameStatsModel> StatsModels { get; }

    public GameStatsData(InGameMode gameMode)
    {
    GameMode = gameMode;

    string gameModeSuffx = "unknown";
    switch(GameMode)
    {
    case InGameMode.SinglePlayer:
    case InGameMode.LocalElimination:
    case InGameMode.LocalTeamDeathmatch:
    gameModeSuffx = "singleplayer";
    break;
    case InGameMode.MatchmakingElimination:
    case InGameMode.CreateMatchElimination:
    gameModeSuffx = "elimination";
    break;
    case InGameMode.MatchmakingTeamDeathmatch:
    case InGameMode.CreateMatchTeamDeathmatch:
    gameModeSuffx = "teamdeathmatch";
    break;
    }

    HighestScoreStats = new($"unity-highestscore-{gameModeSuffx}", "Highest Score");
    TotalScoreStats = new($"unity-totalscore-{gameModeSuffx}", "Total Score");
    MatchesPlayedStats = new($"unity-matchesplayed-{gameModeSuffx}", "Matches Played");
    MatchesWonStats = new($"unity-matcheswon-{gameModeSuffx}", "Matches Won");
    KillCountStats = new($"unity-killcount-{gameModeSuffx}", "Kill Count");
    DeathStats = new($"unity-deaths-{gameModeSuffx}", "Deaths");

    StatsModels = new ReadOnlyCollection<GameStatsModel>(new[]
    {
    HighestScoreStats,
    TotalScoreStats,
    MatchesPlayedStats,
    MatchesWonStats,
    KillCountStats,
    DeathStats
    });

    StatsCodes = new ReadOnlyCollection<string>(StatsModels.Select(model => model.StatCode).ToList());
    }
    }
  • 各ゲームモードの統計データコードを格納するヘルパー変数。

    public readonly static GameStatsData SinglePlayerStatsData = new(InGameMode.SinglePlayer);
    public readonly static GameStatsData EliminationStatsData = new(InGameMode.CreateMatchElimination);
    public readonly static GameStatsData TeamDeathmatchStatsData = new(InGameMode.CreateMatchTeamDeathmatch);
  • ゲームモードに基づいて統計データコードを返すヘルパー関数。

    public static GameStatsData GetGameStatsDataByGameMode(InGameMode gameMode)
    {
    switch (gameMode)
    {
    case InGameMode.SinglePlayer:
    case InGameMode.LocalElimination:
    case InGameMode.LocalTeamDeathmatch:
    return SinglePlayerStatsData;
    case InGameMode.MatchmakingElimination:
    case InGameMode.CreateMatchElimination:
    return EliminationStatsData;
    case InGameMode.MatchmakingTeamDeathmatch:
    case InGameMode.CreateMatchTeamDeathmatch:
    return TeamDeathmatchStatsData;
    default:
    return null;
    }
    }

ゲームクライアント用の統計データを実装する

このセクションでは、AGS SDK を使用してゲームクライアント用の統計データ機能を実装する方法を説明します。

  1. StatsEssentialsWrapper_Starter クラスを開きます。まず、後で UI に表示するためのユーザー統計データを取得する以下の新しい関数を作成します。この関数は統計データコードのリストを必要とし、リクエストが完了するとコールバック関数を呼び出します。

    public void GetUserStatsFromClient(string[] statCodes, string[] tags, ResultCallback<PagedStatItems> resultCallback)
    {
    statistic.GetUserStatItems(
    statCodes,
    tags,
    result => OnGetUserStatsFromClientCompleted(result, resultCallback)
    );
    }
  2. 次に、上記の関数のコールバック関数を作成します。ここでは、統計データ値の取得に成功したかどうかのリクエストステータスを単純にログに記録します。

    private void OnGetUserStatsFromClientCompleted(Result<PagedStatItems> result, ResultCallback<PagedStatItems> customCallback = null)
    {
    if (!result.IsError)
    {
    BytewarsLogger.Log("Get User's Stat Items from Client successful.");
    }
    else
    {
    BytewarsLogger.LogWarning($"Get User's Stat Items from Client failed. Message: {result.Error.Message}");
    }

    customCallback?.Invoke(result);
    }
  3. 次に、統計データ値を更新するための以下の新しい関数を作成します。これは、Admin Portal で以前に設定したシングルプレイヤーモードの最高スコアなど、ゲームクライアントによって更新されることを意図した統計データ値を更新するために使用します。この関数は、更新する統計データコードと値のリストを必要とし、リクエストが完了するとコールバック関数を呼び出します。

    public void UpdateUserStatsFromClient(List<StatItemUpdate> statItems, ResultCallback<StatItemOperationResult[]> resultCallback = null)
    {
    statistic.UpdateUserStatItems(
    statItems.ToArray(),
    result => OnUpdateUserStatsFromClientCompleted(result, resultCallback)
    );
    }
  4. 次に、上記の関数のコールバック関数を作成します。ここでは、統計データ値の更新に成功したかどうかのリクエストステータスを単純にログに記録します。

    private void OnUpdateUserStatsFromClientCompleted(Result<StatItemOperationResult[]> result, ResultCallback<StatItemOperationResult[]> customCallback = null)
    {
    if (!result.IsError)
    {
    BytewarsLogger.Log("Update User's Stat Items from Client successful.");
    }
    else
    {
    BytewarsLogger.LogWarning($"Update User's Stat Items from Client failed. Message: {result.Error.Message}");
    }

    customCallback?.Invoke(result);
    }

ゲームサーバー用の統計データを実装する

このセクションでは、AGS SDK を使用してゲームサーバー用の統計データ機能を実装する方法を説明します。

  1. StatsEssentialsWrapper_Starter クラスを開きます。Admin Portal で以前に設定したエリミネーションモードとチームデスマッチモードの最高スコアなど、ゲームサーバーによって更新されることを意図した統計データ値を更新するための以下の新しい関数を作成します。この関数は、更新する統計データコードと値のリストを必要とし、リクエストが完了するとコールバック関数を呼び出します。

    public void UpdateManyUserStatsFromServer(List<UserStatItemUpdate> statItems, ResultCallback<StatItemOperationResult[]> resultCallback)
    {
    serverStatistic.UpdateManyUsersStatItems(
    statItems.ToArray(),
    result => OnUpdateManyUserStatsFromServerCompleted(result, resultCallback));
    }
  2. 次に、上記の関数のコールバック関数を作成します。ここでは、統計データ値の更新に成功したかどうかのリクエストステータスを単純にログに記録します。

    private void OnUpdateManyUserStatsFromServerCompleted(Result<StatItemOperationResult[]> result, ResultCallback<StatItemOperationResult[]> customCallback = null)
    {
    if (!result.IsError)
    {
    BytewarsLogger.Log("Update User's Stat Items from Server successful.");
    }
    else
    {
    BytewarsLogger.LogWarning($"Update User's Stat Items from Server failed. Message: {result.Error.Message}");
    }

    customCallback?.Invoke(result);
    }

統計データ値を更新するための実装

Byte Wars では、ゲーム終了時にプレイヤーの統計データ値を更新するように設計されています。これらの値は、ゲームモードと統計データタイプ(例: ゲームクライアント用、またはゲームサーバー用)に基づいて更新する必要があります。このセクションでは、以前に作成した関数を使用して統計データ値を更新する方法を説明します。

  1. StatsEssentialsWrapper_Starter クラスを開き、以下の関数を作成します。この関数は、ゲーム内の接続されているすべてのプレイヤーの統計データを更新するためのラッパー関数です。まず、現在プレイされているゲームモードを判断します。次に、接続されているプレイヤーをループして、そのデータを統計データアイテムに格納します。最後に、この関数はすべての統計データアイテムを収集し、ゲームモードに基づいて UpdateUserStatsFromClient() または UpdateManyUserStatsFromServer() のいずれかを呼び出します。

    備考

    以下の関数は、Byte Wars で利用可能なすべての統計データを変更する方法を示しています。ただし、このモジュールでは、プレイヤーの最高スコアの統計データのみを設定します。他の統計データ値は更新されません。

    private void UpdateConnectedPlayersStatsOnGameEnds(GameManager.GameOverReason reason)
    {
    if (reason != GameManager.GameOverReason.MatchEnded)
    {
    return;
    }

    GameModeEnum gameMode = GameManager.Instance.GameMode;
    InGameMode inGameMode = GameManager.Instance.InGameMode;
    StatsEssentialsModels.GameStatsData gameStatsData = StatsEssentialsModels.GetGameStatsDataByGameMode(inGameMode);
    List<PlayerState> playerStates = GameManager.Instance.ConnectedPlayerStates.Values.ToList();

    // Store statistics to update.
    List<UserStatItemUpdate> statItems = new();
    Dictionary<int, (bool isWinner, int score, int kills, int deaths)> teamStats = new();
    GameManager.Instance.GetWinner(out TeamState winnerTeam, out PlayerState winnerPlayer);
    foreach (PlayerState playerState in playerStates)
    {
    if (!teamStats.ContainsKey(playerState.TeamIndex))
    {
    List<PlayerState> teamPlayers = playerStates.Where(p => p.TeamIndex == playerState.TeamIndex).ToList();
    teamStats.Add(playerState.TeamIndex, new()
    {
    isWinner = winnerTeam != null ? playerState.TeamIndex == winnerTeam.teamIndex : false,
    score = (int)teamPlayers.Sum(p => p.Score),
    kills = teamPlayers.Sum(p => p.KillCount),
    deaths = (GameData.GameModeSo.PlayerStartLives * teamPlayers.Count) - teamPlayers.Sum(p => p.Lives)
    });
    }

    (bool isWinner, int score, int kills, int deaths) = teamStats[playerState.TeamIndex];

    // Highest score statistic
    statItems.Add(new()
    {
    updateStrategy = StatisticUpdateStrategy.MAX,
    statCode = gameStatsData.HighestScoreStats.StatCode,
    userId = playerState.PlayerId,
    value = score
    });

    // Total score statistic
    statItems.Add(new()
    {
    updateStrategy = StatisticUpdateStrategy.INCREMENT,
    statCode = gameStatsData.TotalScoreStats.StatCode,
    userId = playerState.PlayerId,
    value = score
    });

    // Matches played statistic
    statItems.Add(new()
    {
    updateStrategy = StatisticUpdateStrategy.INCREMENT,
    statCode = gameStatsData.MatchesPlayedStats.StatCode,
    userId = playerState.PlayerId,
    value = 1
    });

    // Matches won statistic
    statItems.Add(new()
    {
    updateStrategy = StatisticUpdateStrategy.INCREMENT,
    statCode = gameStatsData.MatchesWonStats.StatCode,
    userId = playerState.PlayerId,
    value = isWinner ? 1 : 0
    });

    // Kill count statistic
    statItems.Add(new()
    {
    updateStrategy = StatisticUpdateStrategy.INCREMENT,
    statCode = gameStatsData.KillCountStats.StatCode,
    userId = playerState.PlayerId,
    value = kills
    });

    // Death statistic
    statItems.Add(new()
    {
    updateStrategy = StatisticUpdateStrategy.INCREMENT,
    statCode = gameStatsData.DeathStats.StatCode,
    userId = playerState.PlayerId,
    value = deaths
    });
    }

    #if UNITY_SERVER
    BytewarsLogger.Log($"[Server] Update the stats of connected players when the game ended. Game mode: {gameMode}. In game mode: {inGameMode}");
    UpdateManyUserStatsFromServer(statItems, (Result<StatItemOperationResult[]> result) =>
    {
    if (!result.IsError)
    {
    BytewarsLogger.Log("[Server] Successfully updated the stats of connected players when the game ended.");
    }
    else
    {
    BytewarsLogger.LogWarning($"[Server] Failed to update the stats of connected players when the game ended. Error: {result.Error.Message}");
    }
    });
    #else
    BytewarsLogger.Log($"[Client] Update the stats of local connected players when the game ended. Game mode: {gameMode}. In game mode: {inGameMode}");

    /* Local gameplay only has one valid account, which is the player who logged in to the game.
    * Thus, we can only update the stats based on that player's user ID. */
    List<StatItemUpdate> localPlayerStatItems = statItems
    .Where(x => x.userId == GameData.CachedPlayerState.PlayerId)
    .Select(x => new StatItemUpdate
    {
    updateStrategy = x.updateStrategy,
    value = x.value,
    statCode = x.statCode,
    additionalData = x.additionalData
    }).ToList();

    UpdateUserStatsFromClient(localPlayerStatItems, (Result<StatItemOperationResult[]> result) =>
    {
    if (!result.IsError)
    {
    BytewarsLogger.Log("[Client] Successfully updated the stats of connected players when the game ended.");
    }
    else
    {
    BytewarsLogger.LogWarning($"[Client] Failed to update the stats of connected players when the game ended. Error: {result.Error.Message}");
    }
    });
    #endif
    }
  2. 最後に、Start() 関数で、上記の関数を以下のイベントにバインドして、ゲーム終了時に呼び出されるようにします。

    void Start()
    {
    statistic = AccelByteSDK.GetClientRegistry().GetApi().GetStatistic();
    #if UNITY_SERVER
    serverStatistic = AccelByteSDK.GetServerRegistry().GetApi().GetStatistic();
    #endif

    GameManager.OnGameEnded += UpdateConnectedPlayersStatsOnGameEnds;
    }

リソース