Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Can one script run many items?

Asked by
Spooce 78
10 years ago

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

0
It depends on what the script is doing. YasuYoshida 171 — 10y

1 answer

Log in to vote
5
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
10 years ago

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
1
For the multiple threads, why not just use spawn(f) or delay(n, f)? Looks cleaner than using a coroutine. Tkdriverx 514 — 10y
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. Spooce 78 — 10y
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. BlueTaslem 18071 — 9y
Ad

Answer this question