Note, by proxmity, I only mean the :DistanceFromCharacter() and not ProximityPrompt object. Now, to begin…
I am attempting to do a door that opens when a player is in the range of 15 studs. For the most part, proximity detection is worked in the client, respective to the own’s client player. Also, it only trigger if the player is in front of it.
The door is such that, it is not actually walking through, but instead where you touch the glowing part inside it (will be visually clarified later on) and get teleported to another door that is under a folder that is marked as ‘exit’.
Client Sided Local Script:
function triggerMediumProximity(medium)
local holyEntrance = medium.OpenVariant.HolyEntrance
if medium.Name == "Door_" then -- Medium is referencing the actual object (medium like media of how you enter)
local doorHinge = medium.ClosedVariant.PrimaryPart
local doorState = doorHinge.DoorState
local doorRelativeToCharacter = (humanoidRootPart.Position - holyEntrance.Position).Unit
local holyEntranceLookVector = holyEntrance.CFrame.LookVector
local dotProduct = doorRelativeToCharacter:Dot(holyEntranceLookVector)
if player:DistanceFromCharacter(holyEntrance.Position) <= 15 and dotProduct >= 0 then
proximityResponseEvent:FireServer(medium, "open")
end
if player:DistanceFromCharacter(holyEntrance.Position) > 15 or dotProduct < 0 then -- Added this so performance is good as it only calls the doors that have initially been open (they are closed by default)
if doorState.Value == "open" then -- I only check it here and not the previous one as by default, the door is closed. To save on the time events is called, it only really needs to work when the door is already opeend
proximityResponseEvent:FireServer(medium, "close")
end
end
end
end
Server sided script:
mediumProximityEvent.OnServerEvent:Connect(function(player, medium, arg)
if medium.Name == "Door_" then
local holyEntrance = medium.OpenVariant.HolyEntrance
local doorHinge = medium.PrimaryPart
local doorState = doorHinge.DoorState
local tweenState = doorHinge.TweenState
if doorState.Value == "closed" and tweenState.Value == "idle" and arg == "open" then
doorState.Value = "open"
local goal = {}
goal.CFrame = doorHinge.CFrame * CFrame.Angles(0, math.rad(90), 0)
local holyEntranceGoal = {}
holyEntranceGoal.Transparency = 0
local openAnimateTween = TweenService:Create(doorHinge, moveDoorAnimateTweenInfo, goal)
local openAnimateGlowTween = TweenService:Create(holyEntrance, moveDoorAnimateTweenInfo, holyEntranceGoal)
openAnimateTween:Play()
tweenState.Value = "playing"
local openSound = SoundService.LevelEntranceSystemAudio.DoorOpen:Clone()
openSound.Parent = doorHinge
openSound:Play()
openSound.Ended:Connect(function() openSound:Destroy() end)
task.wait(0.08)
openAnimateGlowTween:Play()
openAnimateTween.Completed:Connect(function() -- This, like the next time the :Connect was fired lower down the script was to make sure that the tweenicngs do not overlap and that it can keep its orientation and only close when wanted
tweenState.Value = "idle"
end)
elseif doorState.Value == "open" and tweenState.Value == "idle" and arg == "close" then
doorState.Value = "closed"
local goal = {}
goal.CFrame = doorHinge.CFrame * CFrame.Angles(0, math.rad(-90), 0)
local holyEntranceGoal = {}
holyEntranceGoal.Transparency = 1
local openAnimateTween = TweenService:Create(doorHinge, moveDoorAnimateTweenInfo, goal)
local openAnimateGlowTween = TweenService:Create(holyEntrance, moveDoorAnimateTweenInfo, holyEntranceGoal)
openAnimateTween:Play()
tweenState.Value = "playing"
local closeSound = SoundService.LevelEntranceSystemAudio.DoorClose:Clone()
closeSound.Parent = doorHinge
closeSound:Play()
closeSound.Ended:Connect(function() closeSound:Destroy() end) -- Deletes sound when it finishes playing as to not use too much memory
task.wait(0.08)
openAnimateGlowTween:Play()
openAnimateTween.Completed:Connect(function()
tweenState.Value = "idle"
end)
end
end
end)
Note: Both code above is only JUST a snippet, you won’t be able to copy and run it yourself just like that unless you make your own repeatable thingy by adding stuff
This works completely fine in the client, and for some situations, even the server script for when there are 2 or more players. However
The Problem
When all players are out of range of the door, I want to it to close back to its original orientation (but only when all the players are out of the 15 studs). So, it does so, I tested all my own players for when I do a test run via a local server, when all of them are out of range, it is closed (as expected) - or open for when all of them are in range.
However, as soon as one player is in bounds and another player, or more others, are out of bounds, the door will do this thing where it opens and closes continusly.
Here, there are 2 players in the local server, the other copy of me is just somewhere far off out of range
The expected result is for it to keep open.
What I know, and the question
I am aware this occurs due to one of the clients firing "open" and another firing "close", this causes the event to respond accordingly and on each instance, opens and closes depending which was called in order. However, how on earth could I avoid this (in a performant way).What I tried
I made a dictionary that stored the player calling and what they were calling (either the arg to "open" or to "close) in the global scope of the code to check when all the players are calling for it to close (meaning all of them are out of bounds). This worked, but didn't as soon as the other player (copy of myself) called another door to be open (there are multiple doors which I want this to work with). I want all of them to work accordingly. Keep it mind, whatever I will code here will copy over to the doors under the 'exit' folder due to how I looped it.Thank you in advance, please message or comment if you want further clarification