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

How to check if any instance inside a folder is touched?

Asked by 3 years ago

Hi.

Intro I'm making multiple parts that will kill you when touched. It works. But it doesn't look good when I have a lot of those parts and each of them contains a script that acts exactly the same. So I moved all of them inside a folder and left only 1 script to act for them all.

Problem

I don't know how to let the script know if any of those parts were touched. Here is the script that I have if it's any help at all.

local rs = game:GetService("ReplicatedStorage")
local DeathScreen = rs.DeathScreen
local Players = game:GetService("Players")

local KillBricks = game.Workspace:FindFirstChild("KillBricks")

local function respawn(hit)
    if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
        local player = Players:GetPlayerFromCharacter(hit.Parent)
        DeathScreen:FireClient(player)
        hit.Parent.HumanoidRootPart.Anchored = true
        wait(.1)
        hit.Parent.HumanoidRootPart.CFrame = player.PlayerData.Checkpoint.Value + Vector3.new(0, 4, 0)
        wait(.3)
        hit.Parent.HumanoidRootPart.Anchored = false
    end
end

KillBricks.Touched:Connect(respawn) --I want it when one of the bricks inside KillBricks folder touch this event triggers

1 answer

Log in to vote
4
Answered by
imKirda 4491 Moderation Voter Community Moderator
3 years ago
Edited 3 years ago

TL;DR

Use ipairs loop:

--KillBricks.Touched:Connect(respawn) --I want it when one of the bricks inside KillBricks folder touch this event triggers

for _, KillBrick in ipairs(KillBricks:GetChildren()) do
    KillBrick.Touched:Connect(respawn)
end

Explanation

You need to use a thing called generators or iterators or just loops, a brief description of iterators is "they will repeat code block while specified function does not return nil", in your case you will use it to repeat a code while next child exists. Generators are created the same as normal functions:

local function generate()
end

For generators there is a built-in syntax that looks like this:

for ... in generator_function do
    -- some code
end

Where ... stands for parameters returned by the generator, the code between do and end can be called an iteration, while generator is running it will repeat this code forever in a loop. Generators should return a value, let's return 5 as an example:

local function generate()
    return 5
end

for number in generate do
    print(number)
end

This will print number 5 repeatedly until it breaks, for me it printed the number 4996 times. They way this worked is that it called the generate function, the function returned 5 so number variable held value of 5, it was not nil so the iteration code was ran which was just print(number), after the iteration finished, it repeated the same action, it called generate again, the function returned 5, number held value 5 and the iteration code began running, this is an infinite loop. This was bad way of making a generator, let's make a generator that will loop over all children in the KillBricks folder, using Instance.GetChildren you can get list of them. To create a generator for this task, you need to know at which position in the list you are, return a child at that position, run the iteration function and increment the position, repeat that until position is out of the children list bounds (means all children were looped through). A good way to create this is to make function which returns generator, this will let you create local variables inside the generator:

local function iterateChildren(instance)
    -- list of all the children of the instance (all the killbricks for your case)
    local children = instance:GetChildren()
    -- current position of the list, every element in list
    -- has its own position, in this case all the children
    -- in the list have ordered position so we can
    -- increment the position to get the next child from
    -- the list
    -- first position is always 1, the reason why we start at
    -- 0 is because later we increment the position by 1
    -- and we need to increment it before we call "return"
    local index = 0

    -- this function is the actual generator that will be repeated
    -- every iteration this function will increase position to
    -- get the next child and return a value at that position
    -- from the children list, then the "do" "end" code will run
    -- where the parameter will be the next child
    return function()
        index += 1
        return children[index]
    end
end

local KillBricks = game.Workspace.KillBricks

for KillBrick in iterateChildren(KillBricks) do
    print(KillBrick)
    -- :Connect the function for currently iterated brick
    KillBrick.Touched:Connect(respawn)
end

Cool generator, but since this is used very often, Roblox has a built-in generator that will do this thing for you, it's called pairs and ipairs, first one returns generator that loops through all elements in table and returns current position and the value at that position for the iteration, position can also be a key, example:

local t = {
    a = 5, -- key a
    b = 100, -- key b
    c = "Hello", -- key c
    d = 2000, -- key d
    [1] = 200, -- position 1
    [2] = 300, -- position 2
    [4] = 30000 -- position 4
}

for key, value in pairs(t) do
    print(key, value)
end
--> a 5
--> 2 300
--> c "Hello"
--> b 100
--> d 2000
--> 4 30000
--> 1 200

You may see that its order is randomized, this is not true for ipairs which goes strictly by order and only works for positions, this makes it faster:

local t = {
    a = 10,
    20, -- position 1
    30, -- position 2
    [4] = 600 -- position 4, notice how i skipped position 3
}

for index, value in ipairs(t) do
    print(index, value)
end
--> 1 20
--> 2 30

a was straight ignored and it stopped at position 2 since it could not find position 3. Since :GetChildren returns table in ordered form, ipairs is the best fit in your case.

Sources

ipairs and pairs

some post about generators

roblox tutorial about loops that also includes pairs and ipairs

0
Thank you very much it worked. I know how the for loop works now. But i still have some questions. For example. Will it work if i just wrote " for KillBrick in KillBricks do "? (notice i didnt use ipairs()). If it doens't, why doesn't it? iMazariuz 36 — 3y
0
it doesn't because generators need a function after the `in`, Lua was built to be very simple and small language, it could predict that you want to iterate over KillBricks folder like Python does for example, but this would add more lines of code to the language which was not what Lua owners wanted. imKirda 4491 — 3y
0
Oh, okay. So if Im getting this right, how the "cool generator" one that doesn't use ipairs works is. 1. The for loop calls iterate children. The iterate children gets the children of killbricks, assign them to an index, and the call the function again? (line 19). And then adds the index by 1 then it loops like that? iMazariuz 36 — 3y
1
iterateChildren gets table of children and creates a variable index, then it returns function and the for loop uses this returned function as a generator, it calls this function, the function increments the index and returns child at that index -> KillBrick variable assigned to it, after "do" "end" finishes, it calls the returned function again without calling the "iterateChildren" imKirda 4491 — 3y
View all comments (2 more)
0
Very good, never thought you can optimize your code like that, just putting thousands of kill briks into a single folder and use a single 3 lines code, amazing MrSuperKrut 167 — 3y
Ad

Answer this question