レベルシステム、RPG作っていれば必ず書くと言っていい処理ですが、自分流の書き方を残しておきます。
累計経験値と累計経験値に応じたレベルのテーブルがあれば、そこから現在Lvと次のLvまでの残り経験値を算出できます。
しかし、Lvを取得する度に都度計算していては流石に重たいので、累計経験値が加算される度に現Lvと残り経験値を更新するようにします。
累計経験値に応じたレベルのテーブルを関数の引数にとって外部から参照してますが、これはレベルテーブルは固有な値としてstatic readonly
で修飾して使うことが多いためです。
あるいは、UnityならScriptableObjectから参照する場合もあるでしょう。
いずれにせよ外部またはサブクラス上のstaticな値を汎用的に参照させたいので関数の引数に含めました。
ExpLevelClass.cs
using System.Linq;
using UnityEngine;
[System.Serializable]
public class ExpLevelClass
{
[SerializeField] int _exp;
[SerializeField] int _remainExp;
[SerializeField] int _minLevel;
[SerializeField] int _level = 1;
public int Exp => _exp;
public int RemainExp => _remainExp;
public int MinLevel => _minLevel;
public int Level => _level;
// Expを加算してLvを初期化する
public void AddExp(int exp, int[] expArray)
{
//カンストを考慮して加算
_exp = Mathf.Clamp(_exp + exp, 0, expArray[expArray.Length - 1]);
// 値の更新
UpdateLevel(expArray);
UpdateRemainExp(expArray);
}
void UpdateLevel(int[] expArray)
{
// 現Exp以下の値の中で最大の値のインデックスを取得
var maxIdx = expArray.Where(x => x <= _exp).Select((val, idx) => new {V = val, I = idx})
.Aggregate((max, working) => (max.V > working.V) ? max : working).I;
_level = maxIdx + 1;
}
void UpdateRemainExp(int[] expArray)
{
// 現Expより大きい値の中で最小の値のインデックスを取得
var minIdx = expArray.Where(x => x > _exp).Select((val, idx) => new {V = val, I = idx})
.Aggregate((min, working) => (min.V < working.V) ? min : working).I;
_remainExp = expArray[minIdx] - _exp;
}
}
Player.cs
[System.Serializable]
public class Player
{
public string Name = "主人公";
public ExpLevelClass ExpLevel = new ExpLevelClass();
static readonly int[] TOTAL_EXP_ARRAY = {0,100,300,600,1000};
// 経験値獲得処理
public void AddExp(int exp)
{
ExpLevel.AddExp(exp, TOTAL_EXP_ARRAY);
}
}
###おまけ
関数でLevelとRemainExpの計算結果を返す
ExpLevelClass.cs
using System.Linq;
using UnityEngine;
[System.Serializable]
public class ExpLevelClass
{
[SerializeField] int _exp;
[SerializeField] int _remainExp;
[SerializeField] int _minLevel;
[SerializeField] int _level = 1;
public int Exp => _exp;
public int RemainExp => _remainExp;
public int MinLevel => _minLevel;
public int Level => _level;
// Expを加算してLvを初期化する
public (int afterLevel, int remainExp) AddExp(int exp, int[] expArray)
{
//カンストを考慮して加算
_exp = Mathf.Clamp(_exp + exp, 0, expArray[expArray.Length - 1]);
// 値の更新
UpdateLevel(expArray);
UpdateRemainExp(expArray);
return (Level, RemainExp);
}
void UpdateLevel(int[] expArray)
{
// 現Exp以下の値の中で最大の値のインデックスを取得
var maxIdx = expArray.Where(x => x <= _exp).Select((val, idx) => new {V = val, I = idx})
.Aggregate((max, working) => (max.V > working.V) ? max : working).I;
_level = maxIdx + 1;
}
void UpdateRemainExp(int[] expArray)
{
// 現Expより大きい値の中で最小の値のインデックスを取得
var minIdx = expArray.Where(x => x > _exp).Select((val, idx) => new {V = val, I = idx})
.Aggregate((min, working) => (min.V < working.V) ? min : working).I;
_remainExp = expArray[minIdx] - _exp;
}
}
Player.cs
[System.Serializable]
public class Player
{
public string Name = "主人公";
public ExpLevelClass ExpLevel = new ExpLevelClass();
static readonly int[] TOTAL_EXP_ARRAY = {0,100,300,600,1000};
// 経験値獲得処理
public (int afterLevel, int remainExp) AddExp(int exp)
{
return ExpLevel.AddExp(exp, TOTAL_EXP_ARRAY);
}
}
##参考
Linqで快適な生活を
[LINQ][C#] Aggregateの使い方(畳み込み, fold)
C# 7 の Tuple は戻り値が複数の時に便利