I’m trying to make it so when the player enters back into the SafeZone, their sword gets removed and they get a forcefield. What ends up happening is that the player gets multiple swords and forcefields for some reason and I can’t figure out why. When exiting the SafeZone it’s completely fine, everything works. Once they enter back in, it just completely breaks.
local event = game.ReplicatedStorage.SafeZone
script.Parent.Touched:Connect(function(part)
if(part.Name ~= "HumanoidRootPart") then return end
--if not game.Players:GetPlayerFromCharacter(part.Parent) then return end
local character = part.Parent
local forceField = Instance.new("ForceField")
forceField.Name = "Safezone"
forceField.Parent = character
forceField.Visible = true
local backpack = character:FindFirstChildOfClass("Backpack")
local player = game.Players:GetPlayerFromCharacter(character)
for _, tool in ipairs(backpack:GetChildren()) do
if tool:IsA("Tool") then
tool:Destroy()
end
end
if player.Character:FindFirstChildOfClass("Tool") then
player.Character:FindFirstChildOfClass("Tool"):Destroy()
end
if(player) then
event:FireClient(player, "In")
end
end)
script.Parent.TouchEnded:Connect(function(part)
if(part.Name ~= "HumanoidRootPart") then return end
local character = part.Parent
local forceField = character:FindFirstChild("Safezone")
local debounce = false
if(forceField) then
debounce = false
wait(1)
forceField:Destroy()
local clone = game.ServerStorage.Swords.ClassicSword:Clone()
clone.Parent = character
debounce = true
end
local player = game.Players:GetPlayerFromCharacter(character)
if(player) then
event:FireClient(player, "Out")
end
end)
This is where I have my sword at:
I have a small idea on why this doesn’t work, and that’s because the Touched function runs like every time the player moves. I can’t find a different way to do it though.
Try this instead. The only change I made is that instead of character.Backpack, I did player.Backpack (after the player variable). That’s because the character doesn’t have a backpack, because the player has that.
script.Parent.Touched:Connect(function(part)
if(part.Name ~= "HumanoidRootPart") then return end
local character = part.Parent
local forceField = Instance.new("ForceField")
forceField.Name = "Safezone"
forceField.Parent = character
forceField.Visible = true
local player = game.Players:GetPlayerFromCharacter(character)
local backpack = player.Backpack
for _, tool in ipairs(backpack:GetChildren()) do
if tool:IsA("Tool") then
tool:Destroy()
end
end
if player.Character:FindFirstChildOfClass("Tool") then
player.Character:FindFirstChildOfClass("Tool"):Destroy()
end
end)
script.Parent.TouchEnded:Connect(function(part)
if(part.Name ~= "HumanoidRootPart") then return end
local character = part.Parent
local forceField = character:FindFirstChild("Safezone")
local debounce = false
if(forceField) then
debounce = false
wait(1)
forceField:Destroy()
local clone = game.ServerStorage.Swords.ClassicSword:Clone()
clone.Parent = character
debounce = true
end
local player = game.Players:GetPlayerFromCharacter(character)
end)
--> Services
local Players = game:GetService("Players")
--> Configuration
local debounce = false
script.Parent.Touched:Connect(function(hit)
if hit.Parent and hit.Parent:FindFirstChildOfClass("Humanoid") and not debounce then
debounce = true
local Player = Players:GetPlayerFromCharacter(hit.Parent)
local Character = Player and Player.Character
if Character:FindFirstChildOfClass("ForceField") then
return
end
local ForceField = Instance.new("ForceField", Character)
ForceField.Name = "SafeZone"
-- Runs a loop through the players backpack and deletes them
for _, Tools in Player.Backpack:GetChildren() do
if Tools:IsA("Tool") then
Tools:Destroy()
end
end
-- If the character finds a tool then destroy it
if Character:FindFirstChildOfClass("Tool") then
Character:FindFirstChildOfClass("Tool"):Destroy()
end
debounce = false
end
end)
My best guess is that the player is repeatedly triggering the Touched and/or TouchEnded events.
This looks like it is a script inside of your SafeZone part? If it is you could create a table that tracks what players are inside the SafeZone and refer to that table as an additional check.
Though personally I’d make SafeZone stuff a localscript thing, and then the server double checks using spacial query possibly.
I don’t know how to create tables and I want to try to keep this simple as this is my first game, but I do want to ask what a spacial query is just for future references as I don’t know what it is.
This is what happens whenever I re-enter the safe zone with the item equipped. If it’s not equipped aka in the backpack it works fine, but once it’s equipped it completely breaks.
Here is my code again if anybody is wondering:
local event = game.ReplicatedStorage.SafeZone
script.Parent.Touched:Connect(function(part)
if(part.Name ~= "HumanoidRootPart") then return end
--if not game.Players:GetPlayerFromCharacter(part.Parent) then return end
local character = part.Parent
local forceField = Instance.new("ForceField")
forceField.Name = "Safezone"
forceField.Parent = character
forceField.Visible = true
local player = game.Players:GetPlayerFromCharacter(character)
local backpack = player:FindFirstChild("Backpack")
--if backpack then
-- for _, child in pairs(backpack:GetChildren()) do
-- if child:IsA("Tool") then
-- child.Enabled = false
-- end
-- end
--end
for _, tool in ipairs(backpack:GetChildren()) do
if tool:IsA("Tool") then
tool:Destroy()
end
end
if character:FindFirstChildOfClass("Tool") then
character:FindFirstChildOfClass("Tool"):Destroy()
end
if(player) then
event:FireClient(player, "In")
end
end)
script.Parent.TouchEnded:Connect(function(part)
if(part.Name ~= "HumanoidRootPart") then return end
local character = part.Parent
local forceField = character:FindFirstChild("Safezone")
local debounce = false
if(forceField) then
debounce = false
wait(1)
forceField:Destroy()
local clone = game.ServerStorage.Swords.ClassicSword:Clone()
clone.Parent = character
debounce = true
end
local player = game.Players:GetPlayerFromCharacter(character)
if(player) then
event:FireClient(player, "Out")
end
end)
----> Services
--local Players = game:GetService("Players")
----> Configuration
--local debounce = false
--script.Parent.Touched:Connect(function(hit)
-- if hit.Parent and hit.Parent:FindFirstChildOfClass("Humanoid") and not debounce then
-- debounce = true
-- local Player = Players:GetPlayerFromCharacter(hit.Parent)
-- local Character = Player and Player.Character
-- if Character:FindFirstChildOfClass("ForceField") then
-- return
-- end
-- local ForceField = Instance.new("ForceField", Character)
-- ForceField.Name = "SafeZone"
-- -- Runs a loop through the players backpack and deletes them
-- for _, Tools in Player.Backpack:GetChildren() do
-- if Tools:IsA("Tool") then
-- Tools:Destroy()
-- end
-- end
-- -- If the character finds a tool then destroy it
-- if Character:FindFirstChildOfClass("Tool") then
-- Character:FindFirstChildOfClass("Tool"):Destroy()
-- end
-- debounce = false
-- end
--end)
Try using game.Workspace:GetPartsInPart() instead of script.Parent.Touched. It’s similar to what @Lleventyate said. All it does is send a table of all physically touching parts in a list, and you can detect the player from there. Here’s a simple piece of code on how it works:
while wait() do
local touchingParts = game.Workspace:GetPartsInPart(script.Parent)
for i, part in pairs(touchingParts) do
if part.Parent:FindFirstChild("Humanoid") then
-- this will detect if anything is touching it
end
end
end
game.Workspace:GetPartsInPart(function(part)
if(part.Name ~= "HumanoidRootPart") then return end
--if not game.Players:GetPlayerFromCharacter(part.Parent) then return end
local character = part.Parent
local forceField = Instance.new("ForceField")
forceField.Name = "Safezone"
forceField.Parent = character
forceField.Visible = true
local player = game.Players:GetPlayerFromCharacter(character)
local backpack = player:FindFirstChild("Backpack")
--if backpack then
-- for _, child in pairs(backpack:GetChildren()) do
-- if child:IsA("Tool") then
-- child.Enabled = false
-- end
-- end
--end
for _, tool in ipairs(backpack:GetChildren()) do
if tool:IsA("Tool") then
tool:Destroy()
end
end
if character:FindFirstChildOfClass("Tool") then
character:FindFirstChildOfClass("Tool"):Destroy()
end
if(player) then
event:FireClient(player, "In")
end
end)
Based off the Touched implementation you’re using, you can add a guard clause in Touched to neglect players that are already safe.
After the character variable is set in Touched, do:
if character:FindFirstChildWhichIsA("ForceField") then
return
end
It looks like you’ve done the correct opposite decision in TouchEnded, except you’re sending that RemoteEvent even if there wasn’t a forcefield in the character. I don’t know if that’s intentional.
Touched & TouchEnded aren’t very reliable. Usually, Region3 would fix the issue but since the sword unequips from the character, it triggers the Touched/TouchEnded events. I don’t exactly know why this happens, but I think it would be better to get the distance of the HumanoidRootPart and check if it is in the area of the safe zone. Probably something similar to this:
local event = game.ReplicatedStorage.SafeZone
local paart = script.Parent
local players = game:GetService("Players")
local hrps = {}
local tagged = {}
local runservice = game:GetService("RunService")
runservice.Heartbeat:Connect(function()
local descendants = workspace:GetDescendants()
for i = 1,#descendants do
if descendants[i].Name == "HumanoidRootPart" then
local find = table.find(hrps,descendants[i])
if not find then
table.insert(hrps,descendants[i])
end
end
end
for i = 1,#hrps do
local magnitude = (hrps[i].Position - paart.Position).Magnitude
local character = hrps[i].Parent :: Model
local plr = players:GetPlayerFromCharacter(character)
if magnitude < paart.Size.Magnitude/2.5 and not table.find(tagged,hrps[i]) then
if not plr then return end
if character:FindFirstChild("Safezone") then return end
table.insert(tagged,hrps[i])
local ff = Instance.new("ForceField")
ff.Name = "Safezone"
ff.Parent = character
local sword = character:FindFirstChildOfClass("Tool")
if sword then sword:Destroy() end
if plr.Backpack:FindFirstChildOfClass("Tool") then plr.Backpack:FindFirstChildOfClass("Tool"):Destroy() end
elseif magnitude >= paart.Size.Magnitude/2.5 and table.find(tagged,hrps[i]) then
local ff = character:FindFirstChild("Safezone")
local find = table.find(tagged,hrps[i])
if ff then
table.remove(tagged,find)
delay(1,function()
ff:Destroy()
local clone = game.ServerStorage.Swords.ClassicSword:Clone()
clone.Parent = character
end)
end
end
end
end)
One of my friends helped fix this last night I just forgot to post this, but all these solutions seem reasonable (sorry if you wasted time doing this, it was so late I just saved my game and got in bed).
He did use a table (I think?) by doing.
local PlayersInZone = {}
And setting stuff to true and false throughout this script.