Lua map() command

,

Hello,

Currently, while developing UI in Roblox, I find myself having to somehow convert different values of a specific range into values of another range. This can be tedious and not so easy to do with specific things.

I would like to have an inbuilt function to take care of this for me. Similar to the p5.js framework, there is a command known as map()

This command takes 5 arguments. (With an optional 6th).

  1. The iterator (could be the actual value such as mouse’s position)
  2. Minimum value for the mouse’s range
  3. Maximum value for the mouse’s range
  4. New minimum value for the mouse’s range to be mapped to
  5. New maximum value for the mouse’s range to be mapped to
  6. bool value to constrain the mapped value to the range set (just means that if you give a value less/more than the given bounds for that item, it will just return the minimum instead of a number outside the bounds of the new range.

The 6th value is optional and defaults to false, as long as your given iterator is within the given range for that iterator, there will be no problems.

I have recreated the code for this command in lua below:

Map Command Code
--// maps a given range from a specific iterator to a new range
local function map(n, start, stop, newStart, newStop, withinBounds)
    local value = ((n - start) / (stop - start)) * (newStop - newStart) + newStart
    
    --// Returns basic value
    if not withinBounds then
        return value
    end
    
    --// Returns values constrained to exact range
    if newStart < newStop then
        return math.max(math.min(value, newStop), newStart)
    else
        return math.max(math.min(value, newStart), newStop)
    end
end

for i = 0, 600 do
    print(map(i, 0, 600, 0, 255, true))
    -->> Outputs the range 0-600 mapped between 0-255
end

I feel as though this function would be a very useful addition for graphical artists on Roblox as well as backend developers wishing to make their games work just this little bit more efficiently.

A quick use-case off the top of my head could be if a graphical user wanted to assign the mouse’s position within the screen to set the colour of the background between black and white or whatever colour range they wished. As they moved the mouse from 0 to 1000, they could get the mapped value of the mouse’s position between 0-255 so that they could get a gradient mapped over the whole x-axis of the screen.

Or a developer could use it to make simple harmonic motion with UI elements. A quick sketch up could look like this:

Harmonic Motion sketch
local angle = 0

while wait() do
    
    local h = map(math.sin(angle), -1, 1, 0, 1)
    uiElement.Size = UDim2.new(.1,0,h,0) 
    
    angle = angle + 0.1
end

All feedback is welcome.

Sincerely,
RoyallyFlushed

12 Likes

I don’t really see the efficiency gain in using this function (when done on the C-side of things). You’re still using a for-loop, the body of the loop doesn’t appear to do very intensive things to make a significant difference.

The keyword map itself seems rather ambiguous as well. Reading the title I assumed it would be a function to iterate over a list and execute given function f for each element instead of this.

1 Like

when I said efficiently, I was referring to the actual development of writing code.

As for the name, I’m using the exact name that the well known & popular p5.js version uses. I think the name is fine and doesn’t need changing.

Oh and I’m fairly sure you’re thinking of the map command often used for arrays. If that were the case, I’d suggest making that command under the table table.

Wikipedia for ‘map’ in languages with first-order functions results in the implementation I described;

If the usecase for your proposed ‘map’ is mostly UI-based, same could be said for that. Taking into account the ambiguous nature and its limited use I’d not consider it a good idea to add it as global token with your described functionality.

1 Like

Like I said, you’re thinking of a completely different map function.

That function, should it be included in lua would go under table.map() as it is a function acting on a given array. The function I’m describing is completely different and wouldn’t come under and subsection.

It is not limited to lists/arrays, as described in the wikipedia page.

The Use cases aren’t specifically linked to UI. The function only returns a given range set to a desired range. I was just giving random use cases as mentioned in the post.

" The concept of a map is not limited to lists: it works for sequential containers, tree-like containers, or even abstract containers such as futures and promises."

Pretty much all lists but in different ways.

Vector3 is not a table type, it could work with those. I think there are plenty of similar examples where it’s not Lua-type table since there are many types of userdata it could apply to.

Regardless, my initial and final point is that the use is not clear from the naming convention, for which reason I don’t consider it a good idea to add as global token.

p5.js has both types of maps and the one described in the original post is a global function and the one you’re describing is a sub function of a table.

They have had no issues and so it’s pretty safe to presume we won’t either.

1 Like

Point is, doesn’t really matter where it goes, it could go in math.map() I’m more interested about whether or not it will be introduced.

You seemed rather intent on getting it included in the global scope. My only concern is the ambiguity of it in that case, if it’s within a library then I have no concerns.

I don’t have a preference of where it goes. I was just making the point that I didn’t think it made much of a difference as per the example being p5.js.

I use this a lot:

-- Maps a number from one range to another:
-- [in_min, in_max] -> [out_min, out_max]
function map(x, in_min, in_max, out_min, out_max)
	return out_min + (x - in_min)*(out_max - out_min)/(in_max - in_min)
end

I can see the use of adding it as math.map. Not a fan of the clamping option; that’s what math.clamp is for.

9 Likes

Forgot clamp was a thing. I just re-created this as the constrain() function which is also available in p5.js

Hopefully they add this into the framework. I also, on a second note, wish they would add in the bit32 sub-section as well so I can do bitshifts, bit masking and much more.

Add your use case to this thread + add a like to the first post so it’s not lost on an unrelated topic:

It’s been added to Luau in release 648!!

4 Likes