• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML map_value (remap values from one range to another)

samspade

Member
map_value Function Tutorial

GM Version: 2.3+
Target Platform: All
Download: NA
Links: Video Explanation

Summary:

map_value re-maps a number from one number range to another. It works with positive and negative numbers and outside of its given range updated for GameMaker 2.3+.

Tutorial:


It is often very useful to be able to take a number from one range and find its equivalent in another range. That is what the function map_value() does. It takes five arguments, a value, the current min and max range and the destination or desired min and max range. It then takes the relation of that value to the first range and figures out what the number should be in relation to the second range and returns that number. For example,
  • 15 in range 0...10 becomes 150 in range 0...100
  • -5 in range -10...0 becomes 50 in range 0...100
  • 5 in range 0...10 becomes 0 in range -5...5
  • -5 in range 0...-10 becomes 250 in range 200...300
  • 5 in range 0...10 becomes -5 in range 0...-10
Example Uses:
  • drawing health bars to the screen (where health is the value, 0 and max health is the current range and the position for the start and end of the health bar is the desired min and max range)
  • sliders (turn the value of any slider into any other range)
  • functions or formulas that return a range (such as sin, cos, or gamepad_axis_value)
  • relative value of one thing to another (such as scaling damage within a range based on max health or scaling an image based upon another value)

Code

GML:
//map a value from one range to another
function map_value(_value, _current_lower_bound, _current_upper_bound, _desired_lowered_bound, _desired_upper_bound) {
    return (((_value - _current_lower_bound) / (_current_upper_bound - _current_lower_bound)) * (_desired_upper_bound - _desired_lowered_bound)) + _desired_lowered_bound;
}
Example Use

GML:
//draw a horizontal rectangle health bar where x1, y1, x2, and y2 are its coordinates on screen
var draw_hp_at = map_value(current_hp, 0, max_hp, x1, x2);
draw_set_color(c_red);
draw_rectangle(x1, y1, draw_hp_at , y2, false);
draw_set_color(c_black);
draw_rectangle(x1, y1, x2, y2, true);

//translate a sliders value to 0-1 assuming a slider where
//x represents the sliders position and slider_start and slider_end represent the min and max x values
global.slider_value = map_value(x, slider_start, slider_end, 0, 1);
If you would like a more detailed understanding of the math behind it, watch the following three videos on YouTube (not by me).

Coding Math:
 
Last edited:
I

immortalx

Guest
I'm only seeing this now due to a link posted in another thread. Great work as always samspade and kudos to FrostyCat too.
Sometime ago I've made a version of this script with an additional argument, for cases where as the value from the source range increases, the returned value decreases and vice-versa.

A use of that is a flashing sprite animation, where for example when a timer variable decreases the image_speed of the sprite increases.
Code:
///@description conv_range(from_min, from_max, to_min, to_max, value, inverse)
///@arg from_min
///@arg from_max
///@arg to_min
///@arg to_max
///@arg value
///@arg inverse

var f_min = argument[0];
var f_max = argument[1];
var t_min = argument[2];
var t_max = argument[3];
var val = argument[4];
var inverse = argument[5];
var result;

if (inverse)
{
    result = 1 - ((((val - f_min) / (f_max - f_min)) * (t_max - t_min)) + t_min);
}
else
{
    result = (((val - f_min) / (f_max - f_min)) * (t_max - t_min)) + t_min;
}

return clamp(result, t_min, t_max);
 

samspade

Member
I'm only seeing this now due to a link posted in another thread. Great work as always samspade and kudos to FrostyCat too.
Sometime ago I've made a version of this script with an additional argument, for cases where as the value from the source range increases, the returned value decreases and vice-versa.

A use of that is a flashing sprite animation, where for example when a timer variable decreases the image_speed of the sprite increases.
Code:
///@description conv_range(from_min, from_max, to_min, to_max, value, inverse)
///@arg from_min
///@arg from_max
///@arg to_min
///@arg to_max
///@arg value
///@arg inverse

var f_min = argument[0];
var f_max = argument[1];
var t_min = argument[2];
var t_max = argument[3];
var val = argument[4];
var inverse = argument[5];
var result;

if (inverse)
{
    result = 1 - ((((val - f_min) / (f_max - f_min)) * (t_max - t_min)) + t_min);
}
else
{
    result = (((val - f_min) / (f_max - f_min)) * (t_max - t_min)) + t_min;
}

return clamp(result, t_min, t_max);
I don't think that math is right. I believe what you want is:

Code:
result = ((1 - (val - f_min) / (f_max - f_min)) * (t_max - t_min)) + t_min;

//not

result = 1 - ((((val - f_min) / (f_max - f_min)) * (t_max - t_min)) + t_min);
As you want to reverse the percent, not get one minus entire equation - e.g. 0, 1, 0, 100, 0.25, true, should result in 75 not -24.

However, even this is unnecessary as map already does that naturally. You just reverse the to min and to max.

So for example (using my argument order - value, from min, from max, to min, to max):

Code:
result = map(0.25, 0, 1, 0, 100); //result = 25
result = map(0.25, 0, 1, 100, 0); //result = 75
No need for an inverse variable.

Edit: You can also reverse the from min and max for similar results or mix and match as you want:

Code:
result = map(0.25, 0, 1, 0, 100); //result = 25
result = map(0.25, 1, 0, 0, 100); //result = 75
result = map(0.25, 1, 0, 100, 0); //result = 25
But you do bring up a good point that another version of map - perhaps name it map_clamp - is useful if you want to clamp the values returned by map as the version I posted will return values outside of the range (which is how the GML function lerp also works).
 
Last edited:
I

immortalx

Guest
Thanks for the explanation samspade! I'm not a math guy so I'll just blindly use what you said :D
 

FoxyOfJungle

Kazan Games
map_value still exist? i can't use this function, sorry i'm newbie dev :/
Yes, it's in the first post, just copy this code to a script. Then just use the map_value() function as if it were another normal GameMaker/GML function.

//map a value from one range to another function map_value(_value, _current_lower_bound, _current_upper_bound, _desired_lowered_bound, _desired_upper_bound) { return (((_value - _current_lower_bound) / (_current_upper_bound - _current_lower_bound)) * (_desired_upper_bound - _desired_lowered_bound)) + _desired_lowered_bound; }
 
Top