Note: My code sample is relatively trivial and generic enough to be usable in any game/app. It's 95% tested, but not very rigorously as it should be.
Range.cs - C# XNA Version:
using System;
using Microsoft.Xna.Framework;
namespace EricsLib
{
/// <summary>
/// The range class gives you a number which is between a min and max number.
/// Usages: -Keeping track of hitpoints or similar metrics
/// -keeping track of ability cool down timers
/// -Generating random numbers within a range
/// -Storing direction angles or other circular data (use looping values)
/// </summary>
public class Range
{
float m_max, m_min; //the thresholds for the meter value
float m_regen; //how many points you want to regenerate/degenerate every second
float m_current; //the current value of the meter
bool m_loopValues; //if this is 'true', then the current value will loop between min and max values instead of being capped.
public Range()
{
m_max = 100;
m_min = 0;
m_current = 100;
m_regen = 0;
m_loopValues = false;
}
/// <summary>
/// Creates a range with the current value at max value and min at zero
/// </summary>
/// <param name="max">the highest range value allowed</param>
public Range(float max)
{
m_max = max;
m_current = max;
m_min = 0.0f;
m_loopValues = false;
}
/// <summary>
/// creates a range value with the current value defaulted to the max value
/// </summary>
/// <param name="min">lowest range value</param>
/// <param name="max">highest range value</param>
public Range(float min, float max)
{
m_max = max;
m_min = min;
m_current = max;
m_loopValues = false;
}
/// <summary>
/// Creates a range
/// </summary>
/// <param name="min">lowest range value</param>
/// <param name="max">highest range value</param>
/// <param name="current">current range value</param>
public Range(float min, float max, float current)
{
m_max = max;
m_min = min;
m_current = current;
m_loopValues = false;
}
/// <summary>
/// creates a range value with regeneration/decay value set so the current value increases/decreases over time
/// </summary>
/// <param name="min">lowest range value</param>
/// <param name="max">highest range value</param>
/// <param name="current">current value in range</param>
/// <param name="regen">the change in current value over time</param>
public Range(float min, float max, float current, float regen)
{
m_max = max;
m_min = min;
m_current = current;
m_regen = regen;
m_loopValues = false;
}
public Range(Range Copy)
{
if (Copy == null)
return;
m_max = Copy.m_max;
m_min = Copy.m_min;
m_current = Copy.m_current;
m_regen = Copy.m_regen;
m_loopValues = Copy.m_loopValues;
}
/// <summary>
/// The current value will always be between min and max values
/// </summary>
public float Current
{
get
{
return m_current; //E: I'm assuming this gets truncated.
}
set
{
//do some quick bounds checking
if (value > m_max) //value is greater than specified max value
{
if (m_loopValues)
{
//the remaining looped value should be seamlessly added to the minimum value if it overflows the max
m_current = m_min + (value % m_max); //tested
}
else
{
m_current = m_max;
}
}
else if (value < m_min) //value is less than specified minimum value
{
if (m_loopValues)
{
m_current = m_min + (value % (m_max - m_min)); //tested
}
else
{
m_current = m_min;
}
}
else
m_current = value;
}
}
/// <summary>
/// Sets the current value to a random number between the min and max range values
/// </summary>
/// <param name="SetCurrent">Flag on whether you want to set the current value to the randomly generated number</param>
/// <returns>the value of current</returns>
public float Random(bool SetCurrent)
{
double d = Calc.random.NextDouble();
float diff = m_max - m_min;
diff *= (float)d;
if (SetCurrent == true)
{
m_current = m_max - diff;
}
return m_max - diff;
}
/// <summary>
/// Returns a random float which lies between min and max value of the range.
/// </summary>
/// <returns></returns>
public float Random()
{
return Random(false);
}
public float Max
{
get
{
return m_max;
}
set
{
m_max = value;
}
}
public float Min
{
get
{
return m_min;
}
set
{
m_min = value;
}
}
public float Half
{
get
{
return (m_min + m_max) / 2.0f;
}
}
/// <summary>
/// Per second regeneration/decay value for the current value of the meter
/// </summary>
public float RegenRate
{
get
{
return m_regen;
}
set
{
m_regen = value;
}
}
public void Update(GameTime gameTime)
{
//are we regenerating/decaying over time?
if (m_regen != 0)
{
Current += m_regen * (gameTime.ElapsedGameTime.Milliseconds);
}
}
public void SetToMax()
{
m_current = m_max;
}
public void SetToMin()
{
m_current = m_min;
}
public bool IsEmpty()
{
return (m_current <= m_min);
}
/// <summary>
/// Set/Get the current value as a percentage of the min and max values
/// </summary>
public float Percent
{
get
{
return ((m_current - m_min) / (m_max - m_min)) * 100;
}
set
{
m_current = m_min + ((value / 100) * (m_max - m_min));
}
}
/// <summary>
/// if this is 'true', then the current value will loop between min and max values instead of being capped.
/// Default: false
/// </summary>
public bool LoopValues
{
get
{
return m_loopValues;
}
set
{
m_loopValues = value;
}
}
/// <summary>
/// Tells you if the current range value is at the maximum value
/// </summary>
/// <returns></returns>
public bool IsMax()
{
return m_current == m_max;
}
/// <summary>
/// Tells you if the current range value is at the minimum value
/// </summary>
/// <returns></returns>
public bool IsMin()
{
return m_current == m_min;
}
}
}
Range.cs - C# Unity3D version:
using System;
using UnityEngine;
namespace EricsLib
{
/// <summary>
/// The range class gives you a number which is between a min and max number.
/// Usages: -Keeping track of hitpoints or similar metrics
/// -keeping track of ability cool down timers
/// -Generating random numbers within a range
/// -Storing direction angles or other circular data (use looping values)
/// </summary>
public class Range
{
float m_max, m_min; //the thresholds for the meter value
float m_regen; //how many points you want to regenerate/degenerate every second
float m_current; //the current value of the meter
bool m_loopValues; //if this is 'true', then the current value will loop between min and max values instead of being capped.
public Range()
{
m_max = 100;
m_min = 0;
m_current = 100;
m_regen = 0;
m_loopValues = false;
}
/// <summary>
/// Creates a range with the current value at max value and min at zero
/// </summary>
/// <param name="max">the highest range value allowed</param>
public Range(float max)
{
m_max = max;
m_current = max;
m_min = 0.0f;
m_loopValues = false;
}
/// <summary>
/// creates a range value with the current value defaulted to the max value
/// </summary>
/// <param name="min">lowest range value</param>
/// <param name="max">highest range value</param>
public Range(float min, float max)
{
m_max = max;
m_min = min;
m_current = max;
m_loopValues = false;
}
/// <summary>
/// Creates a range
/// </summary>
/// <param name="min">lowest range value</param>
/// <param name="max">highest range value</param>
/// <param name="current">current range value</param>
public Range(float min, float max, float current)
{
m_max = max;
m_min = min;
m_current = current;
m_loopValues = false;
}
/// <summary>
/// creates a range value with regeneration/decay value set so the current value increases/decreases over time
/// </summary>
/// <param name="min">lowest range value</param>
/// <param name="max">highest range value</param>
/// <param name="current">current value in range</param>
/// <param name="regen">the change in current value over time</param>
public Range(float min, float max, float current, float regen)
{
m_max = max;
m_min = min;
m_current = current;
m_regen = regen;
m_loopValues = false;
}
public Range(Range Copy)
{
if (Copy == null)
return;
m_max = Copy.m_max;
m_min = Copy.m_min;
m_current = Copy.m_current;
m_regen = Copy.m_regen;
m_loopValues = Copy.m_loopValues;
}
/// <summary>
/// The current value will always be between min and max values
/// </summary>
public float Current
{
get
{
return m_current; //E: I'm assuming this gets truncated.
}
set
{
//do some quick bounds checking
if (value > m_max) //value is greater than specified max value
{
if (m_loopValues)
{
//the remaining looped value should be seamlessly added to the minimum value if it overflows the max
m_current = m_min + (value % m_max); //tested
}
else
{
m_current = m_max;
}
}
else if (value < m_min) //value is less than specified minimum value
{
if (m_loopValues)
{
m_current = m_min + (value % (m_max - m_min)); //tested
}
else
{
m_current = m_min;
}
}
else
m_current = value;
}
}
/// <summary>
/// Sets the current value to a random number between the min and max range values
/// </summary>
/// <param name="SetCurrent">Flag on whether you want to set the current value to the randomly generated number</param>
/// <returns>the value of current</returns>
public float Random(bool SetCurrent)
{
double d = Calc.random.NextDouble();
float diff = m_max - m_min;
diff *= (float)d;
if (SetCurrent == true)
{
m_current = m_max - diff;
}
return m_max - diff;
}
/// <summary>
/// Returns a random float which lies between min and max value of the range.
/// </summary>
/// <returns></returns>
public float Random()
{
return Random(false);
}
public float Max
{
get
{
return m_max;
}
set
{
m_max = value;
}
}
public float Min
{
get
{
return m_min;
}
set
{
m_min = value;
}
}
public float Half
{
get
{
return (m_min + m_max) / 2.0f;
}
}
/// <summary>
/// Per second regeneration/decay value for the current value of the meter
/// </summary>
public float RegenRate
{
get
{
return m_regen;
}
set
{
m_regen = value;
}
}
public void Update()
{
//are we regenerating/decaying over time?
if (m_regen != 0)
{
Current += m_regen * Time.deltaTime;
}
}
public void SetToMax()
{
m_current = m_max;
}
public void SetToMin()
{
m_current = m_min;
}
public bool IsEmpty()
{
return (m_current <= m_min);
}
/// <summary>
/// Set/Get the current value as a percentage of the min and max values
/// </summary>
public float Percent
{
get
{
return ((m_current - m_min) / (m_max - m_min)) * 100;
}
set
{
m_current = m_min + ((value / 100) * (m_max - m_min));
}
}
/// <summary>
/// if this is 'true', then the current value will loop between min and max values instead of being capped.
/// Default: false
/// </summary>
public bool LoopValues
{
get
{
return m_loopValues;
}
set
{
m_loopValues = value;
}
}
/// <summary>
/// Tells you if the current range value is at the maximum value
/// </summary>
/// <returns></returns>
public bool IsMax()
{
return m_current == m_max;
}
/// <summary>
/// Tells you if the current range value is at the minimum value
/// </summary>
/// <returns></returns>
public bool IsMin()
{
return m_current == m_min;
}
}
}