Godot Engine – How to remap a range of numbers

The explanation of range remapping in this article is universally applicable to every use case where value remapping is required. Towards the end of this article we’ll take a look at how to implement the formula as a function in the Godot game engine.

A use case for value remapping

Let’s say you create a survival game where the player has to eat to survive. At 30% hunger his base health regeneration rate of 3/sec starts to decrease. If the hunger hits 90%, the regeneration is at a maximum of negative 1/sec, which causes the player to lose health.

You now want to find out what the regeneration rate for any value between 30% and 90% hunger is.

We’ll call the percentage of hunger the player has right now value. The hunger’s range from 30 to 90 is InputA and InputB. The regeneration values from 3 to -1 are OutputA and OutputB.

InputA and OutputA (30 and 3) and InputB and OutputB (90 and -1) are paired up.

To figure out the resulting regeneration value, we can use this formula:

result = (value - InputA) / (InputB - InputA) * (OutputB - OutputA) + OutputA

So, if the player is 78% hungry, the formula looks like this:

-0.2 = (78 - 30) / (90 - 30) * (-1 - 3) + 3

The formula is working, but how?

If you are a visual learning type like me, you might not get what’s happening there at first. But it’s actually quite simple if you deconstruct each step. Let’s begin with visualizing the values.

The value range for the player’s hunger is yellow, the one for the regeneration value is green. The current hunger level is indicated by the red bar. I’ve aligned the bars in a way that 0 and the maximum values line up. Keep focused on the red bar to understand how the input value is changing with every operation.

Now we’ll split the formula into four steps.

A) (value - InputA)
B) divided by (InputB - InputA)
C) multiplied by (OutputB - OutputA)
D) plus OutputA

A) (value – InputA) moves the yellow bar’s start to 0. Imagine grabbing the bar and moving it 30 units to the left. The values now range from 0 – 60. Our current hunger value of 78 is now offset by -30 too, which is 48.

B) (InputB – InputA) yields the yellow hunger bar’s total length. In our example that would be 90 – 30, which is 60. If we divide the entire yellow bar by 60, its length becomes 1. This scales the hunger value from 48 down to 0.8. The hunger value has been normalized, because its new minimum and maximum value (the yellow bar) is between 0 and 1.

C) OutputB – OutputA is the total length of the green bar (-1 – 3), which is -4. If we multiply our yellow bar with the green bar’s total size of -4, they’ll have the same size, but the yellow bar flips sides. The hunger value (0.8) has been scaled by -4 too and is now at -3.2.

D) + OutputA aligns the yellow bar with the green one. We add the green bar’s OutputA value, which is 3, to the yellow bar. All values inside the yellow bar are shifted by 3. The two bars are fully matched up now and our hunger value has moved from -3.2 to its final position at -0.2. We now know that a hunger value of 78% causes the regeneration rate to fall from 3/sec to -0.2/sec.

Creating the remap_range() function in Godot

We’ll now write this as a remap_range() function in Godot that gives the equation’s outcome back as a return value so we can reuse it with any numbers we choose.

func remap_range(value, InputA, InputB, OutputA, OutputB):
    return(value - InputA) / (InputB - InputA) * (OutputB - OutputA) + OutputA

Important: Make sure to enter the input variable as a float when you call this function or the resulting value will be wrong due to rounding errors. If your value doesn’t have a floating point value, just add .0 to it.

5 Gedanken zu „Godot Engine – How to remap a range of numbers

  1. Although the formula is correct, your explanation is not. it should be 2.2 instead as you pointed out at the end of your article. In your explanation you have the wrong starting point as “-0.2 = (78 – 30) / (90 – 30) * (-1 – 3) + 3” is not correct, you have inverted the (maxOutput – minOutput) as the formula with values should be “2.2 = (78 – 30) / (90 – 30) * (3 – (-1)) + 3”. Therefore the explanation C) and D) are wrong. Hope this helps someone who’s trying to understand this to don’t get confused with the step by step explanation.

  2. Thank you for letting me know about this! In hindsight I should probably have used an easier example.

    -0.2 actually *is* the correct result, but the 2.2 at the end of my posting was wrong. I had some trouble myself because of the values of 3 and -1 and forgot to correct this mistake in the end. The calculation you have posted results in 6.2 and not 2.2.

    I’ve made some minor text passages clearer and also reuploaded the second picture, it went missing for some reason. It should now be easier to follow the example visually.

    The complicated part about my example is that my maxOutput (-1) is smaller than my minOutput (3). If you use easier numbers you can see that the formula is correct. Let’s remap a value of 25 from a range of 0 to 100 to a range of 0 to 1000.

    (input – minInput) / (maxInput – minInput) * (maxOutput – minOutput) + minOutput

    (25 – 0) / (100 – 0) * (1000 – 0) + 0
    = 25 / 100 * 1000
    = 0.25 * 1000
    = 250

    Here’s another one: 15 in a range from 10 to 20 remapped to a range of -10 to -20:

    (15 – 10) / (20 – 10) * (-20 – (-10)) + (-10)
    = 5 / 10 * -10 – 10
    = 0,5 * -10 – 10
    = -5 – 10
    = -15

  3. Thank you for pointing that one out. I missed to fix the D) part of my explanation. First let’s make it clear that the maxOutput you should read as the biggest value possible for your final range, therefore the biggest value between -1 and 3 is 3. Having said that, to fix the issue on C) as I said before, you need to change the (maxOutput – minOutput) to (3 – (-1)) and similarly to fix the issue on D) you need to change the „+ minOutput“ to „+ (-1)“ so the formula should look like this: 2.2 = (78 – 30) / (90 – 30) * (3 – (-1)) + (-1)
    Funny enough you applied the formula correctly in your first comment but not in your second example but still the final result is correct – with negatives where -10 is bigger than -20 so it’s reversed here (should be „(15 – 10) / (20 – 10) * (-10 – (-20)) + (-20)“ . Hope this makes things clearer for you. Thanks for the article!

  4. The maxOutput does not have to be the bigger number. The words „min“ and „max“ are completely misleading here and it was unwise to used them, they just indicate which of the numbers match up. In my example 30 and 3 form one pair and 90 and -1 form the second pair. If I had used „InputA“ and „OutputA“ instead of „minInput“ and „minOutput“ this would have been clearer. The order of pairs here is important, not the size of the numbers.

    If the „maxOutput“ would always have to be the bigger number, you could for example not logically do the following:

    2 in a range from 0 to 10 remapped to a range of 10 to 0.

    The result is 8. If the larger number would always be the „maxOutput“, you would remap a range from 0 to 10 to a range from 0 to 10 again. You would always end up with the same number you started with in this example.

    I have replaced the words min and max in my article. It’s adding unnecessary confusion to use these words together with numbers. This formula here is easier to read:

    result = (value – InputA) / (InputB – InputA) * (OutputB – OutputA) + OutputA

    Thank you too for starting this discussion, it has hopefully made the article much more comprehensible now.

  5. I see now. My assumption that „you should read as the biggest value possible for your final range“ is not correct as you pointed out and your example of „2 in a range from 0 to 10 remapped to a range of 10 to 0“ helped me to understand it better. Thanks for that and keep up the good work!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Nach oben scrollen