How would I get the world position of a GUI properly?

Hi! I’m making a system where if you click anywhere on the minimap, there will be a part created in the world at that place, I’m close to finishing it, but sometimes it doesn’t position the in-world part properly, sometimes it does, and sometimes not, here is a picture of how it works:

Here’s my code:

local GPS_BUTTON = script.Parent;

local player  = game:GetService("Players").LocalPlayer
local Mouse = player:GetMouse()

local location = script.Parent.Parent:WaitForChild("Location")

local UserInputService = game:GetService("UserInputService")

local char = player.Character or player.CharacterAdded:Wait()

local humanoid = char:WaitForChild("Humanoid")

local locations = {};

humanoid.Touched:Connect(function(hit)
    if hit.Name == "GPS" then
        hit:Destroy()

        for index, location in ipairs(locations) do
            location:Destroy()
        end

        locations = {}
    end
end)

GPS_BUTTON.MouseButton1Click:Connect(function()
    if game.Workspace:FindFirstChild("GPS") then return end

    local minX, minY = GPS_BUTTON.AbsolutePosition.X, GPS_BUTTON.AbsolutePosition.Y

    local maxX, maxY = minX + GPS_BUTTON.AbsoluteSize.X, minY + GPS_BUTTON.AbsoluteSize.Y

    local mouseX = math.clamp(UserInputService:GetMouseLocation().X, minX, maxX)

    local mouseY = math.clamp(UserInputService:GetMouseLocation().Y, minY, maxY)

    local xPixel, yPixel = (maxX - minX), (maxY - minY)

    local xPos = (mouseX - minX) / xPixel

    local yPos = (mouseY - minY) / xPixel

    local scale = UDim2.new(xPos, 0, yPos, 0)


    local newLo = location:Clone()

    table.insert(locations, newLo)

    newLo.Visible = true

    newLo.Position = scale

    newLo.Parent = location.Parent

    local anotherLo = newLo:Clone()

    anotherLo.Visible = true

    anotherLo.Size = UDim2.new(0.116, 0,0.111, 0)

    anotherLo.Position = scale

    anotherLo.Parent = GPS_BUTTON.Parent.Parent.Frame.Map

    table.insert(locations, anotherLo)

    local Raycast = game.Workspace.CurrentCamera:ScreenPointToRay(newLo.AbsolutePosition.X, newLo.AbsolutePosition.Y, 0)

    local Ray = Ray.new(Raycast.Origin, Raycast.Direction * 100)

    local hit, pos = game.Workspace:FindPartOnRayWithIgnoreList(Ray, {char})

    local PART = Instance.new("Part")

    PART.Size = PART.Size + Vector3.new(0, 20, 0)
    
    pos = Vector3.new(pos.X, 10 , pos.Z)
    
    PART.Position = pos

    PART.Anchored = true

    PART.Parent = game.Workspace

    PART.CanCollide = false

    PART.Transparency = 0.5

    PART.Name = "GPS";
end)

I know I have made a post about this before, but I didn’t get any help, I tried to search but no luck at all.

Any help that solves my problem will save my day, Thanks. :metal:

Sorry I don’t understand what the problem is. So you want the grey part to spawn where the “Location” Textlabel is on the GUI map?

1 Like

Yes, exactly. Thanks for understanding

2 Likes

Could you explain the purpose of this line? Wouldn’t it create a ray from where the camera is facing. But say your character is on the right side of the map, and you click on the left side of the map wouldn’t it get messed up? Sorry, I might be misunderstanding how ScreenPointToRay works.

1 Like

Yeah, it gets messed up. I don’t know any other way of achieving this other than using ScreenPointToRay.

Here is just an idea. Say the real map is 1000 studs by 1000 studs, if on the map they press down on Udim2.new(0.5,0,0.5,0), then you know that on the map they pressed on 500 studs by 500 studs. As the player walks around the map, do you move the UI map too? If so then you might have to compensate for the changed position of the map, I could help you with that.

How would I do this in the script? I have no idea. I’ve been trying this for about 7 hours now.

I gtg, I’ll be right back in 3 minutes and I’ll show you how you could do it. I’ve never done this before but I’ll try my best.

1 Like

Alright. Thanks for showing up on the post.

2 Likes

First I would measure how big the map is in studs. At the top make a variable for the x and z studs. Then you already are able to find the scale of the picture, so you can just use that same scale to find the position on the map.


--top of script
local mapXSize = --number (how wide in studs the X axis of the map is)
local mapZSize = --number (how wide in studs the Z axis of the map is)
local mapXAnchor = --number (the x position where the top left of the map starts)
local mapYAnchor = --number (the z position where the top left of the map starts)


--delete these lines:

    local Raycast = game.Workspace.CurrentCamera:ScreenPointToRay(newLo.AbsolutePosition.X, newLo.AbsolutePosition.Y, 0)

    local Ray = Ray.new(Raycast.Origin, Raycast.Direction * 100)

    local hit, pos = game.Workspace:FindPartOnRayWithIgnoreList(Ray, {char})


--replace those lines with:

local mapX = (mapXSize/ xPos) + mapXAnchor --take the maps size, divide by where they clicked, and add that to the anchor point
local mapZ = mapZAnchor - (mapXSize/ xPos)

Okay. for real, I am an idiot at calculating. Is mapXSize is Map.Size.X.Scale? and same with the anchors?

Also I appreciate how you typed that whole thing for me.

No problem :slight_smile: . Basically we want to find the size of the real map in studs. Then whenever they click on the GUI we can calculate that position in the 3d workspace by detecting where the GUI was clicked. Pretend you inserted a part, and you made the size reach over the whole map. The “mapXSize” is the X value of the part’s size, and the mapZSize is the Z value of the part’s size.

Misunderstood that. What about the anchor point?

Here is a visual to help you understand. Basically we use the mapXSize and the mapZSize variables to calculate how big the map is. Then say they click in the middle of the GUI, we put the part in the middle of the map. Sorry I misdrew the right map. It’s supposed to say “They clicked (0.5,0,0.25,0)”

Yeah I got that one, but one question. Do I calculate the anchor point from the map or from the GUI?

The anchor point variables are the top left of the real map. So it would be where on the X axis is the top left of the map and where on the Z axis is the top left of the map. If the top left of the map was the origin, then both of the anchor points would be 0. But say the top left point of the map was Vector3.new(50,0,100) then the mapXAnchor point would be 50, and the mapZAnchor would be 100.

Edit: Also I have to go in 5 minute but I can help you until then, and I can help you later.

OH, I position a part at the top left of the map, and get the X and Z position?

Also, are the mapX, and mapY are the variables for in-world position?

Correct!

Yes, mapX and mapY are the coordinated for where the part should go. Once we have those coordinates we can set the marker’s position to:

local mapX = (mapXSize/ xPos) + mapXAnchor --take the maps size, divide by where they clicked, and add that to the anchor point
local mapZ = mapZAnchor - (mapXSize/ xPos)
local pos = Vector3.new(mapX, 0, mapZ)
part.Position = pos

Alright! Thanks for the help, I got every variable done… Now it’s time to try and see if it works. If this works then thank you so much x1000, if no then good game.