Instead of placing the same script inside of a part, is there anyway to just use one script for all off the parts?
Can one script run many items?
1 answer
Yes. Almost always it is better to do it that way.
In general, you'll have a very similar looking script. There will just be an addition of a loop to perform the action on each part (or maybe several loops in things that require waiting). For example, if there was a Model of parts that you wanted to change color when touched, you would just have to modify the event to use a closure:
function Touch(hit, me)
me.BrickColor = hit.BrickColor
end
for _, part in pairs( workspace.Model:GetChildren() ) do
part.Touched:connect( function(h)
Touch(h, part)
end)
end
The above corresponds to something like this:
function Touch(hit)
script.Parent.BrickColor = hit.BrickColor
end
script.Parent.Touched:connect( Touch )
A more complicated example is to make a list of parts flip between blue and red every second. The single script for each might look like this:
while true do
script.Parent.BrickColor = BrickColor.Red();
wait(1)
script.Parent.BrickColor = BrickColor.Blue();
wait(1)
end
If you don't think carefully about it, you might try translating it into the following:
-- THIS DOESN'T WORK!
for _, part in pairs( workspace.Model:GetChildren() ) do
while true do
part.BrickColor = BrickColor.Red();
wait(1)
part.BrickColor = BrickColor.Blue();
wait(1)
end
end
Why? Because it starts an unending loop for just the first part, and never even gets to the second. Removing the loop will be a bit better, but it will do each part in sequence, rather than all at once.
A simple solution is to use 2 for loops:
while true do
for _, part in pairs( workspace.Model:GetChildren() ) do
part.BrickColor = BrickColor.Red();
end
wait(1)
for _, part in pairs( workspace.Model:GetChildren() ) do
part.BrickColor = BrickColor.Blue();
end
wait(1)
end
This could be cleaned up with the help of a function to paint a list of parts (avoiding the repeated code)
An even more complicated example is when you want to do the above but you want them each to be flashing at random offsets, e.g.,
while true do
script.Parent.BrickColor = BrickColor.Blue()
wait(math.random())
script.Parent.BrickColor = BrickColor.Red()
wait(math.random())
end
A direct way to do it is to spawn a new coroutine for each part:
function flash(part)
while true do
part.BrickColor = BrickColor.Blue()
wait(math.random())
part.BrickColor = BrickColor.Red()
wait(math.random())
end
end
for _, part in pairs( workspace.Model:GetChildren()) do
spawn(function() flash(part) end )
end
Though this isn't very elegant because spawning a large number of threads in general can cause difficulties.
Unfortunately, a direct way to do this in one thread is much more sophisticated (though possible):
changes = {}
for _, part in pairs(workspace.Model:GetChildren()) do
changes[ part ] =
{
time = math.random() + tick() ,
red = false
}
end
while true do
soonest = tick() + 1
-- The soonest (so far seen) that
-- a brick needs updating
for part, data in pairs( changes ) do
soonest = math.min( soonest, data.time )
end
wait( soonest - tick() )
-- Wait just until that moment
-- (Less performant, but more responsive, would be
-- to just always wait using RenderStepped)
for part, data in pairs( changes ) do
if data.time < tick() then
if data.red then
part.BrickColor = BrickColor.Red()
else
part.BrickColor = BrickColor.Blue()
end
data.red = not data.red
data.time = tick() + math.random()
end
end
end
3 comments
For the multiple threads, why not just use spawn(f) or delay(n, f)? Looks cleaner than using a coroutine.
Just thought of my own answer. This could be useful, but it doesn't relate to my question exactly. I will accept since you put a lot of work into it.
I am going to contradict myself now. Use spawn. Previously I said don't. Use it. If you are only creating coroutines to run them in the background, use spawn and make your intent clear.
This discussion is preserved as it was. New answers, comments, and votes are closed.

1 comment
It depends on what the script is doing.