Issues with minimap player blips

Hey there! I’m attempting to create a minimap with a ViewportFrame, but I’m having some issues with multiple players showing up. As of now, the only player blip is the local player, not any others.

Currently how this is set up:

  • Player joins, new CFrameValue added to ReplicatedStorage
  • As the player moves, said CFrameValue updates to the player’s HumanoidRootPart position (excluding rotation)
  • LocalScript inside of the UI adds a new blip per player, and uses the CFrameValue to move the blip and roads accordingly.

Blips appear to move properly through their properties, although they don’t show up on the ViewportFrame at all.

1 Like

How are you detecting player joining? May we see some code?

Could be a ZIndex Issue with UI, or something else, but I can’t tell what the problem is from just your explanation.

1 Like

As of now, this is the server script to change all of the values based on positions. This works completely fine through my testing, it’s just the ViewportFrame not updating properly.

game.Players.PlayerAdded:Connect(function(plr)
	local PV = Instance.new("CFrameValue")
	PV.Name = plr.Name
	PV.Parent = game.ReplicatedStorage.MapPositions
	
	plr.CharacterAdded:Connect(function(char)
		local HRP = char:WaitForChild("HumanoidRootPart")
		while HRP do
			PV.Value = CFrame.new(HRP.Position.X, 768.2, HRP.Position.Z) * CFrame.Angles(0, math.rad(-90), math.rad(90))
			wait()
		end
	end)
end)

Through a local script in the UI itself, this moves the blips properly.

for i, v in pairs(game.ReplicatedStorage.MapPositions:GetChildren()) do
		local Val = v.Value
		local Dot = Mark:FindFirstChild(v.Name)
		
		if not Dot then
			local PM = script.PlayerMarker:Clone()
			PM.Name = v.Name
			PM.Parent = Mark
			
			Dot = PM
		end
		
		Dot:PivotTo(v.Value)
	end
1 Like

Why are you using :PivotTo if it is a GUI element, and are you creating the dot once the player joins on the client?

1 Like

I think the localscript can access all players, their characters and therefore their positions?

1 Like

This is a video of the map in action working with all edge cases

This is the structure I am using inside StarterGui
image

This is the code to make it happen:

local RunService 	= game:GetService("RunService")
local PlayerService = game:GetService("Players")

script.Parent.Marker.ZIndex = math.huge

local world 		= {}
world.Size 			= Vector2.new(workspace.Baseplate.Size.X, workspace.Baseplate.Size.Z)

local minimap 		= {}
minimap.Frame 		= script.Parent.Minimap
minimap.Size  		= Vector2.new(minimap.Frame.AbsoluteSize.X, minimap.Frame.AbsoluteSize.Y)
minimap.MarkerTemp  = script.Parent.Marker:Clone()

script.Parent.Marker:Destroy()

local function get_map_entries()
	local entries = {}
	
	for i, player in pairs(PlayerService:GetPlayers()) do
		pcall(function()
			local entry    = {}
			entry.Position = player.Character.PrimaryPart.Position
			entry.Player   = player


			table.insert(entries, entry)
		end)
	end
	
	return entries
end

local function world_to_map(position, marker) -- converts a worldposition VEC3 to a map pos UDIM2
	local marker_offset = UDim2.new(0, marker.AbsoluteSize.X/2, 0, marker.AbsoluteSize.Y/2)
	local conversion 	= Vector2.new(minimap.Size.X / world.Size.X, minimap.Size.Y / world.Size.Y)
	local world_offset  = UDim2.new(0, conversion.X * world.Size.X/2, 0, conversion.Y * world.Size.Y/2)
	
	return UDim2.new(0, conversion.X * position.X, 0, conversion.Y * position.Z) - marker_offset + world_offset
end

local function render()
	local map_entries = get_map_entries()
	minimap.Frame:ClearAllChildren()
	
	for i, entry in pairs(map_entries) do
		local marker = minimap.MarkerTemp:Clone()
		marker.Position = world_to_map(entry.Position, marker)
		
		if entry.Player == PlayerService.LocalPlayer then
			marker.BackgroundColor3 = Color3.fromRGB(220,50,50)
		end
		
		marker.Parent = minimap.Frame
	end
end

RunService.Stepped:Connect(function()
	render()
end)

This was just a prototype, you surely have to add your own background image to suit your map, you’ll also have to change the size of your world to whatever you want (make sure the aspect ratio of your world is the same as the one of your map, both should ideally be square!)

Hope this helps you get a sense for the topic!

I realized I forgot to explain why I chose not to approach it your way:

Having the server keep track of all players, store their positions in values, and then access those values from local scripts feels unnecessarily cumbersome. In my opinion, it’s always better to aim for solutions that are concise yet coherent.

By handling everything locally, the system becomes completely independent, which makes it simpler and more efficient overall.

I’m rendering this with physical parts instead of images, and using :PivotTo was the easiest way I could move one mass-model.

The only issue with this solution is the fact that I’m using a copied version of the current roads (makes things easier for map updates), not an image. I attempted to recreate this with how I have things set up, but to no avail.

It seems that ViewportFrames simply don’t update, unless I always have a camera being created & removed to update it.

For a couple of references, this is how I have the UI set up visually and structurally as of now.
image
image

So you want the player to always be centered, right?
Why do you move the parts then? Just reposition the camera

I attempted to move a camera around (as mentioned in my last post), but it seems any cameras inserted into ViewportFrames are instantly deleted.

I may just make a bug report for this, unless there’s another workaround.

You don’t create a camera inside the ViewportFrame, right? Instead, you place one in the workspace (for example, something like “MinimapCam”) and set the CurrentCamera property of the ViewportFrame to it.

image

From there, you modify the camera itself, not the ViewportFrame.

By the way, there are excellent resources available online to guide you:

Check them out before you proceed.

It looks something like this:

image

local RunService 	= game:GetService("RunService")
local PlayerService = game:GetService("Players")

local localplayer	= PlayerService.LocalPlayer
local camera 		= Instance.new("Camera")
local camera_offset = Vector3.new(0, 40, 0)

script.Parent.ViewportFrame.CurrentCamera = camera

RunService.RenderStepped:Connect(function()
	pcall(function()
		local plr_pos = localplayer.Character.HumanoidRootPart.Position
		camera.CFrame = CFrame.lookAt(plr_pos + camera_offset, plr_pos)
	end)
end)

I was able to get a working version of this, thank you for all of your help!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.