Circular GUI Interface Organizing Algorithm

This is a useful algorithm I was working on today that makes a circular menu, inspired by GTA

local module = {}

function module.arrangeButtons(frame, buttons)
	local buttonscale = (0.05 * (#buttons /4))
	local buttonSize = {0.3 - buttonscale, 0, 0.3 - buttonscale, 0}
	local frameSize = frame.Size
	local radius = .5 -- Assuming the frame is a square

	local function calculatePosition(index, totalButtons)
		local angleIncrement = math.pi * 2 / totalButtons
		local angle = angleIncrement * index
		local x = (radius * (math.cos(angle)*.5)) - (buttonSize[1]*.5)
		local y = (radius * (math.sin(angle)*.5)) - (buttonSize[3]*.5)
		return UDim2.new(x+.5, 0, y+.5, 0)
	end

	for i, button in ipairs(buttons) do
		button.Position = calculatePosition(i - 1, #buttons)
		button.Size = UDim2.new(unpack(buttonSize))
	end
end

return module

image
image
image
image
image

Updated post with a Model with the example interface!
Code has been updated to not use math.floor() to calculate button scale.
(Interact_Example)[https://create.roblox.com/store/asset/18108623226/Interact]

20 Likes

Works good!, i like it, maybe you could try doing a similar one but with circles instead?, i need it for a emote wheel

2 Likes

The button shape is arbitrary in a GUI. You can change the properties of the text button or add a image label of a circle. This is the code I use to create an the interface for my implementation.

local arrange=require(game.ReplicatedStorage.GlobalSpells.Arrange).arrangeButtons
	local interactions=require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.Commands.Interactions).command
	local function interactbuttons()
		arrange(Player.PlayerGui.Interact.Interactions,Player.PlayerGui.Interact.Interactions:GetChildren())
	end
	local template=Player.PlayerGui.Interact.Interactions.Item:Clone()
	local function buttonconnect()
		for i,v in interactions do 
			local b=template:Clone()
			b.ItemID.Value=i
			b.Text=i
			b.Parent=Player.PlayerGui.Interact.Interactions
			local con,dis=nil,nil
			con=b.MouseButton1Click:Connect(function()
			interactbuttons()
			remote:FireServer({Player.PlayerGui.Interact.Adornee.Parent,Player.Character},b.ItemID.Value)	
				--interact.command[apicall].Condition(str[1],str[2],player)
				b.Visible=false	
				b:Destroy()b.Parent=nil 
			dis:Disconnect()
			con:Disconnect()
			
			end)
			dis=b.AncestryChanged:Connect(function()
			con:Disconnect()
			dis:Disconnect()
			end)
		end
	end
	local function cleanup()
		for i,v in Player.PlayerGui.Interact.Interactions:GetChildren() do
			v:Destroy()
		end
	end
	local function buildinteractions()
		cleanup()
		Player.PlayerGui.Interact.Adornee=Player.PlayerGui.TalkGui.NPCTarget.Value		
		buttonconnect()
		interactbuttons()
	end

I have an array of keys that determine the number of buttons, then I connect events to them and fire a signal to the server to execute the function there and call it locally.

Also I have updated the code to not use math.floor when calculating the button scale.

1 Like