Need help making a mini map!

I want to make a mini map GUI like phantom forces where is displays enemies nearby. I have looked at many tutorials on YouTube and on the DevForum and couldn’t find what I wanted. If you know a tutorial I can use to achieve this I will be much appreciated thanks.

3 Likes

Try this out ROBLOX | How to make an Radial Map! - YouTube Best part is it utilizes viewport frames

How I do it is I have this 2d identity matrix with a 1 representing a player. That being updated by the players position from the client then being replicated to the server every time they move x blocks. Viewport frames could work but I dont think thats what you want

I can try to throw together a bit of a tutorial here:

  1. Create your minimap GUI. This can be sized with scale or offset, whatever you prefer for your game. Just make sure to take note of its sizing. This is all done in a local script btw.
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")

local gui = Instance.new("ScreenGui") -- create main gui
gui.Name = "MiniMap"

local mapFrame = Instance.new("Frame") -- make actual map
mapFrame.Name = "MapFrame"
mapFrame.Size = UDim2.fromScale(0.2, 0.2)
mapFrame.AnchorPoint = Vector2.new(0,1)
mapFrame.Position = UDim2.fromScale(0.05,0.85)
mapFrame.BorderSizePixel = 0
mapFrame.BackgroundTransparency = 0.3
mapFrame.BackgroundColor3 = Color3.fromRGB(58, 58, 58)

local ratioConstraint = Instance.new("UIAspectRatioConstraint") -- keep map square

ratioConstraint.Parent = mapFrame
mapFrame.Parent = gui
gui.Parent = PlayerGui

local playerDot = Instance.new("Frame") -- create the player markers for the map
playerDot.Size = UDim2.fromScale(0.05,0.05)
playerDot.BorderSizePixel = 0

local round = Instance.new("UICorner") -- make dot round
round.CornerRadius = UDim.new(1,0)
round.Parent = playerDot

local selfDot = playerDot:Clone()
selfDot.Position = UDim2.fromScale(0.5,0.5)
selfDot.Parent = mapFrame

local sameTeamDot = playerDot:Clone()
sameTeamDot.BackgroundColor3 = Color3.fromRGB(0, 255, 0) -- make teammates green

local enemyTeamDot = playerDot:Clone()
enemyTeamDot.BackgroundColor3 = Color3.fromRGB(255, 0, 0) -- make enemies on map red
  1. Figure out your constants. These include the map radius and how often the map is updated.
local MAP_RADIUS = 100 -- how many studs the edge of the map should be from center
local TIME_BETWEEN_CHECKS = 3 -- how long to wait between map pings
  1. Make the function that updates the player positions on the map relative to the current player and their look direction.
function UpdateMap() -- main function to update the map
	for _,player in ipairs(Players:GetPlayers()) do
		if player ~= LocalPlayer then  -- might want to implement some kind of check here to see if player is playing
			local otherChar = player.Character
			local myChar = LocalPlayer.Character
			if otherChar and myChar then
				local myHRP = myChar.PrimaryPart
				local otherHRP = otherChar.PrimaryPart
				if myHRP and otherHRP then
					
					local diff = otherHRP.Position - myHRP.Position -- get vector diff
					local rotated = myHRP.CFrame:vectorToObjectSpace(diff) -- rotate based on look direction

					local relX = rotated.X -- size to side
					local relZ = rotated.Z -- forward

					local guiPosX = relX / (MAP_RADIUS * 2) + 0.5 -- get scale location to place dot
					local guiPosY = relZ / (MAP_RADIUS * 2) + 0.5
					
					if guiPosX > 1 then -- adjust for out of bounds
						guiPosX = 1
					elseif guiPosX < 0 then
						guiPosX = 0
					end
					
					if guiPosY > 1 then
						guiPosY = 1
					elseif guiPosY < 0 then
						guiPosY = 0
					end
					
					local playerDot
					if player.Team == LocalPlayer.Team and player.Team ~= nil then -- determine if friendly
						playerDot = sameTeamDot:Clone()
					else
						playerDot = enemyTeamDot:Clone()
					end
					
					playerDot.Position = UDim2.fromScale(guiPosX, guiPosY) -- set pos
					playerDot.Name = "playerDot"
					playerDot.Parent = mapFrame
				end
			end
		end
	end
end
  1. Create the loop and clear the dots every iteration.
function ClearMap() -- get rid of old dots
	for _,player in pairs(mapFrame:GetChildren()) do
		if player.Name == 'playerDot' then
			player:Destroy()
		end
	end
end


while true do -- continually update
	UpdateMap()
	wait(TIME_BETWEEN_CHECKS)
	ClearMap()
end

Result:


Full Code:

--[[
Written by Xyphur
2/2/21
]]

local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild("PlayerGui")

local gui = Instance.new("ScreenGui") -- create main gui
gui.Name = "MiniMap"

local mapFrame = Instance.new("Frame") -- make actual map
mapFrame.Name = "MapFrame"
mapFrame.Size = UDim2.fromScale(0.2, 0.2)
mapFrame.AnchorPoint = Vector2.new(0,1)
mapFrame.Position = UDim2.fromScale(0.05,0.85)
mapFrame.BorderSizePixel = 0
mapFrame.BackgroundTransparency = 0.3
mapFrame.BackgroundColor3 = Color3.fromRGB(58, 58, 58)

local ratioConstraint = Instance.new("UIAspectRatioConstraint") -- keep map square

ratioConstraint.Parent = mapFrame
mapFrame.Parent = gui
gui.Parent = PlayerGui

local playerDot = Instance.new("Frame") -- create the player markers for the map
playerDot.Size = UDim2.fromScale(0.05,0.05)
playerDot.BorderSizePixel = 0

local round = Instance.new("UICorner") -- make dot round
round.CornerRadius = UDim.new(1,0)
round.Parent = playerDot

local selfDot = playerDot:Clone()
selfDot.Position = UDim2.fromScale(0.5,0.5)
selfDot.Parent = mapFrame

local sameTeamDot = playerDot:Clone()
sameTeamDot.BackgroundColor3 = Color3.fromRGB(0, 255, 0) -- make teammates green

local enemyTeamDot = playerDot:Clone()
enemyTeamDot.BackgroundColor3 = Color3.fromRGB(255, 0, 0) -- make enemies on map red

local MAP_RADIUS = 100 -- how many studs the edge of the map should be from center
local TIME_BETWEEN_CHECKS = 3 -- how long to wait between map pings

function UpdateMap() -- main function to update the map
	for _,player in ipairs(Players:GetPlayers()) do
		if player ~= LocalPlayer then  -- might want to implement some kind of check here to see if player is playing
			local otherChar = player.Character
			local myChar = LocalPlayer.Character
			if otherChar and myChar then
				local myHRP = myChar.PrimaryPart
				local otherHRP = otherChar.PrimaryPart
				if myHRP and otherHRP then
					
					local diff = otherHRP.Position - myHRP.Position -- get vector diff
					local rotated = myHRP.CFrame:vectorToObjectSpace(diff) -- rotate based on look direction

					local relX = rotated.X -- size to side
					local relZ = rotated.Z -- forward

					local guiPosX = relX / (MAP_RADIUS * 2) + 0.5 -- get scale location to place dot
					local guiPosY = relZ / (MAP_RADIUS * 2) + 0.5
					
					if guiPosX > 1 then -- adjust for out of bounds
						guiPosX = 1
					elseif guiPosX < 0 then
						guiPosX = 0
					end
					
					if guiPosY > 1 then
						guiPosY = 1
					elseif guiPosY < 0 then
						guiPosY = 0
					end
					
					local playerDot
					if player.Team == LocalPlayer.Team and player.Team ~= nil then -- determine if friendly
						playerDot = sameTeamDot:Clone()
					else
						playerDot = enemyTeamDot:Clone()
					end
					
					playerDot.Position = UDim2.fromScale(guiPosX, guiPosY) -- set pos
					playerDot.Name = "playerDot"
					playerDot.Parent = mapFrame
				end
			end
		end
	end
end

function ClearMap() -- get rid of old dots
	
	for _,player in pairs(mapFrame:GetChildren()) do
		if player.Name == 'playerDot' then
			player:Destroy()
		end
	end
	
end


while true do -- continually update
	UpdateMap()
	wait(TIME_BETWEEN_CHECKS)
	ClearMap()
end
9 Likes

Do I just need to make a GUI and add the script to it??

This script makes the gui. All you’d need to do is put this code in a local script in StarterPlayerScripts. Then if you’re not using Roblox’s native team objects for your player teams, you need to change the line of code that detects teams to use whatever you’re using. But if you are using Roblox’s teams, it should work as is.

1 Like

Okay thanks this helped me a lot

1 Like