はじめに
クッキークリッカー系ゲームを作ったのですが、int型が割と簡単にオーバーフローしてしまったので、拡張メソッドを使って上限値・カンスト値を設定してみました。
今回は、intとintを加算して、元々の値に代入する仕様ですので、それぞれのintのカンスト値を999,999,999(10億 - 1)に設定しました。
intの値の範囲は、正の部分が2,147,483,647(21億4748万3647)のため、999,999,999(10億 - 1)にカンスト値を設定すれば、
・何かの拍子にカンスト値同士を足してしまっても、intの値の範囲を超えない
・ゲーム慣れしている人にとって、上限値っぽく見える
という点でメリットがあるかなーと考えた結果です。
コード
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class IntExtension {
// 上限値
public const int UPPER_LIMIT = 999999999;
// 下限値
public const int LOWER_LIMIT = 0;
///<summary>
/// Int同士の加算時に、加算予定の値につけて下限・上限を超えないかチェック。
///<param name="baseVariable">加算される元の値</param>
///<example>
///<code>
/// willAddInt.AddIntAndIntLimitCheck(BaseInt);
///</code>
///</example>
///</summary>
public static int AddIntAndIntLimitCheck(this int _willAdd, int baseVariable) {
int checkedNum;
// 加算する二値の和が上限値より大きい場合、上限値で上書きする。
if (_willAdd + baseVariable > UPPER_LIMIT) {
checkedNum = UPPER_LIMIT;
// 二値の和が下限値未満になる場合、下限値で上書きする。
} else if (_willAdd + baseVariable < LOWER_LIMIT) {
checkedNum = LOWER_LIMIT;
// 問題がなければ、二値の和をそのまま返す。
} else {
checkedNum = _willAdd + baseVariable;
}
return checkedNum;
}
}
使い方
使い方は、以下の値があるとして
・足した結果を格納する変数 BaseInt(e.g. プレイヤーの所持金)
・これから足すint値 willAddInt(e.g. モンスターを倒した時に得られるお金)
BaseInt = willAddInt.AddIntAndIntLimitCheck(BaseInt);
みたいな感じで使います。
BaseIntが2回あるのが冗長なのですが、左辺の変数と、右辺の引数部分を別の値にすることもあるかもしれないので、こんな感じにしました。
既存のメソッドを拡張したときは、利用時には特にusingなどを足さなくても大丈夫です(int型が使える必要はありますが)。
おわりに
莫大なデータ値を扱う場合、それが正の値であるならばuintを使ったり、環境が許せばlongを使ったりという選択肢もあると思います。
今回は、UnityのPlayerPrefsに直で保存できる値がfloat、int、stringだったため、intを使いました。
データ型として例えばuintを使った場合、保存時にstringパースして、引き出す時にuintパースをすればできるはずなのですが、ボクが試した限りでは変換が上手くいかなかったのでintを利用しました。
いやしかし、友人がツールを使って数分でオーバーフローさせてくれたのは笑いました。
何かの参考になれば幸いです。
参考文献
データ型の範囲
https://msdn.microsoft.com/ja-jp/library/s3f49ktz.aspx
【C#】 数値を加算して、範囲を超えた分は 0 からの値として処理して返す拡張メソッド - コガネブログ
http://baba-s.hatenablog.com/entry/2014/07/03/100719