Im making a dungeon escape game, and im making a trap, theres a bunch of pressure plates, and when you step on the wrong one the camera moves to a anchored part so you can see yourself explode basically, it all works perfectly but i have a script in StarterGui for each part, id like for it all to be in 1 script if its even possible, this is one of the scripts
wait(1)
local TouchPart = game.Workspace.PressurePlates.Plate1
local Camera = game.Workspace.CurrentCamera
local Player = game.Players.LocalPlayer
local Char = Player.Character
local Head = Char.Head
local debounce = true
TouchPart.Touched:Connect(function(Boom)
repeat wait() until Player.Character
Camera.CameraType = "Scriptable"
Camera.CFrame = game.Workspace.BombCam.CFrame
wait(1)
local explosion = Instance.new("Explosion")
if debounce == false then return end
debounce = false
explosion.Parent = game.Workspace
explosion.Position = Boom.Position
explosion.BlastRadius = 2.5
explosion.BlastPressure = 25
wait(2.2)
debounce = true
Camera.CFrame = Head.CFrame
Camera.CameraType = "Follow"
end)
and another problem im having, its a first person game, so when the camera moves to third person, the player is invisible because the game thinks the person is in first person still.
You can apply a tag to each of the trap parts and use CollectionService to add behavior to them automatically.
Try something like this: Here I’ve modified your code to apply itself to any part that is tagged with TouchPart. This should be placed in a script in StarterPlayerScripts
local CollectionService = game:GetService("CollectionService")
local Camera = game.Workspace.CurrentCamera
local Player = game.Players.LocalPlayer
local function RegisterTouchPart(TouchPart)
local debounce = true
TouchPart.Touched:Connect(function(Boom)
local Char = Player.Character
local Head = Char and Char.Head
if Char == nil or Head == nil then return end
-- Make sure the part belongs to your character!
if not Boom:IsDescendantOf(Char) then return end
if Camera.CameraType == "Scriptable" then return end
if debounce == false then return end
debounce = false
Camera.CameraType = "Scriptable"
Camera.CFrame = game.Workspace.BombCam.CFrame
wait(1)
local explosion = Instance.new("Explosion")
explosion.Parent = game.Workspace
explosion.Position = Boom.Position
explosion.BlastRadius = 2.5
explosion.BlastPressure = 25
wait(2.2)
debounce = true
Camera.CFrame = Head.CFrame
Camera.CameraType = "Follow"
end)
end
for _, TouchPart in CollectionService:GetTagged("TouchPart") do
RegisterTouchPart(TouchPart)
end
CollectionService:GetInstanceAddedSignal("TouchPart"):Connect(RegisterTouchPart)
The reason why players in first person are still invisible once you take control of the camera, is because the CameraSubject is still set to their character. Adding a line which changes the CameraSubject over to the anchored part, should fix this issue.
@berezaa’s answer would be a solid solution. Though based on your code, it seems like you could also accomplish this without using CollectionService tags. I’d assume PressurePlates is already a dedicated container? You could use an approach similar to what they demonstrated, just iterating through its children. Though CollectionService makes things neat–as being able to grab direct references to instances, solves potential name collisions when accessing their path.
Why not use 1 .Touched event and check using CollectionService if the part is tagged?
It’s better than having a lot of connections for each individual part.
I think what you mean to say is why not have a single OnPartTouched function? Touched is an event of BasePart, and you are required to make a connection for every single part that you want to listen to, there’s no avoiding that. The number of connections will be the same whether or you use one function or individual anonymous functions like in my example.
In the above example, the TouchPart Touched function requires two key pieces of information for context: the part hitting and the part being hit, let’s call them part0 and part1 of the form part1.Touched:Connect(function(part0) .... The Touched event only passes information about part0, it does not pass information about part1. So if you were to define a single function to act as the handler for all touched events, presumably of the form OnPartTouched(part0, part1), you wouldn’t be able to connect that function to the Touched event and receive all of the information you need.
At best, you could move all of the code to an OnPartTouched function but it would still require the use of a barebones anonymous function to pass information about part 1:
-- Assume OnPartTouched(part0, part1) is defined above
-- This would not work because part1 would not be passed
part1.Touched:Connect(OnPartTouched)
-- This works, but you still make an anonymous function
part1.Touched:Connect(function(part0)
OnPartTouched(part0, part1)
end
There may be some OOP patterns I’m not aware of that can get around this and let you perfectly define a single touched function that fits this use case, but I don’t think you are going to see any noticeable improvements in code execution performance by doing so. If I missed something and there is a better way of doing this please do let me know.
The way you’d have one touched event (at least per player) would be by making one for the character (either a hitbox or the feet or something). I doubt this would be more efficient because the character’s part would be unanchored and fire hundreds of events as the character walks around.
It’s not worth the time to try to limit touched events–one per player and one per trap are on fairly similar magnitudes. Either solution is fine.
Maybe they could swap
repeat wait() until Player.Character
for
repeat task.wait() until Player.Character
or maybe ideally
if not player.Character then
player.CharacterAdded:Wait()
end
(though there is a bigger problem with that code block from it being in starter gui and having reset on respawn and them waiting for the character but not setting their character variable again)
TL;DR: The golden rule of optimization: don’t do it*. * unless you have to
@OP:
I’d recommend putting the script you have in StarterPlayerScripts and additionally checking if the hit is part of the character refer to Bereza
I meant when touching HumanoidRootPart, check if the part is a trap and that’s it.
You can modify CollectionService tags on the properties menu nowadays.
Note the script cant be clientside, since then you’d do if not game:IsLoaded() then game.Loaded:Wait() end
replace repeat wait() until Player.Character with local Character=Player.Character or Player.CharacterLoaded:Wait() i think