Introduction: This is going to be a complex UI
Making a map like this will involve a complex UI. You were on the right track when you were using a ScrollingFrame. However, I think you might have run into problems when trying to do the mathematics to transform positions in the world to positions that could be used to position icons on the UI.
My post aims to teach how to conduct the math for these transformations. Of course, creating a complete map like will require more code to create each icon, and, if you want it to show player ship positions, code to update the positions of player icons every frame. However, this should get your math sorted.
Position Transformations
For calculating the positions of the icons on the screen, there is absolutely no need to do advanced raytracing or anything like that. Raytracing would be OVERKILL for something like this. Raytracing involves casting a ray for every pixel on the screen. We don’t need to raytrace because we already know the position of every object we want to place on the map just from its position in the world.
If I’m understanding this correctly, all you want to do is make a reduced representation of a 3d game world on a 2D plane. In other words, we need to map the X and Z coordinates of objects within the game world to X and Y coordinates on a map GUI. All that we need to do this is some pretty trivial transformation math.
Say I have a scrolling UI frame of a set canvas size. To render this map, I will need to create a frame/ui element for each object of interest, be it a planet, moon, or ship. Then, I need to have some way to transform the objects in the 3d world to UDim2 coordinates that represent an offset from the canvas’s origin.
We can use a Linear Mapping operation to map a value from one range to another. I talked about this in another response, but another application will really show its versatility.
--[[
Source from RosettaCode:
@param a1 (number) The lower bound of the range to map from
@param a2 (number) The upper bound of the range to map from
@param b1 (number) The lower bound of the range to map to
@param b2 (number) The upper bound of the range to map to
@param s (number) The value in the range [a1,a2] to be mapped to [b1,b2]
@returns (number) The value 's' mapped from [a1,a2] to [b1,b2]
--]]
function map_range( a1, a2, b1, b2, s )
return b1 + (s-a1)*(b2-b1)/(a2-a1)
end
We can use this function to create a more specialized function that maps the position of objects in the bounds of the game world to a position in the bounds of a UI. But before we can do that, you need to define what the bounds of the game world are. Objects outside this range will not render correctly (unless you write code to handle that, but that will be left as an exercise for the reader), so be sure to pick a minimum and maximum position that bounds the entire game world. The following code sets such constants to a 2000x2000x2000 box.
-- This constant will define the minimum position of the game world.
local MIN_POSITION = Vector3.new(-1000,-1000,-1000)
-- This constant will define the maximum position of the game world.
local MAX_POSITION = Vector3.new(1000,1000,1000)
Now that we have our bounds, we can write a function that transforms a position in the game world to a position on the screen. We can’t render in 3 dimensions on a standard flat UI, so we will just ignore every object’s Y coordinate, opting to use X and Z instead.
function TransformWorldPositionToUIPosition(position : Vector3, canvasSizeX : number, canvasSizeY : number)
local xCoordinateOnUI = map_range(MIN_POSITION.x, MAX_POSITION.x, 0, canvasSizeX, position.x)
local yCoordinateOnUI = map_range(MIN_POSITION.z, MAX_POSITION.z, 0, canvasSizeY, position.y)
return UDim2.new(0, xCoordinateOnUI, 0, yCoordinateOnUI)
end
This function should give us the position of where an object of interest in the 3d world should be on the 2D map.
Zooming - More Transformation Math
I’m about out of time and need to get back to studying, but if you want to know how to further implement zoom transformation math like what was displayed in your example gif, I’m happy to give a follow-up post.
Happy programming!