Unity3D has a class for platform-independent data storage called PlayerPrefs
. Supported data types: int
, float
and string
can be retrieved and set using static methods, but no bool
support exists, and you have to manually call Save()
to make sure value changes persist.
I wrote a little helper class to cut down on the the boilerplate, and also add support for bool
and enum
datatypes. I'm looking for a general critique on style and efficiency, there's a fair amount of duplication, but I'm not sure how I can reduce that.
/// <summary>
/// Helper class that simplifies common PlayerPrefs getting and setting.
/// </summary>
public static class PlayerPrefsHelper
{
/// <summary>
/// Gets an int value from PlayerPrefs
/// </summary>
/// <remarks>
/// This method has a side effect of creating a PlayerPrefs entry for the given key if one does not exist.
/// </remarks>
/// <param name="key">The key.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>The int value stored in PlayerPrefs for the given key, or defaultValue if no such key exists</returns>
public static int GetInt(string key, int defaultValue)
{
if (!PlayerPrefs.HasKey(key))
{
SetInt(key, defaultValue);
}
return PlayerPrefs.GetInt(key);
}
/// <summary>
/// Sets an int value on PlayerPrefs
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public static void SetInt(string key, int value)
{
PlayerPrefs.SetInt(key, value);
PlayerPrefs.Save();
}
/// <summary>
/// Gets a bool value from PlayerPrefs.
/// </summary>
/// <remarks>
/// This method has a side effect of creating a PlayerPrefs entry for the given key if one does not exist.
/// The value will be converted from an integer value, because PlayerPrefs does not support boolean values. 0 will be converted to false, all other values will be converted to true.
/// </remarks>
/// <param name="key">The key.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>The bool value stored in PlayerPrefs for the given key, or defaultValue if no such key exists</returns>
public static bool GetBool(string key, bool defaultValue)
{
return GetInt(key, defaultValue ? 1 : 0) != 0;
}
/// <summary>
/// Sets a bool value on PlayerPrefs.
/// </summary>
/// <remarks>
/// The value will be stored as an integer, because PlayerPrefs does not support boolean values. True will be stored as 1, false as 0.
/// </remarks>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public static void SetBool(string key, bool value)
{
SetInt(key, value ? 1 : 0);
}
/// <summary>
/// Gets a float value from PlayerPrefs
/// </summary>
/// <remarks>
/// This method has a side effect of creating a PlayerPrefs entry for the given key if one does not exist.
/// </remarks>
/// <param name="key">The key.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>The float value stored in PlayerPrefs for the given key, or defaultValue if no such key exists</returns>
public static float GetFloat(string key, float defaultValue)
{
if (!PlayerPrefs.HasKey(key))
{
SetFloat(key, defaultValue);
}
return PlayerPrefs.GetFloat(key);
}
/// <summary>
/// Sets a float value on PlayerPrefs
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public static void SetFloat(string key, float value)
{
PlayerPrefs.SetFloat(key, value);
PlayerPrefs.Save();
}
/// <summary>
/// Gets a string value from PlayerPrefs
/// </summary>
/// <remarks>
/// This method has a side effect of creating a PlayerPrefs entry for the given key if one does not exist.
/// </remarks>
/// <param name="key">The key.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>The string value stored in PlayerPrefs for the given key, or defaultValue if no such key exists</returns>
public static string GetString(string key, string defaultValue)
{
if (!PlayerPrefs.HasKey(key))
{
SetString(key, defaultValue);
}
return PlayerPrefs.GetString(key);
}
/// <summary>
/// Sets a string value on PlayerPrefs
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public static void SetString(string key, string value)
{
PlayerPrefs.SetString(key, value);
PlayerPrefs.Save();
}
/// <summary>
/// Gets a value from PlayerPrefs as enumerated type T.
/// </summary>
/// <remarks>
/// This method has a side effect of creating a PlayerPrefs entry for the given key if one does not exist.
/// </remarks>
/// <typeparam name="T">The type of enum expected.</typeparam>
/// <param name="key">The key.</param>
/// <param name="defaultValue">The default value if no PlayerPrefs setting exists for the key.</param>
/// <returns>The value stored in PlayerPrefs for the given key, converted to type T, or defaultValue if no such key exists</returns>
/// <exception cref="ArgumentException">T must be an enumerated type</exception>
/// <exception cref="InvalidOperationException">Cannot get an enum that doesn't have underlying type Int32.</exception>
public static T GetEnum<T>(string key, T defaultValue) where T : struct, IConvertible
{
var enumType = typeof(T);
if (!enumType.IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
if (Enum.GetUnderlyingType(enumType) == typeof(int))
{
var value = GetInt(key, defaultValue.ToInt32(CultureInfo.InvariantCulture));
return (T)Enum.ToObject(enumType, value);
}
throw new InvalidOperationException("Cannot get an enum that doesn't have underlying type Int32.");
}
/// <summary>
/// Sets an int value on PlayerPrefs based on an enumerated value.
/// </summary>
/// <typeparam name="T">The type of enum.</typeparam>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <exception cref="ArgumentException">T must be an enumerated type</exception>
/// <exception cref="InvalidOperationException">Cannot store an enum that doesn't have underlying type Int32.</exception>
public static void SetEnum<T>(string key, T value) where T : struct, IConvertible
{
var enumType = typeof(T);
if (!enumType.IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
if (Enum.GetUnderlyingType(enumType) == typeof(int))
{
SetInt(key, value.ToInt32(CultureInfo.InvariantCulture));
}
throw new InvalidOperationException("Cannot store an enum that doesn't have underlying type Int32.");
}
}