Approaching GUI in Layers

For practice, I’ve decided to try doing some basic GUI Script, having no knowledge at all on how to deal with GUI. Quite simple concept;

Pressing “M” would open up four icons (TextButtons) on the lower-right, and clicking each of them would open a different Frame on the screen center.

To go easier on me, I’ve broken down that concept into more, but simpler steps;

  • Position all the GUI elements (a Frame with four TextButtons within it)
  • Hide the GUI elements
  • Condition to make the Frame visible again (UserInputService)
  • Turn the Frame’s “Visible” property “true” if the previous conditions are met (and of course, turning it “false” if Visible was “true” in the first place)

Doing that was rather easy, even though there’s definitely a better way of achieving it that I don’t know of. Well, after succeeding with the first part of the “simple GUI concept”, all that was left was opening a different panel for every TextButton clicked.

Of course, with me being a beginner that had never touched GUI, my first line of though was hard-coding my way through that. If “Button One” is clicked on, open up “Panel One”, if “Button Two” is clicked on, open up “Panel Two” and so on. Now, that sounds absurdly impractical; what if there were one hundred icons? I wouldn’t enjoy manually programming each icon to do the same thing.

My first though on a better approach was making a table containing all the four TextButtons within that Frame (even though I’m not sure myself on how to do that) and using an in pairs loop in which for “Button One”, if clicked on, would open up “Panel One”, and so on until “Button Four”, though with my limited knowledge of in pairs loops, which I have never actually used, I wouldn’t be able to, for example, open the first Panel, then straight up open the Fourth without opening either the Second nor Third. I’d be forced to open them in order, which if it were to be used for any menu, wouldn’t really be practical.

So, how am I supposed to approach that sort of GUI hierarchy? How am I supposed to make a GUI element only be accessible from having first selected another element?

Some examples of what I’m trying to achieve (though, obviously, with no polishing as it is entirely for practice);

Grand Piece Online


World // Zero

Vesteria

2 Likes

I’m not really sure what you mean, but I was able to accomplish something, and I think it’s what you mean.

My hierarchy:
image

My code:

local frame = script.Parent.Frame

for i, v in pairs(frame:GetChildren()) do
	if v:IsA("TextButton") then
		local panelNumber = v.Name:split("n")[2]
		
		v.MouseButton1Click:Connect(function()
			local panel = script.Parent:FindFirstChild("Frame"..panelNumber)
			panel.Visible = not panel.Visible
		end)
	end
end

All I’m doing here is looping through all the buttons like you mentioned.

Hope this helps.

Ignore the trash UI I made in 10 seconds.

2 Likes

Thank you for the reply, though I don’t really fully understand your Script, neither how you set up your GUI hierarchy.

local panelNumber = v.Name:split(“n”)[3]
local panel = script.Parent:FindFirstChild(“Frame”…panelNumber)

Those two lines specifically confuses me lots, mostly because I’ve never seen nor can find anything about the “split” function. What I (hope I) understood about this Script was that, ir order:

  1. Get a table with all the contents within the “Main Frame”;
  2. Checks if the content is a TextButton;
  3. Store the number value of the TextButton with a variable, probably using that mysterious “split” function;
  4. Compares the Frame’s number value (apparently using concatenation?) with the TextButton, if it matches, sets it Visible.

Not sure if I managed to read the code properly, though if I did, there are two things in it that I’m too “beginner” to understand; “split” function’s purpose (along with its parameter), and the apparent usage of concatenation to check if the Frame has a certain number in its name.

Would you mind explaining those two things?

1 Like

Of course! So Roblox Lua has a string function called split, and as the name suggests, it enables you to split a string, and then returns a table containing the split strings. Here’s an example:

-- I want to split this string to get the word, "Hello".
local exampleString = "HelloWorld!"
local split = exampleString:split("W") -- Splits the string when it meets the letter W. 

print(split[1]) -- Gets the first item in the table, that is "Hello".
print(split[2]) -- Gets the second item in the table, that is "orld!".

So in my case, I’ve named all my frames by corresponding them to their respective TextButton. So TextButton1 would open Frame1, and so on. So instead of coding every single button to do the same thing, what I did was get the frame number. So, I did that by splitting the name of the TextButton, when it meets the letter “n”. So, I would get this table, {“TextButto”, “1”}, {“TextButto”, “2”} etc. You can see that the second item in the table is our frame number, so then I can reference the frame I want to open by concatenating the frame number to “Frame” because that’s how my frames are named.

“Frame”…“1”

That’s basically everything, and I’m so sorry if I made no sense to you at all, as I’m terrible at explaining stuff, but if you have any more questions do not hesitate to shoot me a message.

2 Likes

Lovely, thank you for the explanation! Mind sharing any examples of other situations in which this function would be useful? Of course, without the code itself, as I’m just trying to learn more about the function itself.

Again, thank you!

1 Like

Of course! The first thing that comes to my mind is commands. The split function is very useful for creating commands, that need to specify a player. Like for example, “:kill enc_oded”. I would have to split the string into, “:kill” and “enc_oded”, to find the player and the command. You’ll know when you have to use the function though :wink:.

No worries! Glad to help.

Oh and here’s where you can read a bit more

2 Likes

So, for practice (even though I’m not sure if that’s the best way to do this), I read your code and split it into small pieces, then tried to achieve the same thing, occasionally checking yours when stuck (which very clearly happened quite a lot).

It didn’t work, not sure if I messed up at the code and couldn’t find it, or if the error is within my GUI hierarchy on the Explorer.

“My” code:

-- Get access to Buttons and Frames
local buttonFrame = game.StarterGui.ScreenGui.ButtonFrame
local panelFrame = game.StarterGui.ScreenGui.PanelFrame

-- Set up a table containing buttonFrame's contents within it using a for loop
for i, v in pairs(buttonFrame:GetChildren()) do
	-- If the child is a TextButton, store its number within a variable
	if v:IsA("TextButton") then
		local buttonNumber = v.Name:split(" ")[2]
		
		
		v.MouseButton1Click:Connect(function()
			-- Locate the panel whose number matches the buttonClicked	
			local panel = panelFrame:WaitForChild()("Panel "..buttonNumber)
			-- Set its Visible property the opposite of what it currently is
			panel.Visible = not panel.Visible
		end)
	end
end

My explorer:
image

1 Like

The problem here is that you’re referencing the button through StarterGui. StarterGui is basically just a holder where your UI is stored. When a player joins, the UI from StarterGui gets replicated to the Player’s PlayerGui.

Replace your variables with this:

-- Get access to Buttons and Frames
local buttonFrame = script.Parent.ButtonFrame
local panelFrame = script.Parent.PanelFrame
1 Like

Oh boy, those are the small things that scare me to death when it comes to scripting. Never had a clue about that. Thank you, mate, even though I pretty much just copied your Script, I did learn two new things, and a new way to use a for loop, also.

I did have to replace the WaitForChild() with FindFirstChild(), though, from what the API says, thought they’d do pretty much the same thing except for WaitForChild() being safer for usage in LocalScripts.

Again, thank you!

1 Like