Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Can one script run many items?

Instead of placing the same script inside of a part, is there anyway to just use one script for all off the parts?

1 comment

0

It depends on what the script is doing.

1 answer

✓ Accepted 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

1

For the multiple threads, why not just use spawn(f) or delay(n, f)? Looks cleaner than using a coroutine.

0

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.

0

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.