A player must be within radius of said door and press E to open.
The problem.
A player can be within radius once of said door and walk away, if not in a radius of another door, they can still open the same targeted door via pressing E.
I’ve looked around on DevForums and I can’t seem to get the same question around.
I’ve also tried making it so if you were further than the Radius, the Closest would be nil, but that seemed to break the entire script.
I do believe this is the code block that causes this sort of issue.
if Doors ~= nil then
for i, v in pairs(Doors) do
if Closest == nil then
if (PlayerPosition - v.InteractPart.Position).magnitude < Radius then
Closest = v
end
elseif (PlayerPosition - v.InteractPart.Position).magnitude < (Closest.InteractPart.Position - PlayerPosition).magnitude and (PlayerPosition - v.InteractPart.Position).magnitude < Radius then
Closest = v
end
end
end
PlayerPosition is defined as: Player.Character.HumanoidRootPart.Position
if Doors ~= nil then
for i, v in pairs(Doors) do
if Closest == nil then
if (PlayerPosition - v.InteractPart.Position).magnitude < Radius then
Closest = v
end
elseif (PlayerPosition - v.InteractPart.Position).magnitude < (Closest.InteractPart.Position - PlayerPosition).magnitude and (PlayerPosition - v.InteractPart.Position).magnitude < Radius then
Closest = v
else
Closest = nil
end
end
end
I also made it print out Closest after the suggested code, and it now just prints out nil.
Edit One: It doesn’t change a single time, not even when inside the radius of the door.
To find the closest object I usually do something like this:
local closestObject = nil
local closestDistance = nil
for _, object in pairs(objects) do
local distance = (object.Position - playerPosition).Magnitude
if not closestObject or distance < closestDistance then
closestObject = object
closestDistance = distance
end
end
This basically sets the distance corresponding to the current closest object and compares the rest of the objects’ distances to the player against that.
I’ve shortened the code to just this and it still selects the same target even when v or Closest is set to nil.
if Doors ~= nil then
for i, v in pairs(Doors) do
if Closest == nil then
if (PlayerPosition - v.InteractPart.Position).magnitude < Radius then
Closest = v
elseif (PlayerPosition - v.InteractPart.Position).magnitude > Radius then
Closest = nil
v = nil
end
end
end
end
Edit One: When the player is outside radius, v and Closest are set to nil, yet it keeps targeting same door.
Edit Two: I now have reason to think it is the second code that is run afterwards inside the while true do loop.
if Doors ~= nil then
for i, v in pairs(Doors) do
if Closest == nil then
if (PlayerPosition - v.InteractPart.Position).magnitude < Radius then
Closest = v
elseif (PlayerPosition - v.InteractPart.Position).magnitude > Radius then
Closest = nil
v = nil
end
end
end
end
for i, v in pairs(Doors) do
if v == Closest then
-- Do stuff here.
end
end
this is the thing I use for this, idk if itll work with your system though
function getClosest(player)
local ch = player.Character
repeat wait() until ch ~= nil
local root = ch.HumanoidRootPart
local tbl = {}
local lowest = 1000000
local instance
local typ
for i,v in pairs(game:GetService("Workspace"):FindFirstChild("INTERACTABLES"):GetChildren()) do
local real_name = string.split(v.Name, "_")[1]
if real_name == "obj" then
local z = v.Position
local pos = root.Position
tbl[(pos-z).Magnitude] = {["Instance"] = v, ["Type"] = "obj"}
elseif real_name == "npc" then
local z = v.HumanoidRootPart.Position
local pos = root.Position
tbl[(pos-z).Magnitude] = {["Instance"] = v, ["Type"] = "npc"}
elseif real_name == "lock" then
local z = v.Position
local pos = root.Position
tbl[(pos-z).Magnitude] = {["Instance"] = v, ["Type"] = "lock"}
elseif real_name == "door" then
local z = v.Position
local pos = root.Position
tbl[(pos-z).Magnitude] = {["Instance"] = v, ["Type"] = "door"}
end
end
local data = game:GetService("HttpService"):JSONDecode(player:FindFirstChild("Data").Value)
for i,v in pairs(tbl) do
if i < lowest then
lowest = i
instance = v.Instance
typ = v.Type
end
end
return {lowest, instance, typ, player, data}
end
game.ReplicatedStorage.interact.OnServerEvent:Connect(function(player)
local data = getClosest(player)
if data[1] <= 25 then
if data[3] == "obj" then
print("Player is interacting with an object.")
iapi:UpdateInventory(player,data[2].Name)
data[2]:Destroy()
elseif data[3] == "npc" and data[1] <= 10 then
print("Player is interacting with an NPC.")
elseif data[3] == "lock" and data[1] <= 15 then
print("Player is attempting to unlock something. Importing lock libraries from object.")
local dapi = require(game.ServerStorage.Modules.DoorHandler)
dapi:openLock({["Player"] = player,["Instance"] = data[2], ["Data"] = data})
elseif data[3] == "door" and data[1] <= 15 then
local dapi = require(game.ServerStorage.Modules.DoorHandler)
dapi:openDoor({["Player"] = player, ["Instance"] = data[2], ["Data"] = data})
end
end
end)
-- client
local cas = game:GetService("ContextActionService")
cas:BindAction("interact", function(n,is) if is == Enum.UserInputState.Begin then game.ReplicatedStorage.interact:FireServer() end end, false, Enum.KeyCode.E)
I’ve looked at this, and I like the way you put your interactables in a table, unfortunately that just isn’t going to work with me. My snippet of code is entirely in a LocalScript.
Honestly I have been trying to find a solution for 21 whole days and I’ve found it. The problem was not identifying which door was closest to you, it was rather the user input still being connected despite out of range.
First it started with this following code snip.
UserInputService.InputBegan:Connect(function(input)
if input.KeyCode == Key then
--< Code blah blah blah
end
end)
This was obviously a mistake as I didn’t disconnect the input once the key was pressed.