How to make a phone gps

i want to make a gps system inside a ui for my game. But i have absolutely no idea how to start making it. Can anyone help me or reference a general idea on the logic and how do i make this gps system.

here’s an example

alternatively, (i prefer not to use complicated algorithms) how do i make an arrow pointing to a “destination” or a waypoint inside a ui

1 Like

Hi

What I’d start with is:

A frame containing the map itself.
The map can then be an image/whatever, however you need to make it a child of the frame and turn on ClipsDescendants for both of them, so it basically snips the map to fit the frame.

For the map, you could either use a pre-rendered image or a ViewportFrame of the map; ViewportFrames are more expensive but can update real time, however pre-rendered images are cheaper but would need to be updated every time a change is made to your map

For the player and it all to move, you’d need to be able to map the player’s location to a location of the UI; which should be pretty simple. If you know (0, 0) of the UI corresponds to, say, (-100, 0, -100) in the world and (1, 1) corresponds to (100, 0, 100), then it’s simple maths to figure out where in the world corresponds to where on the UI. You could then make it so when the player clicks on the map, it just does the maths in reverse to find where from the UI the map is in the world

Finally, to make, as you described, an arrow, its just a bit more maths. You could use CFrame:lookAt() to find how to look from the player to the destination, and then move it two studs forwards (from what i remember, cframe * CFrame.new(-2, 0, 0) to move it 2 studs forwards)

Let me know if you need any clarification or help writing the code or anything :slight_smile:

this is what i currently already have,

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local RepStorage = game:GetService("ReplicatedStorage")

local frame = script.Parent
local camera = workspace.CurrentCamera
local viewportFrame = frame.ViewportFrame
local playerIndicatorTemplate = frame.Player

local pixelsPerStud = 3.69

playerIndicatorTemplate.Parent = nil

local waypoint = workspace.Visual:WaitForChild("Node")
local waypointUI = viewportFrame.Waypoint

for _, descendant in pairs(workspace.Visual.Map:GetDescendants()) do
	if descendant:IsA("BasePart") == false then continue end
	local clone = descendant:Clone()	
	clone.Parent = viewportFrame
end

local viewportCamera = Instance.new("Camera")
viewportCamera.FieldOfView = 20
viewportFrame.CurrentCamera = viewportCamera

-- Minimap variables
local offset, chunkSize, chunkHalfSize, currentX, currentZ
local playerIndicators = {}

local function UpdateMinimap()
	local focusX = camera.Focus.Position.X / chunkSize
	local focusZ = camera.Focus.Position.Z / chunkSize
	local chunkX, chunkZ = math.floor(focusX), math.floor(focusZ)
	local x, z = focusX % 1, focusZ % 1

	if currentX ~= chunkX or currentZ ~= chunkZ then
		currentX, currentZ = chunkX, chunkZ
		local position = Vector3.new(chunkX * chunkSize + chunkHalfSize, 0, chunkZ * chunkSize + chunkHalfSize)
		viewportCamera.CFrame = CFrame.lookAt(position + offset, position, -Vector3.zAxis)
	end

	viewportFrame	.Position = UDim2.new(1 - x, 0, 1 - z, 0)
end


local function UpdatePlayers()
	local focusX = camera.Focus.Position.X / chunkSize
	local focusZ = camera.Focus.Position.Z / chunkSize

	for player, gui in pairs(playerIndicators) do
		if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
			local cFrame = player.Character:GetPivot()
			local x, z = cFrame.Position.X / chunkSize, cFrame.Position.Z / chunkSize
			gui.Position = UDim2.new(0.5 - focusX + x, 0, 0.5 - focusZ + z, 0)
			gui.Rotation = -player.Character.HumanoidRootPart.Orientation.Y
		end
	end
end

local function PlayerAdded(player)
	if player == game.Players.LocalPlayer then
		local gui = playerIndicatorTemplate:Clone()
		gui.PlayerName.Text = ""
		gui.Parent = frame
		playerIndicators[player] = gui
	else
		local gui = playerIndicatorTemplate:Clone()
		gui.PlayerName.Text = player.Name
		gui.Parent = frame
		playerIndicators[player] = gui
	end
end

-- Player leaves: Remove from minimap
local function PlayerRemoving(player)
	if playerIndicators[player] then
		playerIndicators[player]:Destroy()
		playerIndicators[player] = nil
	end
end

local function SetMinimapZoom(value)
	offset = Vector3.new(0, value, 0)
	chunkSize = offset.Y * math.tan(math.rad(viewportCamera.FieldOfView) / 2)
	chunkHalfSize = chunkSize / 2
	currentX, currentZ = math.huge, math.huge
	UpdateMinimap()
end

RunService.RenderStepped:Connect(function()
	UpdatePlayers()

	local player = Players.LocalPlayer
	local playerIndicator = playerIndicators[player]

	if player.Character and player.Character.PrimaryPart and playerIndicator then
		local direction = waypoint.Position - player.Character.PrimaryPart.Position
		local direction2D = Vector2.new(direction.X, direction.Z)

		local currentPixelsPerStud = pixelsPerStud * (offset.Y / 500) -- Adjust multiplier based on default zoom
		local posOnMap = playerIndicator.Position + UDim2.new(0, direction2D.X * currentPixelsPerStud, 0, direction2D.Y * currentPixelsPerStud)


		waypointUI.Position = posOnMap
	end
end)

SetMinimapZoom(650)

camera:GetPropertyChangedSignal("Focus"):Connect(UpdateMinimap)

for _, player in pairs(Players:GetPlayers()) do PlayerAdded(player) end
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(PlayerRemoving)

i already made all the previous steps (before the arrow one), but i still don’t understand how would i use the cframe look at to make the arrow (inside the gui), can you elaborate more?

Thanks