ConvertScale Function

I came up with a useful little function that I’ve used in my game many times. Basically, it defines a linear relationship between two number ranges.

function ConvertScale(input,inputRange,outputRange,noClamp)
	if input and inputRange and outputRange then
		local inputRangeMin = inputRange[1]
		local inputRangeMax = inputRange[2]
		local outputRangeMin  = outputRange[1]
		local outputRangeMax = outputRange[2]
		local scale = (input - inputRangeMin) / (inputRangeMax - inputRangeMin)
		local unclampedOutputValue = ((outputRangeMax - outputRangeMin) * scale) + outputRangeMin
		local clampedOutputValue = math.min(outputRangeMax,math.max(outputRangeMin,unclampedOutputValue))
		return (noClamp and unclampedOutputValue) or clampedOutputValue
	end
end

Examples:

Changing the transparency of a brick depending how high it is off the ground. In this example, if the block is touching the ground (position.y == 0), it will be nearly invisible. If the block 100 studs or higher, it will be opaque. If the block’s height is at around 50 studs, the block’s transparency will be slightly below .5

local heightRange = {0,100} --range from the ground to 100 studs in the air
local transparencyRange = {.95,0} --nearly invisible to opaque
local transparency = ConvertScale(Block.Position.Y,heightRange,transparencyRange)
Block.Transparency = transparency

Changing the volume of in-game music depending on the position of a gui volume slider

local musicVolumeRange = {0,1.5} --let's say the max volume of the music is 1.5
local sliderPositionOffsetRange = {0,500} --let's say the slider's range of movement is 500 pixels wide
local volume = ConvertScale(SliderObject.X.Offset,sliderPositionOffsetRange,musicVolumeRange)
MusicSoundObject.Volume = volume  --If the slider's offset is 500, then the music volume will be 1.5

You can pass “true” through the noClamp argument if you want to scale the output value beyond the output range.

15 Likes

Nice. I think this is similar to the “map” function used in Arduino’s API, if I’m understanding this correctly. Pretty useful! I like that you added the option to not clamp though.

1 Like

I figured there would be something similar out there.

Why not use the official NumberRange class? :o

local heightRange = NumberRange.new(0, 100)

The idea there is nice, though I think you may have overcomplicated it. As @Crazyman32 said…

I think it may be better in some cases to write a standard map function. I’ve written one myself.

function Map(Value, Min, Max, NewMin, NewMax)
	local Ratio = (Value - Min) / (Max - Min)
	local ScaledValue = NewMax - NewMin
	local NewValue = ScaledValue * Ratio
	return NewValue + NewMin
end

It is exactly the same as the one Arduino has - including that a minimum value can be larger than a maximum. I was using it for dynamic UI scaling in a ScrollingFrame where I needed the elements inside to dynamically change size so that they always appeared the same size when using the Scale values.

3 Likes