Help with making this a lot cleaner

As you can from these SS, this is my color wheel (made a while back, took me practically an entire day!!) and I had to MANUALLY position every single button into a good position. It scales to every screen too. I had to also manually go through every brick color, copy the Color3 over from it and but it on the button. My question though is how can I make this cleaner/nicer? 127 buttons ain’t exactly the nicest looking thing, and I’m afraid if I want to change the positions of the buttons in the future that it could take forever. Could using any of the UI scaling elements help with this? Any fancy math equation that can place them in the correct order? Is there simply a UI that already replicates the default Roblox BrickColor UI (default doesn’t have spaces between each color)


3 Likes

Perhaps with a combination of BrickColor.palette, the usage of for loops (I have no clue how you can generate the buttons, this is an uneducated guess) and using each ImageButton’s size along with the position of the last button, you could generate it via script.

I’d suggest maybe making then circular, smaller and in lines

With big stuff like that I would personally handle it all with coding, like put all the positions in a table or something and loop through the table creating the objects at the start of the server and if you wanted to move all the objects you could loop through the table and move them like that.

I don’t think you could replicate all the default BrickColor UI, but there is brickcolor codes

(Most of this is just a guess from the screenshots provided)

note: i am still touching up some mistakes in my reply

Scaling is quite difficult however can be acheived by using a bit of math.


This should help up with the GUI issue. Just run a function with a given parent and it should spawn a bunch of brickcolors in that frame, provided the frame is exactly a square then it should look perfectly fine.

You can also tween the frame after you run this code as well!


Lets get into it!

We know that the scale property on UDim is a number from 0 to 1. This is perfect for this algorithm since this provides us a sense of scale on how far something is from the left side of your parent frame.

We also know that there is exactly 127 colors in that pallete. We will also use what @Ankur_007 suggested earlier in the topic above. This will loop from 1 to 127 to grab your exact colours from BrickColor.pallet().


So now that we have a value to change the colours to, how about adding it all up?
sure thing, if you know a little bit of…

M A T H

I will walk you through my math and put it all in a code for you! Make sure your GUI frame is exactly a square and everything should be fine. In my case, I am usinga 200x200 pixel frame.


To begin with, we need to know the Y and X axis of where to put them in. A for loop will be perfect for itterating numbers 1 to 127. But what about the Y axis? How do we know how many colors we need for each row? I use an array for this that will itterate so many numbers on each row. Like this:

local list = {
	7, 8, 9, 10, 11, 12, 13, 12, 11, 10, 9, 8, 7
}
-- This totals up to 127, it also tells the script how many for each line

Now that we know how many colors for each row, lets put it all togther to get our X and Y values.

local brickColorIndex = 1
for i, v in pairs (list) do
	for IndexX = 1, v do
		brickColorIndex = brickColorIndex + 1 -- adds 1 for each colour
		-- at this point, IndexX = position on X axis and i = position on Y axis
		
		generateButton(
			{IndexX, i},
			{v, #list}, 
			brickColorIndex
		)
	end
end

You can see I use an external index value that will add 1 to every loop (every time it generates a new button). The cool thing now is that we can take the values from our loop and do a bit of math. I won’t explain so much on this algorithm but you are free to message me if you want a breakdown of it.

local function generateButton(position, maxPos, index) -- generates gui with position and index
	local i = Instance.new("ImageButton")
	i.BackgroundTransparency = 1
	i.Image = "http://www.roblox.com/asset/?id=2419759490"
	print(BrickColor.palette(index-1))
	print(BrickColor.palette(index-1).Color)
	i.ImageColor3 = BrickColor.palette(index-1).Color
	-- this returns the BrickColor with a given index and then I convert to Color3
	i.Parent = gui
	
	-- now for a bit of math --
	
	-- X POS
	local div = 13
	
	local calcDiv = 1 / div
	
	local remainder = (div - maxPos[1]) / 2
	
	local Offset = calcDiv * (remainder - 1)
	
	local x = (calcDiv * position[1]) + Offset
	
	--Y POS
	local divY = maxPos[2]
	
	local calcDivY = 1 / divY
	
	local y = (calcDivY * (position[2] - 1))
	
	i.Position = UDim2.new(x, 0, y, 0)
	i.Size = UDim2.new(calcDiv, 0, calcDivY, 0)
end

CODE

local list = {
	7, 8, 9, 10, 11, 12, 13, 12, 11, 10, 9, 8, 7
}
-- This totals up to 127, it also tells the script how many for each line

local gui = script.Parent

local function generateButton(position, maxPos, index) -- generates gui with position and index
	local i = Instance.new("ImageButton")
	i.BackgroundTransparency = 1
	i.Image = "http://www.roblox.com/asset/?id=2419759490"
	print(BrickColor.palette(index))
	print(BrickColor.palette(index).Color)
	i.ImageColor3 = BrickColor.palette(index).Color
	-- this returns the BrickColor with a given index and then I convert to Color3
	i.Parent = gui
	
	-- now for a bit of math --
	
	-- X POS
	local div = 13
	
	local calcDiv = 1 / div
	
	local remainder = (div - maxPos[1]) / 2
	
	local Offset = calcDiv * remainder
	
	local x = (calcDiv * position[1]) + Offset
	
	--Y POS
	local divY = maxPos[2]
	
	local calcDivY = 1 / divY
	
	local y = (calcDivY * position[2])
	
	i.Position = UDim2.new(x, 0, y, 0)
	i.Size = UDim2.new(calcDiv, 0, calcDivY, 0)
end

local function colorPallet()
	local brickColorIndex = 1
	for i, v in pairs (list) do
		for IndexX = 1, v do
			brickColorIndex = brickColorIndex + 1 -- adds 1 for each colour
			-- at this point, IndexX = position on X axis and i = position on Y axis
			
			generateButton(
				{IndexX, i},
				{v, #list}, 
				brickColorIndex
			)
		end
	end
end

colorPallet()
1 Like

Still reading though it :sweat_smile: just thought I’d mention that there’s 128 numbers in the color palette (ranging from 0 - 127) however, the color ‘Really black’ is not in the ‘circular’ palette, instead being placed in the white and greys below the normal palette :+1:

 22:39:47.251 - invalid vector<T> subscript
22:39:47.254 - Stack Begin
22:39:47.256 - Script 'Players.NinjoOnline.PlayerGui.ScreenGui.Frame.LocalScript', Line 12 - upvalue generateButton
22:39:47.256 - Script 'Players.NinjoOnline.PlayerGui.ScreenGui.Frame.LocalScript', Line 49 - local colorPallet
22:39:47.257 - Script 'Players.NinjoOnline.PlayerGui.ScreenGui.Frame.LocalScript', Line 58
22:39:47.258 - Stack End

Also get that error (still generates all the buttons, but yea)

I am pretty sure you can just do

i.ImageColor3 = BrickColor.palette(index-1).Color

to fix it.
You may also want to do the same on the print() functions unless you want to remove that (recomended).
I updated it.

You can use basic euclidean geometry to solve the issue.

The challenge here is figuring out what are the offsets that need to be applied to each of the buttons in the X and Y coordinates, which can be solved in two ways - with scripting, and with UI constraints. I am only going to tackle the scripting method, but setting it up with UI Constraints should be as simple as making a list of UIListLayouts.


Scripting

Starting with scripting, the easier value to begin with is the X coordinate:

  • X coordinate

Since we want to horizontally align it to the middle, we need to first know how long our tiled row will be. This length varies as you go further down the palette, but it can be calculated using the following function:

function lengthOfRowForRowPosition(rowPosition)
  if (rowPosition <= 7) then
    return ( 13 - (7 - rowPosition) )
  else
    return ( 7 + (13 - rowPosition) )
  end
end

So, to check what is the length for a given row, you do lengthOfRowForRowPosition(n), with n being a natural number in the set [1, 13].

For the next sections, I am going to use the Scale properties of UDim2, for convenience, but a similar logic could be applied with the Offset property.

After calculating what is the length of the row, we need to figure out the starting X position for placing buttons. This should be as simple as taking the middle position, 0.5, and subtracting from it half of the length of our row, corrected to the hexagon’s size. This should, in code, translate to this:

local startingX = 0.5 - (lengthOfRowForRowPosition(rowN) * hexagonBase.Size.X.Scale)/2

And we have done it! To place our buttons for the row, it’s as simple as positioning them at startingX and summing the button’s width for each iteration. We are going to see the full implementation of this at the end of the post.

  • Y Coordinate

To begin with, the Y offsets per row are constant and do not change, so we do not need to worry about that.

We are going to do something similar to what we have done in the X coordinate: let’s figure out the starting Y position and lets position the rows starting from there.

Again, to do that, we need to determine the value by the centre of the GUI element that’s holding the buttons, so our code will end up more or less like this:

local startingY = 0.5 - (7 * (hexagonBase.Size.Y.Scale * HEXAGON_HEIGHT))/2

Note: please observe the HEXAGON_HEIGHT constant I put in the excerpt. This should be the percentage of the height of the hexagon which is straight, or visually, the red part of the following image:

There is no way for me to know what is the value for your hexagon, as certain hexagons have different ratios depending on their proportions. In the example above, the result is roughly 1/2, or 0.5.

To position the buttons Y-wise, it’s as simple as offsetting them from the starting Y value.

  • Full Code

The code for positioning and color setting is the following:

local hexagonBase = -- [...] should be the path to your base button.
local buttonHolder = --[...] should be the path to the button holding element.

function lengthOfRowForRowPosition(rowPosition)
  if (rowPosition <= 7) then
    return ( 13 - (7 - rowPosition) )
  else
    return ( 7 + (13 - rowPosition) )
  end
end

local HEXAGON_HEIGHT = 1
local startingY = 0.5 - (7 * (hexagonBase.Size.Y.Scale * HEXAGON_HEIGHT))/2
local buttonIndex = 0

for rowN = 1, 13 do
  local startingX = 0.5 - (lengthOfRowForRowPosition(rowN) * hexagonBase.Size.X.Scale)/2
  for buttonP = 1, lengthOfRowForRowPosition(rowN) do
    buttonIndex = buttonIndex + 1

    local button = hexagonBase:Clone()
    button.ImageColor3 = BrickColor.palette(buttonIndex-1).Color
    button.Position = UDim2.new(
      startingX + hexagonBase.Size.X.Scale * buttonP,
      0,
      startingY + (hexagonBase.Size.Y.Scale * HEXAGON_HEIGHT) * rowN,
      0
    )
    button.Parent = buttonHolder
  end
end

I’m still reviewing some parts of the code, namely positioning around the center.

Final: oops, was a bit late

Adding a background might help.