Incorrrect Icon Positioning on Minimap

I have a script that controls a minimap with icons.

The script for the most part works, however the positioning of the icons breaks if the viewport’s X and Y are not equal. Essentially if its anything besides a perfect square the icons are positioned incorrectly.

If the minimap IS a square, the positioning is as intended.

I tried searching for similar topics but couldn’t find anything that relates to my specific problem of the positioning being incorrect only if the viewport isn’t a square.

Any help is appreciated

Code:

local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local RP = char:WaitForChild("HumanoidRootPart")

local PlrUi = player.PlayerGui
local MinimapGUI = PlrUi:WaitForChild("Minimap")

local Viewport = MinimapGUI:WaitForChild("ViewportFrame")
local newCam = Instance.new("Camera")

for i, object in pairs(game.Workspace:GetDescendants()) do
	if object:IsA("BasePart") then
		if object:IsA("Terrain") then continue end
		if object:IsA("Accessory") then continue end
		if object.Parent:FindFirstChild("Humanoid") then continue end
 		local part = object:Clone()
		part.Anchored = true
		part.Parent = Viewport
	end
end

for i, object in pairs(game.Workspace.MapIcons:GetChildren()) do
	local newIcon = script.IconTemplate:Clone()
	newIcon.Text = object.Name
	newIcon.AnchorPoint = Vector2.new(0.5, 0.5)
	newIcon.Name = object.Name
	newIcon.Parent = Viewport.Icons
end

Viewport.CurrentCamera = newCam

local ViewportX = Viewport.AbsoluteSize.X
local ViewportY = Viewport.AbsoluteSize.Y

local ViewportPosition = Viewport.AbsolutePosition
	

game["Run Service"].RenderStepped:Connect(function()
	newCam.CFrame = CFrame.new(RP.Position * Vector3.new(1,0,1) + Vector3.new(0,70,0)) * CFrame.Angles(math.rad(-90),0,0)
	
	ViewportX = Viewport.AbsoluteSize.X
	ViewportY = Viewport.AbsoluteSize.Y
	
	local FaceNorthLV = game.Workspace.FaceNorth.CFrame.LookVector
	local RPLV = RP.CFrame.LookVector
	
	local Differance = FaceNorthLV:Angle(RPLV, Vector3.new(0,1,0))
	Differance = math.deg(Differance)
	
	local Cross = FaceNorthLV:Cross(RPLV)
	
	if Cross.Y < 0 then
		Differance = math.abs(Differance)
	else
		Differance = 180 + (180 - Differance)
	end
	
	Viewport.PlayerArrow.Rotation = Differance
	
	for i, icon in pairs(Viewport.Icons:GetChildren()) do
		local pos, onscren = newCam:WorldToViewportPoint(Viewport:FindFirstChild(icon.Name).Position)
		
		icon.Position = UDim2.new(0,pos.X * ViewportX, 0, pos.Y * ViewportY)
	end
end)

I found a topic from 5 years ago that fixed it for me. Here is the corrected code

local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local RP = char:WaitForChild("HumanoidRootPart")

local PlrUi = player.PlayerGui
local MinimapGUI = PlrUi:WaitForChild("Minimap")

local Viewport = MinimapGUI:WaitForChild("ViewportFrame")
local newCam = Instance.new("Camera")

for i, object in pairs(game.Workspace:GetDescendants()) do
	if object:IsA("BasePart") then
		if object:IsA("Terrain") then continue end
		if object:IsA("Accessory") then continue end
		if object.Parent:FindFirstChild("Humanoid") then continue end
 		local part = object:Clone()
		part.Anchored = true
		part.Parent = Viewport
	end
end

for i, object in pairs(game.Workspace.MapIcons:GetChildren()) do
	local newIcon = script.IconTemplate:Clone()
	newIcon.Text = object.Name
	newIcon.AnchorPoint = Vector2.new(0.5, 0.5)
	newIcon.Name = object.Name
	newIcon.Parent = Viewport.Icons
end

Viewport.CurrentCamera = newCam

local ViewportX = Viewport.AbsoluteSize.X
local ViewportY = Viewport.AbsoluteSize.Y

local ViewportPosition = Viewport.AbsolutePosition
	
local function fixAspect(xCoord)
	local viewport = Viewport.AbsoluteSize
	local viewportAspect = viewport.Y / viewport.X
	local cameraAspect = newCam.ViewportSize.X / newCam.ViewportSize.Y
	local aspectModification = viewportAspect / cameraAspect
	xCoord -= 0.5
	xCoord *= aspectModification
	xCoord += 0.5
	return xCoord
end


game["Run Service"].RenderStepped:Connect(function()
	newCam.CFrame = CFrame.new(RP.Position * Vector3.new(1,0,1) + Vector3.new(0,70,0)) * CFrame.Angles(math.rad(-90),0,0)
	
	ViewportX = Viewport.AbsoluteSize.X
	ViewportY = Viewport.AbsoluteSize.Y
	
	local XYRatio = ViewportX/ViewportY


	local FaceNorthLV = game.Workspace.FaceNorth.CFrame.LookVector
	local RPLV = RP.CFrame.LookVector
	
	local Differance = FaceNorthLV:Angle(RPLV, Vector3.new(0,1,0))
	Differance = math.deg(Differance)
	
	local Cross = FaceNorthLV:Cross(RPLV)
	
	if Cross.Y < 0 then
		Differance = math.abs(Differance)
	else
		Differance = 180 + (180 - Differance)
	end
	
	Viewport.PlayerArrow.Rotation = Differance
	
	for i, icon in pairs(Viewport.Icons:GetChildren()) do
		
		local pos, onscren = newCam:WorldToViewportPoint(Viewport:FindFirstChild("SpawnLocation").Position)
	
		local fixedX = fixAspect(pos.X)
		
		icon.Position = UDim2.new(0, fixedX * ViewportX, 0, pos.Y * ViewportY)
		
	end
end)
1 Like