Clamp / Map Range Clamped / Normalize To Range¶
At a glance
Lives in: Kismet Math Library; Blueprint API / Math / Float -
Returns: one real number; never None - Changes: nothing; these are
pure calculations, so you must assign or pass the result yourself -
Fails by: producing a valid-looking fallback or unintended endpoint
when bounds are equal/reversed incorrectly; no failure pin or warning -
Official docs: Clamp,
Map Range Clamped,
and Normalize To Range
The one-minute version¶
Clampkeeps a value between a minimum and maximum. It does not convert one range into another.Map Range Clampedconverts a value from input endpoints A/B to output endpoints A/B and limits values outside the input range to output endpoints.Normalize To Rangeanswers "how far from Range Min to Range Max is this value?" It returns0at the first endpoint and1at the second, but it does not clamp values outside the range.Normalize To Range(150, 0, 100)returns1.5, not1.- Reversed endpoints can be intentional. Mapping
100 -> 0into0 -> 1makes75become0.25. - Equal input endpoints have zero width, so no meaningful ratio exists. Branch before the node and choose an explicit fallback.
- For a health bar, guard
MaxHealth <= 0, then use a clamped0..1result. - Keep range math as real numbers. Convert to Integer only at the edge with an explicit rounding rule.
Pick the node by the question¶
| Question | Node | Example result |
|---|---|---|
| "Keep this health between 0 and 100." | Clamp |
Clamp(130, 0, 100) = 100 |
| "Convert speed 0..600 into volume 0..1, limited." | Map Range Clamped |
300 -> 0.5 |
| "What fraction of 200..600 is 300?" | Normalize To Range |
0.25 |
| "Blend A to B using an existing 0..1 alpha." | Lerp |
consumes the ratio; does not derive it |
All three nodes are pure. Calling Clamp(CurrentHealth, 0, MaxHealth) does not
change CurrentHealth until you assign the returned value:
CurrentHealth = Clamp(CurrentHealth + Delta, 0, MaxHealth)
Clamp limits; it does not remap¶
Clamp(Value, Min, Max) has three outcomes:
Value below Min -> Min
Value in range -> Value
Value above Max -> Max
Examples:
| Call | Result |
|---|---|
Clamp(-20, 0, 100) |
0 |
Clamp(40, 0, 100) |
40 |
Clamp(130, 0, 100) |
100 |
The result stays in the original units. Clamping health to 0..100 does not
turn health into a 0..1 UI percentage.
Min should be less than or equal to Max. A reversed Clamp is not an
instruction to invert the value and the node does not sort the bounds for you.
If bounds can arrive in either order, establish them explicitly:
Low = Min(A, B)
High = Max(A, B)
SafeValue = Clamp(Value, Low, High)
Do not use that sorting pattern for a deliberate reversed mapping. Mapping endpoint order carries direction; Clamp minimum/maximum order does not.
Map Range Clamped converts and limits¶
Map Range Clamped takes five values:
Value
In Range A
In Range B
Out Range A
Out Range B
It finds Value's fraction between the two input endpoints, limits that fraction
to 0..1, and uses it between the output endpoints:
pseudocode - not engine source
t = (Value - InA) / (InB - InA)
t = Clamp(t, 0, 1)
Result = OutA + t * (OutB - OutA)
For Value = 75, input 0 -> 100, output 0 -> 1, the result is 0.75.
Outside values stop at the corresponding output endpoint:
| Value | Input | Output | Result |
|---|---|---|---|
-20 |
0 -> 100 |
0 -> 1 |
0 |
25 |
0 -> 100 |
0 -> 1 |
0.25 |
150 |
0 -> 100 |
0 -> 1 |
1 |
The output range can use any units. For example, speed 0..600 cm/s can drive
sound volume 0..1, camera shake strength 0..2, or a material parameter
0.2..0.8.
Normalize To Range produces an unclamped ratio¶
Normalize To Range(Value, Range Min, Range Max) calculates:
(Value - RangeMin) / (RangeMax - RangeMin)
For an ordinary increasing range:
| Call | Result |
|---|---|
Normalize To Range(10, 10, 50) |
0 |
Normalize To Range(20, 10, 50) |
0.25 |
Normalize To Range(50, 10, 50) |
1 |
Normalize To Range(70, 10, 50) |
1.5 |
Normalize To Range(0, 10, 50) |
-0.25 |
"Normalize" here means express a scalar relative to a range. It is not the same operation as normalizing a Vector to unit length.
The result can be useful outside 0..1 when overshoot matters. If the consumer
requires a bounded ratio, clamp it:
Ratio = Clamp(Normalize To Range(Value, A, B), 0, 1)
Or use Map Range Clamped with output 0 -> 1.
Reversed ranges¶
A reversed input range is valid when it expresses direction:
Normalize To Range(75, 100, 0) = 0.25
Map Range Clamped
Value = 75
In Range A = 100
In Range B = 0
Out Range A = 0
Out Range B = 1
-> 0.25
Endpoint A still maps to output A, and endpoint B maps to output B. The labels
Range Min and Range Max on Normalize To Range are conventional names;
the formula's direction comes from their order.
A reversed output range is also useful:
Map temperature 0 -> 100
to cooling strength 1 -> 0
Do not sort endpoints automatically unless increasing order is truly the data
contract. Sorting a deliberate 100 -> 0 input changes its meaning.
Equal endpoints and division by zero¶
When both input endpoints are equal, the denominator is zero:
RangeA = 50
RangeB = 50
There is no answer to "what fraction of the way from 50 to 50 is Value?" The Blueprint nodes do not provide a failure pin or diagnostic for this invalid mapping contract.
Current engine source gives Normalize To Range a special exact-equality
fallback: it returns Range Min when Range Min == Range Max. That prevents a
literal divide-by-zero result, but the fallback is not a useful normalized
ratio. With 50 -> 50, it returns 50, not 0 or 1.
Map Range Clamped delegates to the core FMath mapped-range helpers. Do not
make gameplay depend on their degenerate endpoint handling. Guard zero-width
input explicitly and choose the meaning your system needs:
if Nearly Equal(InA, InB, Tolerance):
Result = OutA // or OutB, 0, disabled, hidden - choose deliberately
else:
Result = Map Range Clamped(Value, InA, InB, OutA, OutB)
Use Nearly Equal when endpoints are computed values. Exact equality is fine
for an authored invariant such as MaxHealth == 0, but the branch should still
make the fallback clear.
Health and progress bars¶
There are two separate operations:
- keep gameplay health legal;
- convert legal health to a UI ratio.
CurrentHealth = Clamp(CurrentHealth + Delta, 0, MaxHealth)
if MaxHealth <= 0:
HealthPercent = 0
else:
HealthPercent = Map Range Clamped(
CurrentHealth,
0,
MaxHealth,
0,
1)
The second step could also use:
HealthPercent = Clamp(CurrentHealth / MaxHealth, 0, 1)
after the same MaxHealth guard. A Progress Bar expects a real value from
0..1, not 0..100; see
Buttons and Progress Bars.
Do not hide invalid MaxHealth behind range math. Decide whether zero maximum
means empty, disabled, indeterminate, or a setup error.
Dead zones are not just Clamp¶
Clamping axis input to -1..1 limits extreme values, but it does not remove
small stick drift around zero. A dead zone applies a threshold and often
rescales the remaining interval so motion starts smoothly after that threshold.
A manual one-sided shape is:
if Absolute(Axis) <= DeadZone:
Output = 0
else:
Magnitude = Map Range Clamped(
Absolute(Axis),
DeadZone,
1,
0,
1)
Output = Magnitude * Sign(Axis)
For Enhanced Input, prefer its Dead Zone modifier so the rule lives with the Input Action mapping. Tier 36 covers that node and radial versus axial input.
Keep integers out of the middle¶
Range conversion usually produces fractions. Integer arithmetic or an early Integer conversion can discard them:
Bad shape:
convert 25 / 100 to Integer too early
-> loses the 0.25 ratio
Good shape:
keep Value, ranges, ratio, and mapped output as real numbers
-> convert only the final display/count value
When an Integer is required, choose Round, Floor, Ceil, or Truncate
explicitly. Those rules differ for fractional and negative values. An implicit
conversion hides a design decision.
Relationship to Lerp¶
Lerp consumes an alpha; it does not discover that alpha from an input range.
The operations fit together like this:
Alpha = Normalize To Range(Value, InA, InB)
Result = Lerp(OutA, OutB, Alpha)
With a valid non-equal input range, Map Range Clamped is approximately the
bounded form:
Alpha = Clamp(Normalize To Range(Value, InA, InB), 0, 1)
Result = Lerp(OutA, OutB, Alpha)
Use Lerp, FInterp To, and moving things smoothly when the real question is interpolation over time. Range mapping is an instant conversion; it does not animate or smooth by itself.
The C++ twins¶
For the curious, an original guarded example is:
double UStatusReadout::GetHealthPercent(
double CurrentHealth,
double MaxHealth) const
{
if (MaxHealth <= 0.0)
{
return 0.0;
}
return FMath::GetMappedRangeValueClamped(
FVector2D(0.0, MaxHealth),
FVector2D(0.0, 1.0),
CurrentHealth);
}
FMath::Clamp, FMath::GetRangePct, FMath::GetRangeValue, and
FMath::GetMappedRangeValueClamped are the core helpers behind the same
families of operations.
Lookalikes - which one do I want?¶
| Node | Returns | Use when | Watch out |
|---|---|---|---|
| Clamp | Original value limited to Min/Max | One value must stay within legal bounds. | Does not remap; Min must not exceed Max. |
| Map Range Clamped | Value converted and bounded to output endpoints | Input and output use different scales and overshoot should stop. | Equal input endpoints have no meaningful ratio. |
| Map Range Unclamped | Value converted without limiting alpha | Extrapolation outside output endpoints is intentional. | Overshoot can become large. |
| Normalize To Range | Unclamped ratio relative to two endpoints | You need an alpha/fraction and may care about overshoot. | Result can be below 0 or above 1. |
| Lerp | Value between output A/B for an alpha | You already have the alpha. | Does not derive or advance alpha. |
| Min / Max | One selected endpoint/value | You need to order or choose values. | Does not clamp by itself. |
Going deeper¶
- Buttons, Progress Bars, and basic UMG events -
the
0..1Progress Bar contract and event-driven updates. - Health components and damage response - legal health state and update ownership.
- Lerp, FInterp To, and moving things smoothly - alpha consumption and time-based interpolation.
- Vector Length / Vector Length XY / Normalize - vector magnitude and why vector normalization is a different operation.
- Official docs: Clamp, Map Range Clamped, Normalize To Range, and FMath::GetMappedRangeValueClamped.
- Engine source (requires engine access - we do not reproduce it here):
UKismetMathLibrary::MapRangeClampedandUKismetMathLibrary::NormalizeToRangeare declared inEngine/Source/Runtime/Engine/Classes/Kismet/KismetMathLibrary.hand implemented inEngine/Source/Runtime/Engine/Private/KismetMathLibrary.cpp; the core range helpers are inEngine/Source/Runtime/Core/Public/Math/UnrealMathUtility.h.