Door Mechanics (Open System)

I created a door system that functions with proximity prompts, allowing players to open, close the door. When Locked then the player can open the door. I want the door to open in the opposite direction of the player who activates it. I have attempted this several times without success, so I am reaching out for assistance.



Script (ServerScriptService)

local TweenService = game:GetService("TweenService")
local CollectionService = game:GetService("CollectionService")

local infohand = TweenInfo.new(.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, 0, false, 0)
local Colorinfo = TweenInfo.new(.75, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, 0, false, 0)
local Cardinfo = TweenInfo.new(1, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, 0, false, 0)
local infoopen = TweenInfo.new(.85, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out, 0, false, 0)
local infoclose = TweenInfo.new(.75, Enum.EasingStyle.Quad, Enum.EasingDirection.In, 0, false, 0)

-- Iterate through all tagged doors
for _, model in pairs(CollectionService:GetTagged("Door")) do
	if not model:IsA("Model") then continue end

	local insval = Instance.new("BoolValue", model)
	insval.Name = "Openor"
	local insvalIngor = Instance.new("BoolValue", model)
	insvalIngor.Name = "Ingor"

	for _, i in pairs(model.DoorPart:GetChildren()) do
		if i:IsA("BasePart") then
			local weld = Instance.new("WeldConstraint")
			weld.Parent = i
			weld.Part0 = i
			weld.Part1 = model.Hinge
			i.Anchored = false
		end
	end

	model.DoorPart.Prox.ProximityPrompt.Triggered:Connect(function()
		if model.Ingor.Value == false then
			model.Ingor.Value = true
			model.HHinge.Anchored = true
			model.DoorPart.Prox.ProximityPrompt.MaxActivationDistance = 0
			model.DoorPart.Prox.ProximityPrompt.ActionText = "Close"
			model.DoorPart.Prox2.ProximityPrompt.MaxActivationDistance = 0
			model.Handle.Anchored = false

			local locked = model:GetAttribute("Locked") or false
			local twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeTo.CFrame})
			twhd:Play()

			if not locked then
				if model.Openor.Value == false then
					model.Openor.Value = true
					model.Frame.Open:Play()
					twhd.Completed:Wait()
					model.HHinge.Weld.Enabled = true
					model.HHinge.Anchored = false
					local twdr = TweenService:Create(model.Hinge, infoopen, {CFrame = model.HingeTo.CFrame})
					twdr:Play()
					twdr.Completed:Wait()
					model.HHinge.Anchored = true
					model.HHinge.Weld.Enabled = false
					twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeFrom.CFrame})
					twhd:Play()
					twhd.Completed:Wait()
				else
					model.Openor.Value = false
					model.Frame.Close:Play()
					twhd.Completed:Wait()
					model.HHinge.Weld.Enabled = true
					model.HHinge.Anchored = false
					local twdr = TweenService:Create(model.Hinge, infoclose, {CFrame = model.HingeFrom.CFrame})
					twdr:Play()
					twdr.Completed:Wait()
					model.Frame.Bang:Play()
					model.HHinge.Anchored = true
					model.HHinge.Weld.Enabled = false
					twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeFrom.CFrame})
					twhd:Play()
					twhd.Completed:Wait()
					model.DoorPart.Prox.ProximityPrompt.ActionText = "Open"
				end
			else
				-- If locked, only animate the handle and play the locked sound
				twhd.Completed:Wait()
				twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeFrom.CFrame})
				twhd:Play()
				twhd.Completed:Wait()

				-- Play the locked sound
				local lockedSound = model.Frame:FindFirstChild("Locked") -- Ensure the sound is named correctly
				if lockedSound then
					lockedSound:Play()
				end

				model.DoorPart.Prox.ProximityPrompt.ActionText = "Open" -- Show Locked status
			end

			model.DoorPart.Prox.ProximityPrompt.MaxActivationDistance = 5
			model.DoorPart.Prox2.ProximityPrompt.MaxActivationDistance = 5
			model.Ingor.Value = false
		end
	end)

	model.DoorPart.Prox2.ProximityPrompt.Triggered:Connect(function()
		if model.Ingor.Value == false then
			model.Ingor.Value = true
			model.HHinge.Anchored = true
			model.DoorPart.Prox.ProximityPrompt.MaxActivationDistance = 0
			model.DoorPart.Prox.ProximityPrompt.ActionText = "Close"
			model.DoorPart.Prox2.ProximityPrompt.MaxActivationDistance = 0
			model.Handle.Anchored = false

			local locked = model:GetAttribute("Locked") or false
			local twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeTo.CFrame})
			twhd:Play()

			if not locked then
				if model.Openor.Value == false then
					model.Openor.Value = true
					model.Frame.Open:Play()
					twhd.Completed:Wait()
					model.HHinge.Weld.Enabled = true
					model.HHinge.Anchored = false
					local twdr = TweenService:Create(model.Hinge, infoopen, {CFrame = model.HingeTo.CFrame})
					twdr:Play()
					twdr.Completed:Wait()
					model.HHinge.Anchored = true
					model.HHinge.Weld.Enabled = false
					twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeFrom.CFrame})
					twhd:Play()
					twhd.Completed:Wait()
				else
					model.Openor.Value = false
					model.Frame.Close:Play()
					twhd.Completed:Wait()
					model.HHinge.Weld.Enabled = true
					model.HHinge.Anchored = false
					local twdr = TweenService:Create(model.Hinge, infoclose, {CFrame = model.HingeFrom.CFrame})
					twdr:Play()
					twdr.Completed:Wait()
					model.Frame.Bang:Play()
					model.HHinge.Anchored = true
					model.HHinge.Weld.Enabled = false
					twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeFrom.CFrame})
					twhd:Play()
					twhd.Completed:Wait()
					model.DoorPart.Prox.ProximityPrompt.ActionText = "Open"
				end
			else
				-- If locked, only animate the handle and play the locked sound
				twhd.Completed:Wait()
				twhd = TweenService:Create(model.HHinge, infohand, {CFrame = model.DoorPart.HHingeFrom.CFrame})
				twhd:Play()
				twhd.Completed:Wait()

				-- Play the locked sound
				local lockedSound = model.Frame:FindFirstChild("Locked") -- Ensure the sound is named correctly
				if lockedSound then
					lockedSound:Play()
				end

				model.DoorPart.Prox.ProximityPrompt.ActionText = "Open" -- Show Locked status
			end

			model.DoorPart.Prox.ProximityPrompt.MaxActivationDistance = 5
			model.DoorPart.Prox2.ProximityPrompt.MaxActivationDistance = 5
			model.Ingor.Value = false
		end
	end)

end

Here is the game file for a better understanding of how the System works: DoorTests.rbxl

Thanks in advance!!!

You can probably achieve this with the dot method of a vector.
I can’t provide any examples as I’m not good with vectors, but basically the dot method returns a value based on where 2 vectors are facing, which in your case would be the player and door. Then you’d use the value to determine which way the door opens etc.

1 Like
1 Like


… I think i did somthing wrong ._.

im not good with vectors if you cant tell

Thanks for replying!!!

1 Like


made it worse i think i will just give up

1 Like

Here’s explanation so you can understand better! O hope you can learn something from that.

Step 1: Detect Player’s Position

First, you need to get the position of the player who activates the proximity prompt. You can do this by using the ProximityPrompt.Triggered event.

Step 2: Calculate the Direction

Next, calculate the direction from the door to the player. This will help you determine the opposite direction.

Step 3: Rotate the Door

Finally, rotate the door in the opposite direction based on the calculated direction.


Here’s a sample script to illustrate these steps:

local doorModel = script.Parent -- Assuming the script is a child of the door model
local proximityPrompt = doorModel:FindFirstChild("ProximityPrompt")

-- Ensure the door model has a primary part set
if not doorModel.PrimaryPart then
    warn("Door model does not have a primary part set!")
    return
end

local function onPromptTriggered(player)
    local character = player.Character
    if not character then return end

    local playerPosition = character.PrimaryPart.Position
    local doorPosition = doorModel.PrimaryPart.Position

    -- Calculate the direction from the door to the player
    local direction = (playerPosition - doorPosition).Unit

    -- Calculate the opposite direction
    local oppositeDirection = -direction

    -- Determine the new CFrame for the door
    local newCFrame = doorModel.PrimaryPart.CFrame * CFrame.Angles(0, math.atan2(oppositeDirection.X, oppositeDirection.Z), 0)

    -- Rotate the door model
    doorModel:SetPrimaryPartCFrame(newCFrame)
end

proximityPrompt.Triggered:Connect(onPromptTriggered)

Attach any extra part to the door primary part if you want for something extra to rotate with your opened/closed door

1 Like

Use the dot product like the top comment said. Do you want me to explain what it is?

That would help yes, cous im to dumb to understand!!!

I have explained my code. Try using it and give me your feedback!

cant get the door position when its a model

Oh i absolutely forgot that it can be a model! Let me change my code

1 Like

i only know that bc i already tryed and failed

I have fixed my code, try it now

1 Like

Video

Huh thats odd… I dont think thats supposed to happen…

sorry for bad quality

Oh :rofl: Give me some minutes, i’ll fix my calculations XD

DoorTests.rbxl (76.1 KB)
Theres a Game file for better testing if you havent seen!

1 Like

WTH
I knew that i was bad with vectors … but how did i do it this wrong :rofl:

LOL XD Look cool! :smiley: I’m also almoooost done

Why are you doing this. It’s bad practice to depend on things like this.

Move the functionality of the doors to a separate script, preferrably a ModuleScript that is based on OOP. That is the most optimal way to go around it

Your most prominent mistake aside from the fact that the door behavior isn’t abstracted is that you rely on certain things being inside your door, if a new door is created and doesn’t have a certain thing inside it, it simply will not work and will be very confusing to troubleshoot.

DoorTestsFixed.rbxl (75.0 KB)
It works well, just weld any part if you want for it to rotate with your door!

Here’s the code:

local mainDoorModel = doorModel.DoorPart -- Model you want to rotate
local proximityPrompt = doorModel.DoorPart.Prox:FindFirstChild("ProximityPrompt")
local proximityPromptBack = doorModel.DoorPart.Prox2:FindFirstChild("ProximityPrompt")
local primaryPart = mainDoorModel.PrimaryPart

local hinge = mainDoorModel.HHingeTo -- Assuming there's a part named "HHingeTo" as the hinge point

local DB = false
local isOpen = false

local savedCFrame = mainDoorModel.PrimaryPart.CFrame -- Just to make our life easier

local openAngle = 90 -- Adjust the angle as needed
local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)

local function getOppositeDirection(player)
   local playerPosition = player.Character.PrimaryPart.Position
   local doorPosition = primaryPart.Position
   local doorLookVector = primaryPart.CFrame.LookVector
   local direction = (playerPosition - doorPosition).Unit
   return primaryPart.CFrame.LookVector:Dot(direction) > 0 and -1 or 1
end

local function onProximityPromptTriggered(player)
   if DB then return end
   DB = true
   
   if isOpen then
   	isOpen = false
   	
   	local tween = TweenService:Create(primaryPart, tweenInfo, {CFrame = savedCFrame})
   	tween:Play()
   	tween.Completed:Wait()
   	-- Add logic to close the door after a delay if needed
   	
   	DB = false
   	
   	return
   	
   end
   
   isOpen = true
   
   local direction = getOppositeDirection(player)

   -- Calculate the target CFrame for the door
   local hingeCFrame = hinge.CFrame
   local rotation = CFrame.Angles(0, math.rad(openAngle) * direction, 0)
   local goalCFrame = hingeCFrame * rotation * hingeCFrame:Inverse() * primaryPart.CFrame

   local tween = TweenService:Create(primaryPart, tweenInfo, {CFrame = goalCFrame})
   tween:Play()
   tween.Completed:Wait()
   -- Add logic to close the door after a delay if needed

   DB = false
end

proximityPrompt.Triggered:Connect(onProximityPromptTriggered)
proximityPromptBack.Triggered:Connect(onProximityPromptTriggered)
1 Like