Currently revamping my game’s ‘Enter Building’ teleportation system. Hence, instead of using Touched, I switched to the common ‘Press E to XXX’. I’ve been trying to come up different with ways to do this.
Place all doors in a folder and loop through to get the nearest door. Problem, the keybind GUI did not show up and only showed when there is only one door in the folder
Using CollectionService, tag all doors and loop through the table of tagged objects. It worked, however, it will only work when there is only one door in the specific tag
This is my current code after messing around
local collectionService = game:GetService("CollectionService")
local tag = "door"
local doors = collectionService:GetTagged(tag)
local player = game.Players.LocalPlayer
local character = game.Players.LocalPlayer.Character
local mag
local nearestpart
function openDoor() --fired when 'E' is pressed and magnitude is below/equal to 5
if mag <= 5 then
print(nearestpart)
game.ReplicatedStorage.teleport:FireServer(nearestpart)
end
end
function closestTrigger() --loops through the 'tag', then finds nearest door.
for i,v in pairs(doors) do
mag = (v.Position- character.HumanoidRootPart.Position).magnitude
if mag <= 5 then
nearestpart = v
player.PlayerGui.keyBind.Enabled = true -- the script somehow ignores the next 2 lines
player.PlayerGui.keybind.TextLabel.Text = "[E]".. nearestpart.purpose.Value
print("found near") --jumps to this
print(nearestpart.Name)
elseif mag > 5 then
script.Parent.Enabled = false
end
end
end
game:GetService("RunService").Heartbeat:connect(function(step) --checks if player is close
closestTrigger()
end)
game:GetService("ContextActionService"):BindAction(
"action name",
openDoor,
false,
Enum.KeyCode.E
)
This is the part that’s ruining it
Disabling the script
Basically what’s happening is, when the first door is near it will disable the script! Meaning the script will no longer work, so any future doors won’t trigger the script. This is why it works for one door than stops for the others: The first door disables the script so nothing in the future would happen.
The idea of disabling scripts isn’t always an ideal option honestly, I don’t recommend it, things like loops might continute working even when a script is disabled which might mess up things.
Can you perhaps change the disabling the part with something else? Like maybe break out of the loop?
Just to clarify if you are confused, script.Parent refers to the ScreenGUI that I want to enable/disable when the player is close to the door and not close respectively
Alright, so I tried breaking the loop to see if it helped. This is what happens
The door when teleported inside the house is also part of the doors that were tagged in the CollectionService. Breaking the loop only allowed it to work once, sadly. I checked and it did not disable the script either. Here is the current code with break
local collectionService = game:GetService("CollectionService")
local tag = "door"
local doors = collectionService:GetTagged(tag)
local player = game.Players.LocalPlayer
local character = game.Players.LocalPlayer.Character
local mag
local nearestpart
function openDoor() --fired when 'E' is pressed and magnitude is below/equal to 5
if mag <= 5 then
print(nearestpart)
game.ReplicatedStorage.teleport:FireServer(nearestpart)
end
end
function closestTrigger() --loops through the 'tag', then finds nearest door.
for i,v in pairs(doors) do
mag = (v.Position- character.HumanoidRootPart.Position).magnitude
if mag <= 5 then
nearestpart = v
player.PlayerGui.keyBind.Enabled = true -- the script somehow ignores the next 2 lines
player.PlayerGui.keybind.TextLabel.Text = "[E]".. nearestpart.purpose.Value
print("found near") --jumps to this
print(nearestpart.Name)
elseif mag > 5 then
script.Parent.Enabled = false
end
break
end
end
game:GetService("RunService").Heartbeat:connect(function(step) --checks if player is close
closestTrigger()
end)
game:GetService("ContextActionService"):BindAction(
"action name",
openDoor,
false,
Enum.KeyCode.E
)
player.PlayerGui.keyBind.Enabled = true -- the script somehow ignores the next 2 lines
player.PlayerGui.keybind.TextLabel.Text = "[E]".. nearestpart.purpose.Value
Since the script is ignoring some of the lines, you may be indexing the keyBind GUI before it is loaded in on the client, especially since you are activating that function on a heartbeat as opposed to when the player moves. To rectify this, add:
player.PlayerGui:WaitForChild("keyBind")
before the first index of the keyBind GUI.
On another note, it is semi-inefficient to constantly check whether or not the player is in range of the doors when they may not be moving. Going back to the point made in the first paragraph, use something along the lines of:
game.Players.LocalPlayer.Character.Changed:Connect(function(attribute)
if attribute and attribute == "Position" then
closestTrigger()
end
end)
which will only run when the player moves to make it a more efficient system, hope this helps.
Hmmm… I never thought of that. But another issue has aroused where when the player moves it doesn’t call the function. Which I thought was weird because it should. I tried playing around with
To no avail, this didn’t work either, which baffled me even more! . Even if I did put WaitForChild(), the function doesn’t call at all. So far, here is the modified line that should run when the player moves
game.Players.LocalPlayer.Character:WaitForChild("Torso").Changed:Connect(function(attribute)
if attribute == "Position" then --when the player moves. Problem: lines below do not run
print("moved") -- doesn't print
closestTrigger() -- doesn't run?
end
end)
Position/CFrame/Velocity/etc doesn’t trigger changed events for performance reasons. Secondly you are not listening for new doors. You need to listen for new doors otherwise doors which get sent to the client later will be ignored.
For movement you can bind (using InputBegan) to the W A S D and Space keys and check that gameProcessed is true. Then you could loop the check until UserInputService:IsKeyDown(keyCode) is false and use Heartbeat:Wait().