Mapping a Value
Mapping a value from one range to another is commonly used in game development. Here is some information about this process that you can use to inform you in making your own tools, and also some code you can simply copy.
The Maths
If I’m mapping the range $[a, b]$ onto $[c, d]$ with an input value of x, then: $$y = (x - a) \left( \frac{d - c}{b - a} \right) + c$$
Which is easier to understand when written as: $$\text{outputValue} = (\text{inputValue} - \text{oldMin}) \times \left( \frac{\text{newMax} - \text{newMin}}{\text{oldMax} - \text{oldMin}} \right) + \text{newMin}$$
The Code
Lets translate all of the maths into code. We’ll be using C#, but you can find examples of the final script for other languages at the bottom of this page.
Our Goal
For this to be useful in our games, we would like to be able to wrap it up in a function and call it in the following manner.
float outputValue = MapValue(inputValue, oldMin, oldMax, newMin, newMax);
This line of code calculates the mapped value outputValue from the inputValue given the specified ranges oldMin to oldMax and newMin to newMax. Now we know where we are going, let’s create the MapValue() method that will allow this to work.
Constructing the method
We want our method to return the mapped value, therefore we start by declaring a return type of type float.
float
Then we name our method.
float MapValue()
Then we need to give it some values to work with, those values are of course the input value that we want to map, our input range, and our output range. We represent the ranges by their minimum and maximum values.
float MapValue(float inputValue, float oldMin, float oldMax, float newMin, float newMax) {}
The next step is to translate our maths into code, and fill out the body of our method. Doing this gets us the following.
float MapValue(float inputValue, float oldMin, float oldMax, float newMin, float newMax)
{
return (inputValue - min) * ((newMax - newMin) / (oldMax - oldMin)) + newMin;
}
But, doing so will net us a few problems, notably when our input value is outside of the initial range. For example:
- If the inputValue is less than oldMin then $\text{inputValue} - \text{oldMin}$ will result in a negative value.
- This negative value will then be multiplied by the ratio $\frac{\text{newMax} - \text{newMin}}{\text{oldMax} - \text{oldMin}}$, potentially resulting in an incorrect mapping that then gets added to newMin and returned.
To account for this, we add catchers before the equation, one for if the inputValue is less than the oldMin, and one for if it is greater then the oldMax. In each respective case, we just need our method to spit out the minimum and maximum values of the output range.
Firstly, to check if inputValue is less than or equal to oldMin, we add the following if statement before our equation.
// Check if inputValue is less than or equal to the minimum of the original range.
if (inputValue <= oldMin)
{
// If so, return the minimum value of the new range.
return newMin;
}
Secondly, to check if inputValue is greater than or equal to oldMax, we add a this one.
// Check if inputValue is less than or equal to the minimum of the original range.
if (inputValue =< oldMax)
{
// If so, return the minimum value of the new range.
return newMax;
}
Final Result
You can copy this function and use it in your projects freely.
float MapValue(float inputValue, float oldMin, float oldMax, float newMin, float newMax)
{
// Check if inputValue is less than or equal to the minimum of the original range.
if (inputValue <= oldMin)
{
// If so, return the minimum value of the new range.
return newMin;
}
// Check if inputValue is greater than or equal to the maximum of the original range.
else if (inputValue >= oldMax)
{
// If so, return the maximum value of the new range.
return newMax;
}
else
{
// Otherwise, calculate the mapped value using linear interpolation.
return (inputValue - oldMin) * ((newMax - newMin) / (oldMax - oldMin)) + newMin;
}
}
Other Programming Languages
Here are some examples written for other popular programming languages.
GDScript
func map_value(input_value: float, old_min: float, old_max: float, new_min: float, new_max: float) -> float:
# Check if the input value is less than or equal to the minimum of the original range.
if input_value <= old_min:
# If so, return the minimum value of the new range.
return new_min
# Check if the input value is greater than or equal to the maximum of the original range.
elif input_value >= old_max:
# If so, return the maximum value of the new range.
return new_max
else:
# Otherwise, calculate the mapped value using linear interpolation.
return (input_value - old_min) * ((new_max - new_min) / (old_max - old_min)) + new_min
Python
def map_value(input_value, old_min, old_max, new_min, new_max):
# Check if the input value is less than or equal to the minimum of the original range.
if input_value <= old_min:
# If so, return the minimum value of the new range.
return new_min
# Check if the input value is greater than or equal to the maximum of the original range.
elif input_value >= old_max:
# If so, return the maximum value of the new range.
return new_max
else:
# Otherwise, perform linear interpolation to calculate the mapped value.
return (input_value - old_min) * ((new_max - new_min) / (old_max - old_min)) + new_min