Trying to change the Brick Color of a random part within an array when touched as a repeated process

When a player join the game, a random part will be Bright green. I’m trying to set this up so that when a player steps on the bright green part the part itself will turn Medium stone grey. However, another part contained in the same model will turn Bright green. I am hoping that this will then continue the same process over and over again of having to tap the green part to turn another random part green.

local workSpace = game:GetService("Workspace")
local randomizer = workSpace.Randomizer
local debounce = false

local children = randomizer:GetChildren()
local part = children[math.random(1, #children)]
part.BrickColor = BrickColor.new("Bright green")

while true do
	randomnumber = math.random(1, #children)
	for i, v in pairs(children)do
		v.Touched:Connect(function(part)
			if not debounce then
				debounce = true
				if part.Parent:FindFirstChild("Humanoid")and v.BrickColor == BrickColor.new("Bright green")then
				v.BrickColor = BrickColor.new("Medium stone grey")
				end
			if part.Parent:FindFirstChild("Humanoid")and i == randomnumber then
				v.BrickColor = BrickColor.new("Bright green")
				end
				debounce = false
			end
		end)
	end
	wait(1)
end

The current script gets no error code and the first part turns grey. No other part is made to be green though. I believe this is because I can’t do two if statements like I’ve done here, but I’m not sure. If anyone could recommend a course of action or show me what I’ve done wrong it would be much appreciated.

Touched will fire every time a part is touched.

So you’re connecting a new event to every part, every second.

You actually don’t even need a loop here, since you can do your update when the part gets touched.

Here’s a skeleton to get you started, you’ll need to implement some of it:

local current

local touchedConnection

local function PickRandomPart()
	-- change 'current' to gray (if 'current' exists)
	
	-- pick a new part and set 'current' to it
	
	-- change the new 'current' to green
	
	-- call Disconnect() on touchedConnection (if it exists)
	if touchedConnection then touchedConnection:Disconnect() end

	-- create a new connection instead
	touchedConnection = current.Touched:Connect(function(hit)
		-- check for humnanoid
		-- call PickRandomPart()
	end)
end

-- set up initially
PickRandomPart()
2 Likes

I removed the code that was previously written here, because the final version is posted at the end of this topic.

1 Like

This worked, thanks. I’ll also try out the method suggested by @nicemike40 to try and solve this a perhaps more efficient way.

1 Like

@LordIsaacofBargo @nicemike40 is right (thank you!), I almost missed that. Use the updated code, which doesn’t include the loop anymore. Have a good time!

1 Like

It’s highly suggested to also check if the part is a BasePart just in case. It’s generally good practice, it could be done as shown:

if part:IsA("BasePart") then
    -- code here
end

You can put it in the function for change part color or you can put it in your loop. I would suggest in the loop so you can do something like:

for i, v in pairs(children) do
  if v:IsA("BasePart") then
	v.Touched:Connect(function(part)
		if not debounce then
			changeColor(v, part.Parent)
		end
	end)
  end
end

Hope this helps!

1 Like

I’ve went with the other solution as it’s more efficient, but in future similar situations I will use this as a method to prevent more problems, thank you.

Just going to add it on here incase anyone is interested (or if it works but I made an error of some kind that could cause problems later).


local randomizer = game.Workspace.Randomizer
local children = randomizer:GetChildren()
local current = children[math.random(1, #children)]
local touchedConnection

local function PickRandomPart()
	if current then
		current.BrickColor = BrickColor.new("Medium stone grey")
		current = children[math.random(1, #children)]
		current.BrickColor = BrickColor.new("Bright green")
		if touchedConnection then touchedConnection:Disconnect() end
		touchedConnection = current.Touched:Connect(function(hit)
			if hit.Parent:FindFirstChild("Humanoid")then
				PickRandomPart()
			end
		end)
	end
end

PickRandomPart()

May I ask, how is it more efficient, with the exception of use of disconnect? I removed the while-loop immediately, so it is fine now. Concept is the same. You needn’t have written your own, only had to add :Disconnect().

Huh, oh, I’m sorry. I didn’t notice you had updated yours. I was working on using his method.

The code itself may be more efficient, however you should change the function name to something like: “checkForTouched()” just for readability sake and for any future collaborations or help requests.

Best, TheROBLOXMAPMAKE

Alright, no problem, it was clearly a misunderstanding:

I updated the code 10 seconds after I first published it. Anyways, have a good time!

I agree with you, the other solution isn’t very readable and isn’t efficient for what he wants to do. The “for” loop method you did is perfectly fine and should work for what he wants. Although you could include the disconnect in some way to make it double the efficiency.

Best, TheROBLOXMAPMAKE

1 Like

@LordIsaacofBargo it is true that for loop works and is not at all performance demanding, but the truth is that @nicemike40 had a perfect idea. Here is, for my opinion, a final version:

local randomizer = workspace.Randomizer

local COOLDOWN = true
local COOLDOWN_TIME = .5

local children = {}
local debounce = false
local current, tConnection

local function changeColor()
	if (not current) then return; end
	debounce = true
	
	current.BrickColor = BrickColor.new("Medium stone grey")
	current = children[math.random(1, #children)]
	current.BrickColor = BrickColor.new("Bright green")
	
	if (tConnection) then tConnection:Disconnect() end
	if (COOLDOWN) then wait(COOLDOWN_TIME) end
	debounce = false
	tConnection = current.Touched:Connect(function(hit)
		if (hit.Parent:FindFirstChild("HumanoidRootPart") and not debounce) then
			changeColor()
		end
	end)
end

local function init()
	for i, v in pairs(randomizer:GetChildren()) do
		if (v:IsA("BasePart")) then
			table.insert(children, v)
		end
	end
	if (next(children) == nil) then
		warn("There are no parts in Randomizer.")
		script.Disabled = true
	end
	current = children[math.random(1, #children)]
	changeColor()
end
init()
1 Like