There are two major issues with your code.
- Its design creates a memory leak
- Its design is synchronous
Problem #1 is created by the duplication of the event handler onTouch
. Your loop, at a rate of ~60 times a second, connects onTouch
to part.Touched
. This will bombard the event with duplicate event handlers, leading to an ever-increasing response to the event and memory usage. This is extremely bad. Your design isn’t justified as BasePart.Touched will invoke its connected event handlers each time a collision is made with that BasePart
—there is no need connect a specific event handler more than once. You may be confused on how events work in Roblox, so I recommend learning more about them here.
Problem #2, the problem you’re experiencing, is created by a misunderstanding of control flow. A script is executed line-by-line, from left → right, top → bottom. Pretty much exactly how you read Western books. When it comes to while loops, the control structure modifies code flow to return to the top of the loop so long as the loop’s condition is met. Your first loop is ever-lasting, meaning it will continue to disrupt the downward flow of the script forever. This prevents your second loop from ever being reached, which is why you don’t see any activity from it. If you mean to run code when the part is touched, you need only include that code within the event handler:
local function onTouched(otherPart: BasePart)
local character = otherPart.Parent
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid then
return
end
print(character.Name .. "touched the part!")
-- Do everything else.
end
part.Touched:Connect(onTouched)
To run code when something that was already touching your part stops touching it, use BasePart.TouchEnded. If your intention is to run code while a Model
with a child Humanoid
is in contact with the part, you will need a different design. Utilize the spatial query API:
local Players = game:GetService("Players")
local function getCharacters(): {Model}
local characters = {} :: {Model}
for _, player in Players:GetPlayers() do
local character = player.Character
if character then
table.insert(characters, character)
end
end
return characters
end
local Part = workspace.Part
while true do
local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = getCharacters()
overlapParams.FilterType = Enum.RaycastFilterType.Include
if #workspace:GetPartsInPart(Part, OVERLAP_PARAMS) > 0 do
print("Characters are touching the part!")
else
print("No characters touching the part!")
end
task.wait()
end
Now, the above solution isn’t very ideal either. Unfortunately, the best way to approach this kind of problem requires a whole lot more work. You can use a module like ZonePlus, but that may be overkill for your needs. I have developed my own simplified version called PlayerTracker, but even this may not perfectly fit your situation. There are always more exact solutions, but we’d need to know what your ultimate goal is