i-school - 経験値用テーブルデータからレベルを算出する方法
 以下のような Json 形式のテーブルデータ、あるいはスクリプタブル・オブジェクトなどのデータベースがあるとしたとき、
現在の経験値の値とレベルアップのための累積経験値を比較して、現在のレベルを算出する方法の実装例です。

[
  { "level": 1, "acc_exp": 0 },
  { "level": 2, "acc_exp": 300 },
  { "level": 3, "acc_exp": 1500 },
  { "level": 4, "acc_exp": 4200 },
  { "level": 5, "acc_exp": 9000 },
  { "level": 6, "acc_exp": 16500 },
  { "level": 7, "acc_exp": 27300 },
  { "level": 8, "acc_exp": 42000 },
  { "level": 9, "acc_exp": 61200 },
  { "level": 10, "acc_exp": 85500 },
  { "level": 11, "acc_exp": 115500 },
  { "level": 12, "acc_exp": 151800 },
  { "level": 13, "acc_exp": 195000 },
  { "level": 14, "acc_exp": 245700 },
  { "level": 15, "acc_exp": 304500 },
  { "level": 16, "acc_exp": 372000 },
  { "level": 17, "acc_exp": 448800 },
  { "level": 18, "acc_exp": 535500 },
  { "level": 19, "acc_exp": 632700 },
  { "level": 20, "acc_exp": 741000 }
]

 例えば、現在の経験値 が 500 である場合、累積経験値と照合し、Level が 3 であることを算出する方法になります。



Json ファイルを登録する方法


 いくつか方法がありますので、自分のプロジェクトに合わせて対応してください。

 PlayFab のタイトルデータなどのサーバー上に配置する
 Json ファイルを Unity へインポートしておいて取得する
 スクリプタブル・オブジェクトに取り込む

 ここでは PlayFab のタイトルデータに配置する方法で進めていきます。



 PlayFab のゲームマネージャー画面のダッシュボードより、コンテンツ → タイトルデータを選択します。








 コンテンツ内の新しいタイトルデータを選択します。
すでにタイトルデータが存在している場合には Edit を押します。









 Key の部分にある追加を選択し、Key と Value を登録します。




 Key にはゲーム内に作成するクラス名を登録し、Value には Json の情報を貼り付けます。
ここでは Key を PlayerLevelMasterData に設定しています。
後程、同名のクラスを作成します。








 Value 登録後は Json ボタンを押すことで修正できます。






PlayerLevelMasterData クラスの作成


 タイトルデータの Key と同名のクラスを作成します。
こちらに Json 内の1つ分データが入ります。

 そのため、今回のように複数のデータが配列で管理されている Json の場合には
List などで PlayerLevelMasterData を管理することで、すべての Json の情報を管理します。

// タイトルデータのクラス
[Serializable]
public class PlayerLevelMasterData
{
    public int level;
    public int acc_exp;
}


PlayerLevelManager クラスの作成


 PlayFab へのログインや、タイトルデータから情報を取得する方法は割愛しています。
他の記事を参考にしてください。

 タイトルデータの情報が PlayerLevelMasterData 変数に取得できている前提で処理を作成しています。


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public static class PlayerLevelManager
{
    public List<PlayerLevelMasterData> PlayerLevelMasterData = new();  // PlayFab のタイトルデータから取得した Json の情報が代入されている


    // プレイヤーのexpを受け取って、対応するレベルを返すメソッド
  public static int GetLevelFromExp(int exp)
  {
      // PlayerLevelMasterDataが空の場合の処理
      if (PlayerLevelMasterData.Count == 0)
      {
          // エラーまたはデフォルトのレベルを返すなど、適切な処理を行います。
          return 0; // 例えば0をデフォルトのレベルとして返すことにします。
      }

      int resultLevel = 0; // デフォルトのレベル

      // PlayerLevelMasterDataを順番に確認
      foreach (var levelData in PlayerLevelMasterData)
      {
          // 現在のデータのacc_expがexp以下であるか確認
          if (exp >= levelData.acc_exp)
          {
              // 現在のデータのlevelを結果として保存
              resultLevel = levelData.level;
          }
          else
          {
              // expがデータよりも小さくなった時点でループを終了
              break;
          }
      }

      return resultLevel; // 最終的な結果のレベルを返す
  }
}

 static クラスですので、ゲーム実行と同時にインスタンスが生成されます。

 もしも List の内部データをインスペクターより確認したい場合には、
static キーワードを削除し、static クラスではなく、通常のクラスとして MonoBehaviour クラスを継承して
ゲームオブジェクトにアタッチして利用してください。


サンプルクラス


 こちらのクラスを作成してゲームオブジェクトにアタッチし、ゲームを実行して処理を確認します。

 ボタンを押す度にメソッドを実行し、現在の経験値を元にレベルを算出します。
 
 実際には経験値加算のタイミングでメソッドを実行するとよいでしょう。

using UnityEngine;

public class Player : MonoBehaviour {

    public int playerLevel;
    public int playerExp;


    void Update() {
        if(Input,GetKeyDown(KeyCode.Space)){
            UpdateLevel();
        }
    }

    void UpdateLevel()
    {
        // プレイヤーのexpからレベルを取得
        playerLevel = PlayerLevelManager.GetLevelFromExp(playerExp);

        // 取得したレベルを表示
        Debug.Log($"Player Exp: {playerExp}, Player Level: {playerLevel}");
    }
}


<LINQ を利用したケース>


 PlayerLevelManager クラス内の GetLevelFromExp メソッド内部の処理は LINQ を活用してリファクタリング可能です。


    public int GetLevelFromExp(int exp)
    {
        var levelData = PcharLevelMasterData.LastOrDefault(data => exp >= data.acc_exp);

        return levelData != null ? levelData.level : PcharLevelMasterData.First().level;
    }

 処理を作成して正常に動作することを確認できたら、処理を見直したり、構造を確認した上でリファクタリングを行う癖をつけましょう。