Player radar misalignment

I am currently making a minimap with player visibility, but I’m struggling with converting the player’s 3D position into a 2D UI.

Left: Player 1, Right: Player 2
But as you can see, they both display the wrong positions of other players

viewportMap.CFrame = lookAt(actor.rootpart.CFrame.Position + v3(200, 200, -200), actor.rootpart.Position) -- Viewport camera

local rootpart = plr.Character:FindFirstChild("HumanoidRootPart")
local screenPos, onScreen = viewportMap:WorldToViewportPoint(rootpart.Position) -- I think this is where the issue is
gui.Position = ud2(screenPos.X, 0, screenPos.Y, 0)
gui.Visible = onScreen
1 Like

bumping this i still cant figure out

1 Like

It looks like the camera is staying centered on each player which I expect is what you want so your viewportMap.CFrame is likely fine. I presume actor is Player 1 and plr is Player2 relative to each.

Just a guess, maybe you need to offset the Player 2 position in the minimap relative to the Player 1 position or vice versa before getting the :WorldToViewportPoint.

local p2 = actor.rootpart.Position - rootpart.Position
local screenPos, onScreen = viewportMap:WorldToViewportPoint(p2)

You may also have to include the camera offset from Player 1 for Player 2. i.e. p2 = actor.rootpart.CFrame.Position + v3(…) - rootpart.Position

From what I’m reading here, another approach would be to use ViewportFrames and have a part (marker) that follows the players. Parent the part ot the viewport and the main camera won’t render the part but the mini map camera will.

1 Like

like this?

local screenPos, onScreen = viewportMap:WorldToViewportPoint(actor.rootpart.CFrame.Position + v3(200, 200, -200) + rootpart.Position)

it doesn’t work though… it gives me this result in single player mode
1.568946123123169, 4.818820476531982, -1590.7508544921875 when it should be 0.0.0

that actually sounds like a really good alternative! but would I able to make the part show the frame (marker)?

1 Like

Did you try it without the offset and if so where did the respective other players marker show at?

local p2 = actor.rootpart.Position - rootpart.Position --creates a Vector3 from player1 position - player2 postion

local screenPos, onScreen = viewportMap:WorldToViewportPoint(p2) --uses the p2 vector as the world point for player2

Why are you trying to show the point for player2 in single player? I think seeing a little bit more of your code could help.

Each player has a copy of this script that’s displaying it’s minimap?

How many players are there that you want markers for?
From what I can see the current setup should only work for exactly two players, otherwise you need to loop over a list of all players or not run the code at all if in single player.

As for the viewportframes, it would replace your current minimap frame and shows it’s version of the world that only includes the parts parented to the frame.

I haven’t tried this setup to be sure but it should go something like.
-Add a ViewportFrame, position it (probably pointing at the player), move in-place of the current minimap, hide/remove the current minimap frame, duplicate your map object and parent it to the new viewportFrame, at this point your duplicated map (but nothing else) should be showing in the frame.
-Next add a red sphere (or whatever you want to serve as visual marker for the players) and parent it to the frame. Now that red ball will also show up in the frame (won’t do anything yet) but not in the “normal” world because we didn’t duplicate it (like the map), we just parented it diectly to the frame which makes that part visible only in the frame.
-The next steps would be to remove the red ball added previously for example purposes, have each player or the server create a clone of the marker when the player joins and keep it informed of the players position. Probably Connect to the RunServices HeartBeat and run the code in there.

marker.Position = player.Position

Now the marker(s) should move around the map in the frame in the same way as the player does, all on it’s own, you won’t need to :WorldToViewportPoint(), it just shows what’s going on in the mini version of the world, be it one or twenty players. Of course, if this is done client side it’s open to exploits but it should work either way.

In Unity, you can define renderlayers and have a camera only show objects assigned to that renderlayer. In this case I would have attached the red sphere (with no collider) directly to the player and set it’s renderlayer to only the minimap layer, which is the only layer the minimap camera would be displaying (the main camera would be set to ignore the minimap layer). I’d also include the terrain/map in the that renderlayer. This way the players in game don’t see the red ball marking their position (It’s there they just can’t see it) but the minimap camera (floating somewhere above the player) can see the map and the player markers but not the players themselves, showing them just as they are on the map.

Using a ViewportFrame in Roblox is the same sort of idea, the frame is the layer and parts parented to the frame are only visible in that frame. The extra you have to do here vs in Unity is coordinate the movements between the player and it’s marker because the marker isn’t directly attached to the player like it is in Unity.

Anyway, hope this helps a bit. When I get some more time I’ll try to get a working example posted.

Yes, each of them have their own individual minimap.

Sorry for my lack of explaination, I’ll now show you the full code

local playerMarkers = {}
local playerMarker = ui.minimap:WaitForChild("Template"):WaitForChild("PlayerMarker")

function ui:AddPlayerMarker(plr: Players)
	if not playerMarkers[plr] then
		local playerMarker = playerMarker:Clone()
		playerMarker.Name = plr.UserId
		playerMarker.PlayerName.Text = plr.DisplayName
		playerMarker.Parent = ui.minimap
		playerMarkers[plr] = playerMarker
	end
end
	
function ui:RemovePlayerMarker(plr: Players)
	playerMarkers[plr]:Destroy()
	playerMarkers[plr] = nil
end

game.Players.PlayerAdded:Connect(functinon()
	ui:AddPlayerMarker(player)
end)
game.Players.PlayerRemoving:Connect(function(player)
	ui:RemovePlayerMarker(player)
end)

This is how the player marker is set up, which is meant to support more than 2 players.

Everything from here is ran in a loop:

viewportMap.CFrame = lookAt(actor.rootpart.CFrame.Position + mapOffset, actor.rootpart.Position)

This is how the minimap camera is set up, which basically offsets from the player’s rootpart position.
actor.rootpart. is the player’s rootpart.

Then, it is placed in a loop where it constantly checking the player’s location whereabouts and positioning them where they are supposed to be.

for player, gui in pairs(playerMarkers) do
	if not player.Character then return end	
	local rootpart: Part = player.Character:FindFirstChild("HumanoidRootPart")
	local hum: Humanoid = player.Character:FindFirstChild("Humanoid")
	if not hum or not rootpart then return end
	local screenPos = viewportMap:WorldToViewportPoint(rootpart.Position) 
	gui.Position = UDim2.fromScale(screenPos.X, screenPos.Y) -- this is the issue i think
end

Basically. the loop is constantly putting player’s V3 position to their respective 2D position. However, I am still unsure why the positioning isn’t accurate.

Thanks for giving the suggestion. Indeed it is a good alternative, but I do want the marker to fase through walls.

local target = minimapCam:WorldToViewportPoint(rootpart.Position)
local origin = minimapCam:WorldToViewportPoint(actor.rootpart.Position)
local offset = target - origin
gui.Position = UDim2.fromScale(offset.X + .5, offset.Y + .5)

I have tried every method and searched through the forums but to no avail, this is the closest I can get, though it is still VERY inaccurate.

nvm it is as equally inaccurate as the previous steps, I give up

I haven’t watched it all but Suphi is usually on point with his stuff. He has a video on making a minimap which may give you some insight as to what’s going on. Minimap - Roblox Scripting Tutorial, hope it helps.