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
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:
- 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
- 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
- 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
- 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