Math equation where Y is negative when X is outside of a range?

Are there any math equations that will give a negative number when outside of a range, and a positive number when inside?

For example, if the range is 0.5 - 0.75, and the input is 0.3 or 0.8, it should return negative. If the input is 0.6 or 0.7, it should return positive.

This is for a script that plays a music track depending on your distance to the target (similar to Forsaken, or Dead by Daylight). Each layer should smoothly blend into the next as you approach the music source.
I know I can do this with if-then logic, and I’ve already done that, but the code is pretty messy and I would like to do something more simple.

This is exactly what SDFs (signed distance fields/functions) are for!

2 Likes

this should suit your problem:
f(x) = (x - a) * (b - x)
it’s an upside-down parabola, A and B being the zeros
also love the avatar what a throwback

edit:
here’s a video displaying it, in your case you should normalize it with a math.clamp() from 0 to 1 aswell

3 Likes

thank you so much! i’ll look into it and see if i can make it work. i’ll mark this as solved once i figure it out

i just tried to understand this a second ago. super cool topic!! i may incorporate your idea somewhere down the line. :speaking_head: :fire:

-- x = magnitude (distance from the music source.)
-- a = range start
-- b = range end
local function insideRangeValue(x, a, b)
    local value = (x - a) * (b - x)
    local inside = value >= 0 -- boolean. >= 0 means its inside, anything negative is outside
    return value, inside
end
2 Likes

this helps a ton thank you ^^ it doesn’t really ease in/out evenly, but it cuts down on a ton of the code’s bulk.
i could probably modify the function to make the easing consistent but i’m not fully sure how to do that lol

yeah, it’ll definitely be a bit rough around the edges. if you’re open to using a function that returns the volume instead, i can write one that smooths out the edges real quick

1 Like

actually, try this equation out:

y = ((x-a)^2)((b-x)^2) * 20

1 Like

the smoothing on it seems a lot better, but the output skyrockets a little bit after it leaves the range.

the way the music works right now is that i use this function

function percentage(input, min, max)
return ((input - min)) / (max - min)
end

to get the “closeness” of the player to the monster in the range of its music. if the outer layer starts at 100 studs and i’m 50 studs away, then it sets “closeness” to 0.5.

for example, if the player’s “closeness” is 0.1 and the monster’s first layer of music spans from 0-0.5, then the “layerCloseness” is set to 0.2.

percentage(0.1 0, 0.5) == 0.2

then i check if the the closeness is within the “blend amount”. if it is, i use the percentage function on the layerCloseness and the blend amount to get the final volume.
if layerCloseness is greater than the start of the layer + the blend amount, and less than the end of the layer - the blend amount, then it’s set to 1

percentage(0.2, -0.25, 0.25) == 0.9

it works but it’s not very pretty LOL

this is the code for the blending, it’s just some light math and a ton of if-statements :sob:

layer.Percent is the final volume of the layer, and the volumes are set in the next line.

i’ve made it so that there can be any number of layers to a monster’s music, all at arbitrary intervals, just for maximum flexibility.

	for i,layer in pairs(layers) do
		local layerPercentage;
		local firstLayer, lastLayer = i==1, i==#layers
		local blendStart, blendEnd = (not firstLayer), (not lastLayer)
		layer.Percent = 0

		
		if (firstLayer and lastLayer) then
			layerPercentage = eased_closeness
		elseif (not lastLayer) then
			layerPercentage = percentage(eased_closeness, layer.UnitRadius, layers[i+1].UnitRadius)
		else
			layerPercentage = percentage(eased_closeness, layer.UnitRadius, 1)
		end
		

		if layerPercentage ~= 0 then
			if (not blendStart) and (layerPercentage < blendAmount) then
				layer.Percent = percentage(layerPercentage, 0, blendAmount)
			elseif blendStart and (layerPercentage < blendAmount) then
				layer.Percent = percentage(layerPercentage, blendAmount*-1, blendAmount)
			elseif blendEnd and (layerPercentage > 1 - blendAmount) then
				layer.Percent = 1 - math.clamp(percentage(layerPercentage, 1 - blendAmount, 1 + blendAmount), 0, 1)
			elseif (layerPercentage > blendAmount and layerPercentage < 1 - blendAmount) or not blendEnd then
				layer.Percent = 1
			end
		else
			layer.Percent = 0
		end
		
		layers[i] = layer
	end

if there’s a function that can ease from 0-1 and 1-0 in the first/last % of a range, and then smooth back into 0 or a negative number as it goes away from both ends, that could possibly shrink this thing down to a few lines.

here’s a quick example of what i’ve done/what i’m trying to achieve with a different method

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.