Keep door open if player is still in trigger box

I get this

I put print statements in the activated and I get this.

There isn’t a tween for closing, I’m not sure how to do that. The tween for opening goes to target L and Target R. How do I tween it to go back to its original position?

Well, make 2 parts and put both of them inside the doors. It should be getting you the original position. Then you can tween it using those 2 parts. Oh, make sure it is transparent and non-collidable. I mean, we wouldn’t like parts being visible and blocking the door entrance, right?

(PS: I thought CFrame was gonna work, but I guess not, since Position kind of overrides it.)

Here is from my own door’s code

local tweenInfo = TweenInfo.new(
	1,
	Enum.EasingStyle.Quart,
	Enum.EasingDirection.Out,
	0,
	false,
	0
)

local tweenOpenRight = game.TweenService:Create(motorRight,tweenInfo,{TargetAngle=100})
local tweenOpenLeft = game.TweenService:Create(motorLeft,tweenInfo,{TargetAngle=100})
local tweenCloseRight = game.TweenService:Create(motorRight,tweenInfo,{TargetAngle=0})
local tweenCloseLeft = game.TweenService:Create(motorLeft,tweenInfo,{TargetAngle=0})

		tweenOpenRight:Play()
		tweenOpenLeft:Play()
		tweenOpenRight.Completed:Wait()


		tweenCloseRight:Play()
		tweenCloseLeft:Play()
		tweenCloseRight.Completed:Wait()

Can I use CFrame instead. I don’t like this tween

CFrames are perfectly okay. They’re the same thing with Position.

With a bit of help from @SelDraken’s solution to “Touched is endlessly turned on and off”, I finally got it working!

local model = script.Parent

local trigger_in = model.Trigger_In


local left = model.MainL

local right = model.MainR


local activated = false


local TweenService = game:GetService("TweenService")


local tweenInfo = TweenInfo.new(



     model.Speed.Value, --Time

     Enum.EasingStyle.Bounce, --Easing Style

     Enum.EasingDirection.Out, --EasingDirection

     0, --Repeat Count

     false, --Reverse

     0 --DelayTime



)

local CFrame1 = CFrame.new(3,0,0)
local CFrame2 = CFrame.new(-3,0,0)

local CFrameRevert = {
     Original_CFrame_Left = left.CFrame;
     Original_CFrame_Right = right.CFrame
}

local tweenL = TweenService:Create(left, tweenInfo, {CFrame = left.CFrame * CFrame1})
local tweenR = TweenService:Create(right, tweenInfo, {CFrame = right.CFrame * CFrame2})

local tweenLClose = TweenService:Create(left, tweenInfo, {CFrame = CFrameRevert.Original_CFrame_Left})
local tweenRClose = TweenService:Create(right, tweenInfo, {CFrame = CFrameRevert.Original_CFrame_Right})

local function open(hitPart)

     local player = game.Players:GetPlayerFromCharacter(hitPart.Parent)

     if player and not activated and not player:GetAttribute("InBlock") and hitPart.Name == "HumanoidRootPart" then
          
          player:SetAttribute("InBlock",true)
          activated = true
          
          tweenL:Play()

          tweenR:Play()
     end
end

local function close(hitPart)
     local player = game.Players:GetPlayerFromCharacter(hitPart.Parent)
     if player and activated and hitPart.Name == "HumanoidRootPart" then
          activated = false
          player:SetAttribute("InBlock",false)
          tweenLClose:Play()
          tweenRClose:Play()
     end
end

trigger_in.Touched:Connect(open)
trigger_in.TouchEnded:Connect(close)

(PS: You do not need any “TargetL” or “TargetR” parts as this script will use CFrame.new instead.)
Also, the MainR and MainL must be a part. I think it’s a part already, but I’m just checking.

Edit: I’ve updated the place file and code to account for players logging off while inside hit box.

I went ahead and just made a sliding door. I had only done rotating doors before, so this was a nice learning experience.
AutomaticSlidingDoor.rbxl (54.2 KB)


local openDistance = 4 --how many studs the door will slide open
local speed = 1 --time for the door to open or close
local isOpen = false -- makes sure we wait until door is fully open before closing

local hitTable = {} --holds the id's of players that are standing in the hit box

local hitBox = script.Parent:WaitForChild("HitBox")
local closeSound = script.Parent:WaitForChild("SoundContainer"):WaitForChild("CloseSound")
local openSound = script.Parent:WaitForChild("SoundContainer"):WaitForChild("OpenDoor")

--====== Tweening Things ===========
local rightDoor = script.Parent:WaitForChild("RightDoor")
local leftDoor = script.Parent:WaitForChild("LeftDoor")

local closedLeft = leftDoor.PrimaryPart.CFrame
local closedRight = rightDoor.PrimaryPart.CFrame
local openLeft = leftDoor.PrimaryPart.CFrame + (leftDoor.PrimaryPart.CFrame.RightVector * -openDistance)
local openRight = rightDoor.PrimaryPart.CFrame + (rightDoor.PrimaryPart.CFrame.RightVector * openDistance)

local tweenInfo = TweenInfo.new(
	speed,
	Enum.EasingStyle.Quart,
	Enum.EasingDirection.Out,
	0,
	false,
	0
)

local tweenOpenRight = game.TweenService:Create(rightDoor.PrimaryPart,tweenInfo,{CFrame = openRight})
local tweenOpenLeft = game.TweenService:Create(leftDoor.PrimaryPart,tweenInfo,{CFrame = openLeft})
local tweenCloseRight = game.TweenService:Create(rightDoor.PrimaryPart,tweenInfo,{CFrame = closedRight})
local tweenCloseLeft = game.TweenService:Create(leftDoor.PrimaryPart,tweenInfo,{CFrame = closedLeft})

--============= End Tweening Things =========================

function CheckForClose() --this checks to see if anyone is standing in the door and if not, closes the door
	--check for ghost playrs (players who have teleported away or who left the game while in the door hitbox) adn remove them from the list
	for n = 1, #hitTable do
		local p = game.Players:GetPlayerByUserId(hitTable[n])
		if p and p.Character and p.Character.PrimaryPart then
			local distance = (hitBox.Position - p.Character.PrimaryPart.Position).magnitude
			if distance > (hitBox.Size.Magnitude * 1.5) then
				table.remove(hitTable,n)
				n-=1
			end
		else
			table.remove(hitTable,n)
			n-=1
		end
	end
	--close the door if the list is empty
	if #hitTable < 1 then
		isOpen = false
		tweenCloseRight:Play()
		tweenCloseLeft:Play()
		closeSound:Play()
		tweenCloseRight.Completed:Wait()		
	end
end

hitBox.Touched:Connect(function(part)
	local player = game.Players:GetPlayerFromCharacter(part.Parent)
	if player and player.Character and player.Character.PrimaryPart == part then
		if not table.find(hitTable,player.UserId) then --see if player is not in list
			table.insert(hitTable,player.UserId) -- add player to list
		end
		if isOpen == false then
			closeSound:Stop()
			openSound:Play()
			tweenOpenRight:Play()
			tweenOpenLeft:Play()
			tweenOpenRight.Completed:Wait()
			openSound:Stop()
			isOpen = true
			CheckForClose() --this is called in case players left the hitbox while the dooor was still opening
		end
	end
end)

hitBox.TouchEnded:Connect(function(part)
	local player = game.Players:GetPlayerFromCharacter(part.Parent)
	if player and player.Character and player.Character.PrimaryPart == part then
		local index = table.find(hitTable,player.UserId) --find player in list
		if index then 
			table.remove(hitTable,index) --remove player from list
		end
		if isOpen == true then 
			CheckForClose() --see if the door needs to close, in case everyone is out of hit box, and door is fully open
		end
	end
end)

1 Like

Hi, Omg Thank youuu so much!!!

I feel like this can also be archived with worldroot:FindPartsInRegion3. I haven’t tried it before but given the name it should do what it’s intended

this approach is prone to various glitches related to .Touched event, such as triggering multiple times back and forth and sending TouchEnded if another player’s character is inside this one
UPD: using magnitude in this approach is a reliable measure against all this

The marked solution that I provided doesn’t have any issues with .Touched events triggering multiple times, nor are there issues with multiple players inside the hit box.

The only thing I feel I didn’t account for, is if a player is in the hit box with the door open, and they log out.

So in the solution, I would change the CheckForClose function to check for players that are no longer in the game.

So if a player logs out and the door is stuck open, the next player to enter and leave the hitbox will cause a cleanup to close the door.

function CheckForClose() --this checks to see if anyone is standing in the door and if not, closes the door
	--check for ghost playrs (players who have teleported away or who left the game while in the door hitbox) adn remove them from the list
	for n = 1, #hitTable do
		local p = game.Players:GetPlayerByUserId(hitTable[n])
		if p and p.Character and p.Character.PrimaryPart then
			local distance = (hitBox.Position - p.Character.PrimaryPart.Position).magnitude
			if distance > (hitBox.Size.Magnitude * 1.5) then
				table.remove(hitTable,n)
				n-=1
			end
		else
			table.remove(hitTable,n)
			n-=1
		end
	end
	--close the door if the list is empty
	if #hitTable < 1 then
		isOpen = false
		tweenCloseRight:Play()
		tweenCloseLeft:Play()
		closeSound:Play()
		tweenCloseRight.Completed:Wait()		
	end
end

that is perhaps the provided environment is so simple geometry-wise; once you begin filling your world with objects, especially not aligned orthogonally with each other, Touched event cannot be used for triggers that easy anymore

I don’t agree, I have used them extensively in my games, which are not simple by design. Try my solution out in an advanced game with several players and you will see it is reliable.

you are right; your approach is based on .magnitude and is therefore reliably responding, while using Touched just as a trigger; the only part being bad is that all this is run on the client

Its in a server script, so its being run on the server.

you cannot check for Touched events on a server; Touched events are local

Text often looses its emotion or inflection, and can sound harsh at times. So don’t take this in a harsh or demeaning way. However, I feel you should really work more with the engine, and discover what can and can not work in certain situations. Touched events can work on a server, or else the Roblox place file I supplied in the solution wouldn’t work. It does work, because I use it in my own game. I think its wise do a bit more testing or research before coming to an opinion on things.

the file you provided on Oct’22 clearly features a script with RunContext = Legacy, and it resides in the Workspace, therefore, by default, it will be run on clients; UPD: my mistake, Workspace only runs server-side scripts (BUT storing any kind of scripts in the Workspace is a bad idea bc they easily get replicated to client memory stack)
and, by the way, I’ve already encountered desync with it being run unfixed - doors stay open on one client while being triggered for closing on the other; that is a clear indication of workspace geometry being manipulated on the client-side, which is unrecommended