Hello, I would like to create a Radial UI like in Counter Blox. I want to make one that has 3 selections in a circle like this:
Example of counter blox:
I’ve been looking at existing posts and tutorials but I just can’t seem to understand how to do it.
Most / all of the ones I find involve telling me to use an image UI and make sure it’s placed correctly with no overlap but I’m trying to do a selection of 3 options, not 4 therefore I can’t evenly split it like that.
I would be grateful for any support whether it’s just pointing me in the right place to look or an example.
I’m sorry if I wasn’t clear enough in my initial post but the frames overlap when I do that. This makes it bug out when you hover over the overlapping area so this option isn’t a good fit for me.
I think it would be very hard to do on Roblox (I’m not good at UI so that’s probably why I think that) so I think you would be better of using something else to make the UI such as InkScape or another vector art creator.
Though my approach to do something like that on Roblox Studio would to create a circle as normal and then add lines that match the color of the background on top of the circle so it divides it into radial pieces. I’m not sure if you can use Boolean operations on UI but if you could, you could subtract those lines from the circle to divide it if you wanted to go for a cleaner approach.
you could try making 1 image label with the whole picture then get the angle of the mouse from the middle of the image and distance, determine which button is being hovered and then apply a highlight overlay
You’re just doing it wrong then. Here is how it looks for me:
Here is the explorer view:
Each image is parented to a frame of size {1,0},{1,0} and each image is of size {0.5,0},{0.5,0} located at the top left corner of the frame. The frames are rotated 90 * index degrees so, first frame is rotated 0, second 90, third 180 and forth 270. Then each textlabel is parented to each image, scaled properly and then rotated in the opposite direction to the frame.
yes, but I think the issue was when the mouse hovers over the overlap. Even if all the slices are separate the image will still be square. So its “hit box” will also be square.
Using trigonometry you can get the mouse angle to use on the frames I developed this code:
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local PI = math.pi
local TAU = 2*PI
local MOUSE_CLICK = Enum.UserInputType.MouseButton1
local GRAY = Color3.new(0.5, 0.5, 0.5)
local WHITE = Color3.new(1, 1, 1)
local OFFSET = 1/4 -- since angle 0 is pointing to the right, we can begin our origin 90 degrees counter clockwise so its perfectly up
-- we normalized offset so we have to use decimals (0, 1)
-- 1/4 is one quarter counter clockwise
local baseFrame = script.Parent
local radialLimit = baseFrame.AbsoluteSize.X/2 -- we assume the baseframe is the limit (forgot to divide by 2, whoopsies!)
local mouse = Players.LocalPlayer:GetMouse() -- to account for gui Inset offset (you couldve hard coded it but I like the abstraction)
local list = { -- going counter clockwise
baseFrame.RadialLeft,
baseFrame.RadialBottom,
baseFrame.RadialRight
}
local selected
local checkConn
local clickConn
local function selectRadial(clicked)
if not clicked then return end
print(clicked)
end
local function onHover(hovered)
if not hovered then return end
hovered.ImageColor3 = GRAY
end
local function onHoverLeave(hovered)
if not hovered then return end
hovered.ImageColor3 = WHITE
end
local function activate() -- I would assume you would activate and unavtivate with like a keybind or someth[ing]
checkConn = RunService.RenderStepped:Connect(function()
local center = baseFrame.AbsolutePosition + baseFrame.AbsoluteSize/2
local direction = Vector2.new(mouse.X, mouse.Y) - center
if direction.Magnitude <= radialLimit then -- checking if out of bounds
local angle = math.atan2(-direction.Y, direction.X)/TAU -- we flip Y cause of how Gui is positioned
-- we divide by TAU to normalize the units so its [0, 1]
angle = (angle - OFFSET)%1
local index = math.floor(angle*#list) + 1
-- this works because the amount we have in the list is
local pickedFrame = list[index]
if selected ~= pickedFrame then -- its a new pick so we can hover
onHoverLeave(selected) -- make sure to unhover the one we had before
onHover(pickedFrame)
selected = pickedFrame
end
elseif selected then
onHoverLeave(selected)
selected = nil
end
end)
clickConn = UserInputService.InputBegan:Connect(function(inputType, isTyping)
if isTyping or inputType.UserInputType ~= MOUSE_CLICK then return end
selectRadial(selected)
end)
end; activate()
local function unactivate()
if checkConn then
checkConn:Disconnect()
clickConn:Disconnect()
selected = nil
end
end
For this behaviour you might not want to use Image buttons at all, and also make sure there is no guiInset cause that screws up the direction its poiting