I’m making a system where if a player goes on the first floor of a building, all of the objects in the second floor will no longer have collission until the player goes back up there, and vice versa. A string value (in the player’s Backpack) is updated depending on what floor the player is on, which when changed should trigger a script (also in the Backpack) to load/unload the collision of the other floor. The value is being correctly updated, but the script is not working properly. Now, I’m not too great at coding, so I’m probably missing something pretty obvious here. If what I said didn’t make sense, just ask and I’ll try to explain it better lol, I’m not the best at explaining things sometimes.
Code:
local Value = game.Players.LocalPlayer.Backpack:WaitForChild("Location")
game.Players.LocalPlayer.Backpack:WaitForChild("Location").Changed:Connect(function()
print("Changed")
if Value.Value == "Floor1" then
for _, v in pairs(game:GetDescendants()) do
if v.location == "Floor1" then --The 'location' is an attribute which every object on both floors will have. "Floor1" means the object is in Floor 1
v.CanCollide = true
elseif v.location == "Floor2" then
v.CanCollide = false
wait()
print("Floor 1 loaded.")
end
end
elseif Value.Value == "Floor2" then
for _, v in pairs(game:GetDescendants()) do
if v.location == "Floor1" then
v.CanCollide = false
elseif v.location == "Floor2" then
v.CanCollide = true
wait()
print("Floor 2 loaded.")
end
end
else
print("No Value Assigned")
end
end)
In your notes you have location names as an “Attribute”; you cannot get these using “.” - you have to use object:GetAttribute(“AttributeHere”).
edit: in you code it would have to be
for _, v in pairs(game:GetDescendants()) do
if v:GetAttribute("location") == "Floor1" then
I should also note this may be inefficient or hard on performance, I would reccomend placing all objects that need their collision changed in seperate folders (named as what floor they are) and having your ‘for loop’ seek out these folders and disable collision on all parts within. Example:
local floors = {workspace:WaitForChild("floor1"), workspace:WaitForChild("floor2"), workspace:WaitForChild("floor3")} -- place floors folders here
local locationItem = game.Players.LocalPlayer.Backpack:WaitForChild("Location")
game.Players.LocalPlayer.Backpack:WaitForChild("Location").Changed:Connect(function()
print("Changed")
for _, v in pairs(floors) do
if v.Name == locationItem.Value then -- sees floorname == value
for _, x in pairs(v:GetDescendants()) do -- grabs all its descendants as x
x.Cancollide = true -- makes them touchable
end
else -- for every other floor
for _, y in pairs(v:GetDescendants()) do --grabs its decendants as y
y.Cancollide = false -- makes them untouchable
end
end
end
wait()
print(game.Players.LocalPlayer .. " loaded: " .. game.Players.LocalPlayer.Backpack.Location.Value)
end)
you could definitely refine that further by having local varyable names that define current location and last location so that you only set collision off for the location you’re unloading rather than all of them, but this is a start
Oops! you dont need to use :GetChildren() on the table, as the table is already in the format that it needs to be. Simply remove :GetChildren() and it should work - edited my original response to correct this.
Ok, I think this is the last part I need to fix… some descendants do not have the CanCollide property, so the code stops when it gets to one of them. Is there any way I can make the script ignore descendants without the CanCollide property?
you can check to see if the object is a basepart/unionpart/meshpart using the Object:IsA(“Type”) function, below’s an example checking for only BaseParts. you can use “or” statements to expand the list if you have more parts than a basepart. You could also use “if not” statements to check to see if the targeted instance has a cancollide value, but personally I’ve a bad track record with making that work
for _, x in pairs(v:GetDescendants()) do
if x:IsA("BasePart") then
x.Cancollide = true
end
end