Door CFrame scripting

I completely realise there are multiple topics dedicated to doors. However, I don’t really think they answer my problems.
I am a beginner at scripting so I understand that my script for the door I am making is flawed to start with.
In my script I want to be able to click on the door and make it move 90 degrees in a smooth motion around a hinge part. How would I go about making it so that it doesn’t move by set increments every time I click but rather in a smooth, singular, movement. Would I need to use TweenService?
Also, how would I go about making the door return if the user clicked it again?

local hinge = game.Workspace.hinge
local door = game.Workspace.door

local HiPos = hinge.Position
local DURATION = 2

script.Parent.ClickDetector.MouseClick:Connect(function()
		local deg = 90*(tick()%DURATION)/DURATION
		door.CFrame = CFrame.new(HiPos)*CFrame.Angles(0,math.rad(deg),0)*CFrame.new(3.5,0,0)
	wait()
	end)
4 Likes

The MouseClick event only runs once each time you click it, meaning the door will simply teleport to the position you set it to. Instead, you should have a loop update the position of the door over time. The loop will know where to move the door based on a “DoorClosed” variable. To change whether the door is closed or not, simply set DoorClosed to true or false when the player clicks.

I would recommend using the CFrame:Lerp() function for simplicity since you are a beginner.
If you’re confused as to what Lerp does, it simply moves one value towards another value by a given increment. In this example the door moves 10% closer to the open or closed CFrame every time the loop runs.

local hinge = game.Workspace.hinge
local door = game.Workspace.door

local HiPos = hinge.Position

local ClosedCFrame = CFrame.new(HiPos)*CFrame.new(3.5,0,0)
local OpenCFrame = CFrame.new(HiPos)
	*CFrame.Angles(0,math.rad(90),0)
	*CFrame.new(3.5,0,0)

local DoorClosed = true

script.Parent.ClickDetector.MouseClick:Connect(function()
	if DoorClosed == true then
		DoorClosed = false
	else
		DoorClosed = true
	end
end)

while true do
	wait()
	if DoorClosed == true then
		door.CFrame = door.CFrame:Lerp(ClosedCFrame,0.1)
	else
		door.CFrame = door.CFrame:Lerp(OpenCFrame,0.1)
	end
end
5 Likes

Thanks for the reply. I like the lerp I idea. At first I dismissed it because I forgot you could move a part to given coordinates rather than towards another part. Whilst I understand why this is here:

script.Parent.ClickDetector.MouseClick:Connect(function()
	if DoorClosed == true then
		DoorClosed = false
	else
		DoorClosed = true
	end
end)

I’ve never really understood how it works. Could you explain it in a little more detail?

The code you question simply sets DoorClosed to true if it’s false, or sets DoorClosed to false if it’s true. Since the while loop checks whether DoorClosed is true in order to decide where to lerp the door, it effectively opens and closes the door each time you click.

Alternatively, if you don’t like the way Lerp is moving the door, you can use frame time and some simple math to set the cframe of the door. This is much more difficult for a beginner though, which is why I provided the lerp method first. This code may be good to learn from in the future. If you don’t want to use heartbeat, you can use tick() to calculate the frame time yourself.

local hinge = workspace.hinge
local door = workspace.door

local DURATION = .5
local ANGLE = 90

local DoorClosed = true
local CurrentAngle = 0

script.Parent.ClickDetector.MouseClick:Connect(function()
	if DoorClosed == true then
		DoorClosed = false
	else
		DoorClosed = true
	end
end)

game:GetService("RunService").Heartbeat:Connect(function(delta)
	local Adjustment = ANGLE*(delta/DURATION)
	if DoorClosed then
		if CurrentAngle - Adjustment > 0 then
			CurrentAngle = CurrentAngle - Adjustment 
		else
			CurrentAngle = 0
		end
	else
		if CurrentAngle + Adjustment < ANGLE then
			CurrentAngle = CurrentAngle + Adjustment 
		else
			CurrentAngle = ANGLE
		end
	end

	door.CFrame = hinge.CFrame
		*CFrame.Angles(0,math.rad(CurrentAngle),0)
		*CFrame.new(door.Size.x/2,0,0)
end)

I’ve additionally set the door to use the current hinge CFrame as the pivot, so you can rotate and tilt the hinge and have the door stay aligned.

If you’re curious:

tick() - returns the number of seconds since january 1 1970. It’s a function for keeping track of how much time has passed. It’s not used in this example, but it could be if you wanted to use a loop rather than heartbeat

RunService.Heartbeat - An event that repeats 60 times per second. The delta argument is how much time has passed since the last time the event ran (usually 1/60th of a second).

3 Likes

Thanks for the explanation. The alternative way actually makes sense to me as well. There is a little bit of syntax I need to research, like Heartbeat.