ImageLabel Showing Up When It's Not Supposed To

Whenever the player clicks on a part, I want an image to appear, leaderstats values to change, and for a sound to play. That is all working, kinda.

The issue is, I want separate images to appear upon clicking on the correlating parts using the same script. However, when clicking on one of the parts, both of the images appear instead of just the one. When clicking on the other part, nothing happens.

This is the script I’m using:

local Button = game.Workspace.GasMask
local Click = Button.ClickDetector
local Gui = script.Parent.GasMask

Click.MouseClick:Connect(function(player)
	Gui.Visible = true
	Gui.Parent = script.Parent.Holder
	player.leaderstats.equipped.Value += 1
	player.leaderstats.GasMask.Value = true
	script.Equip:Play()
	Button:Destroy()
end)

local Button2 = game.Workspace.Rifle
local Click2 = Button.ClickDetector
local Gui2 = script.Parent.Rifle

Click2.MouseClick:Connect(function(player)
	Gui2.Visible = true
	Gui2.Parent = script.Parent.Holder
	player.leaderstats.equipped.Value += 1
	player.leaderstats.Rifle.Value = true
	script.Equip:Play()
	Button2:Destroy()
end)

(I am a beginner scripter and my scripts are probably messy.)

Video:

1 Like

You are–accidentally, I suppose–defining Click2 as Button.ClickDetector instead of Button2.ClickDetector. So, when you click on the rifle, nothing will happen. But because you set up two event listeners for the gas mask’s ClickDetector, both of the functions connected to those event listeners will execute.


You should structure your code in a way that it is secure against exploiters and makes your code easy to read and add onto or configure.

Do not forget the DRY principle: don’t repeat yourself. As scripters and programmers, our goal is to be as lazy as possible. Not lazy in the sense that we copy and paste to execute the same code more than once, but lazy in the sense that, for example, when we want to change a value that’s being used multiple times, we don’t need to search through the whole script to change every instance that the value is being used in–we would just need to change it once, and the code will automatically do the rest for us.

Here are examples of going by the DRY priniciple and not, respectively:

-- Let's say workspace.Parts is a folder.
local parts = workspace.Parts

local function connectTouched(part: BasePart)
    part.Touched:Connect(function(...)
        -- ...
    end)
end

for _, part: BasePart in parts:GetChildren do
    connectTouched(part)
end

parts.ChildAdded:Connect(connectTouched)
for _, part: BasePart in workspace.Parts:GetChildren() do
    part.Touched:Connect(function(...)
        -- ...
    end)
end

workspace.Parts.ChildAdded:Connect(function(part)
    part.Touched:Connect(function(...)
        -- ...
    end)
end)

In the second example, you can see that DRY has not been applied to the code.
Which means that if we wanted to change the code that executes when the BaseParts get touched, we would have to update both the code inside the for loop and the code inside the function connected to the Instance.ChildAdded event.
But in the first example, all we would need to do to change the code that executes when a BasePart gets touched is change the code inside the connectTouched() function.

And did you notice that in the second example I didn’t store the path to the Parts Folder in a variable? I typed workspace.Parts each time I wanted to use the folder.


So, instead of manually setting up ClickDetector.MouseClick event listeners for every object, let the code do it for you. All you need to do is tell the script what you want to happen for those objects.

If you have went to an online shopping website and selected an item you wanted to buy, you probably could have chosen the quantity of the item you wanted. Instead of having to order that item [x] times, you just had to tell the server that you wanted [x] of that item.


You should group the equippable items together, using a Folder or tagging them, iterate through those items, like I did in the first snippet above, and set up the ClickDetector.MouseClick events for each of those items.

for _, object in --[[Location here]] do
   object.ClickDetector.MouseClick:Connect(function()
        -- ...
   end) 
end

Also, if you want the server to detect that the player wants to pick up an item, you should set up the ClickDetector.MouseClick event on the server and update the player’s leaderstats there, too, then you call RemoteEvent:FireClient() and tell the player to play the sound and enable the necessary GUI.


In case you’re thinking, “The functions connected to my ClickDetector.MouseClick event listeners are not executing the exact same code.” I see that. But the differences are minor.

Let’s say we wanted to create three balls, but with different Names, BrickColors and Sizes. Instead of creating three functions for each ball, we would set the function up with parameters, then, when creating the balls, we would pass the arguments relative to every ball:

local function createBall(name: string, brickColor: BrickColor, size: number)
    local ball = Instance.new("Part")
    ball.Shape = Enum.PartType.Ball

    ball.Name = name
    ball.BrickColor = brickColor
    ball.Size = Vector3.one * size

    ball.Parent = workspace

    return ball
end

createBall("Basketball", BrickColor.new("Deep orange"), 4)
createBall("Dodgeball", BrickColor.new("Bright red"), 4)
createBall("Tennis Ball", BrickColor.new("New yeller"), 1)

If there are many parameters, you can also use arrays instead:

type ballData = {name: string, brickColor: brickColor, size: number}
local function createBall(ballData: ballData)
    local ball = Instance.new("Part")
    ball.Shape = Enum.PartType.Ball

    ball.Name = ballData.name
    ball.BrickColor = ballData.brickColor
    ball.Size = Vector3.one * ballData.size

    ball.Parent = workspace

    return ball
end
1 Like

Thanks for the feedback!

I’ve tried implementing what you’ve said but I’m afraid I do not fully understand.
This is the code (Which I’m aware there’s probably a few mistakes, but as stated in my previous post, I am still a very beginner scripter)

for _, object in workspace.Parts do
	object.ClickDetector.MouseClick:Connect(function()
		local function update(name: string, UI: TextButton, Equipped: IntValue, leaderstat: BoolValue)
			UI.Visible = true
			UI.Parent = script.Parent.Holder
		end
		local leaderstat = game.Players.LocalPlayer.leaderstats
		local hotbar = game.StarterGui.Hotbar

		update("GasMask", hotbar.GasMask, leaderstat.Equipped + 2, leaderstat.GasMask == true)
	end) 
end

I decided to test it out and see if I had any errors, which of course, there was. Except not at the line I was expecting.

Players.DragonBoss_11.PlayerGui.Hotbar.LocalScript:1: attempt to iterate over a Instance value

Could you help?

Hello. Sorry for such the late reply.

The attempt to iterate over a _ value error occurs when you, in other terms, try to loop through something other than an array. The reason why the error is being thrown in this case is because you’re asking the script to iterate over an Instance (workspace.Parts), not an array–which I assume you’d want to be workspace.Parts:GetChildren().

Remember that Instance:GetChildren() returns a numeric array of that Instance’s children, where as Instance:GetDescendants() returns a numeric array of that Instance’s descendants. If you don’t understand, the children, grandchildren, great grandchildren and so on of that Instance will be returned from Instance:GetDescendants().


I see that you added an update() function. This function will be created every time an object gets clicked, and its parameters are the Name of the object, the GUI associated with it, the Player’s leaderstats.Equipped value object and the leaderstats value that’s associated with the object.

If the two variables leaderstat and hotbar were accessible to the function, we would just need to pass an argument to the @name parameter.
The idea is that the function will just need a key to access the other objects or values that have locks matching that key, and we would not need the @Equipped parameter because the path to that object is already available to the function.
Right now, @name is the key to the other objects relative to the current object being iterated over:

-- You should also define services that you're going to use
-- at the top of your script.
local Players = game:GetService("Players")
local StarterGui = game:GetService("StarterGui")

local player = Players.LocalPlayer
-- I changed the variable name from "leaderstat" to "leaderstats".
local leaderstats = player:WaitForChild("leaderstats")

local hotbar = StarterGui.Hotbar
-- Creating a variable for something helps to
-- express its importance.
local holder = script.Parent.Holder

local function update(name: string)
    local ui = hotbar[name] -- (Example of using the key.)
    -- ...
end

for _, object in workspace.Parts:GetChildren() do
    object.ClickDetector.MouseClick:Connect(function(_)
        update(object.Name)
    end)
end

Also, unless you’re going to call update() somewhere else in your code, you don’t need the function, especially because of how small it is. I don’t know how you will expand your code, so what I previously said may not be the case for you. Just make sure you follow the SOLID principles when necessary, and know that functions are also used to break down code into smaller segments–let’s say you had a function that had one thousand lines of code and every two hundred and fifty lines performed a different task, you could break that function into four separate functions.

-- If you don't need the function:

for _, object in workspace.Parts:GetChildren() do
    object.ClickDetector.MouseClick:Connect(function(_)
        local ui = hotbar[object.Name]
        -- ...
    end)
end

This line would be the cause of an error if you did use @Equipped and @leaderstat in your function, according to the types of those parameters. But if you followed what I previously said about the function, its parameters and its accessibility of using the leaderstat and hotbar variables, this line would not be the same–it might be update(object.Name).


Earlier I mentioned SOLID. You may not know what that is: it is an acronym that stands for five coding design principles that you should use when doing object-oriented programming. I recommend doing a lot of research on it until you get a clear understanding of what these principles are, and how to use them.

This is what SOLID stands for:

  • Single-responsibilty principle
  • Open-closed principle
  • Liskov Substitution principle
  • Interface Segregration principle
  • Dependency Inversion principle.

Because you are a new programmer, it’s not extremely important that you study these principles right now, since you’re still learning the basics, but they are very useful and you should not forget to research them in the future.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.