Help with lift doors tweening

I am learning Lua and decided to try and make a lift as to better my understanding of tweening. The lift itself was fairly easy, although I’m sure I could have achieved a similar outcome with less code. The problem was with the doors. The doors should open when the lift reaches its destination. At the moment the doors don’t move. Any suggestions as to how I can generally improve my code would also be great.

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

local Lift = script.Parent
local LiPos = Lift.Position

local DURATION = 4

local Door11 = game.Workspace.Door11
local Door12 = game.Workspace.Door12
local Door21 = game.Workspace.Door21
local Door22 = game.Workspace.Door22
local Door31 = game.Workspace.Door31
local Door32 = game.Workspace.Door32

local CD1 = game.Workspace.Part1.ClickDetector
local CD2 = game.Workspace.Part2.ClickDetector
local CD3 = game.Workspace.Part3.ClickDetector

local Door1Open = false
local Door2Open = false
local Door3Open = false

local Tweenfo = TweenInfo.new(
	3,
	Enum.EasingStyle.Sine,
	Enum.EasingDirection.In,
	0,
	false,
	0
)

local Goals1 = 
{
	Position = Vector3.new(0,0,0)
}

local Goals2 = 
{
	Position = Vector3.new(0,15,0)
}

local Goals3 = 
{
	Position = Vector3.new(0,30,0)
}

local TweenLift1 = TweenService:Create(Lift, Tweenfo, Goals1)

local TweenLift2 = TweenService:Create(Lift, Tweenfo, Goals2)

local TweenLift3 = TweenService:Create(Lift, Tweenfo, Goals3)


CD1.MouseClick:Connect(function()
	if Door1Open == true or Door2Open == true or Door3Open == true then
		Door1Open = false
		Door2Open = false
		Door3Open = false
	end
	TweenLift1:Play()
	TweenLift1.Completed:Connect(function()
	Door1Open = true
	end)
end)

CD2.MouseClick:Connect(function()
	if Door1Open == true or Door2Open == true or Door3Open == true then
		Door1Open = false
		Door2Open = false
		Door3Open = false
	end
	TweenLift2:Play()
	TweenLift2.Completed:Connect(function()
		Door2Open = true
	end)
end)

CD3.MouseClick:Connect(function()
	if Door1Open == true or Door2Open == true or Door3Open == true then
		Door1Open = false
		Door2Open = false
		Door3Open = false
	end
	TweenLift3:Play()
	TweenLift3.Completed:Connect(function()
		Door3Open = true
	end)
end)

local function doorFunc()
	if Door1Open == true then
		Door11.CFrame = Door11.CFrame*CFrame.new(0,0,-5)
		Door12.CFrame = Door12.CFrame*CFrame.new(0,0,5)
	else
		Door11.CFrame = Door11.CFrame*CFrame.new(0,0,5)
		Door12.CFrame = Door12.CFrame*CFrame.new(0,0,-5)
	end
	
	if Door2Open == true then
		Door21.CFrame = Door21.CFrame*CFrame.new(0,0,-5)
		Door22.CFrame = Door22.CFrame*CFrame.new(0,0,5)
	else
		Door21.CFrame = Door21.CFrame*CFrame.new(0,0,5)
		Door22.CFrame = Door22.CFrame*CFrame.new(0,0,-5)
	end
	
	if Door3Open == true then
		Door31.CFrame = Door31.CFrame*CFrame.new(0,0,-5)
		Door32.CFrame = Door32.CFrame*CFrame.new(0,0,5)
	else
		Door31.CFrame = Door31.CFrame*CFrame.new(0,0,5)
		Door32.CFrame = Door32.CFrame*CFrame.new(0,0,-5)
	end
	
end

doorFunc()
2 Likes

You’re only calling doorFunc() once. You’ll need a loop if you want to constantly check if the elevator is at a floor.

However, preferably you’ll want to connect the TweenCompleted events of each button to open the doors on each floor.

3 Likes

Thanks for the reply. I was using heartbeat like so:

RunService.Heartbeat:Connect(function()
	if Door1Open == true then
		Door11.CFrame = Door11.CFrame*CFrame.new(0,0,-5)
		Door12.CFrame = Door12.CFrame*CFrame.new(0,0,5)
	else
		Door11.CFrame = Door11.CFrame*CFrame.new(0,0,5)
		Door12.CFrame = Door12.CFrame*CFrame.new(0,0,-5)
	end
	
	if Door2Open == true then
		Door21.CFrame = Door21.CFrame*CFrame.new(0,0,-5)
		Door22.CFrame = Door22.CFrame*CFrame.new(0,0,5)
	else
		Door21.CFrame = Door21.CFrame*CFrame.new(0,0,5)
		Door22.CFrame = Door22.CFrame*CFrame.new(0,0,-5)
	end
	
	if Door3Open == true then
		Door31.CFrame = Door31.CFrame*CFrame.new(0,0,-5)
		Door32.CFrame = Door32.CFrame*CFrame.new(0,0,5)
	else
		Door31.CFrame = Door31.CFrame*CFrame.new(0,0,5)
		Door32.CFrame = Door32.CFrame*CFrame.new(0,0,-5)
	end
	
end)

But this caused the doors to be moved in their respective directions once every frame.
Could you expand on connecting the TweenCompleted events?

Sure - I’d recommend storing your doors in a table for ease of access like so and then writing helper functions:

local Doors = {{game.Workspace.Door11, game.Workspace.Door12}, {game.Workspace.Door21, game.Workspace.Door22}}

function CloseDoors()
    for _,Door in pairs(Doors) do
        Door[1].CFrame = Door[1].CFrame * CFrame.new(0, 0, 5)
        Door[2].CFrame = Door[2].CFrame * CFrame.new(0, 0, -5)
    end
end

function OpenDoor(Door)
    Door[1].CFrame = Door[1].CFrame * CFrame.new(0, 0, -5)
    Door[2].CFrame = Door[2].CFrame * CFrame.new(0, 0, 5)
end

function OpenDoors()
    for _,Door in pairs(Doors) do
        OpenDoor(Door)
    end
end

CD1.MouseClick:Connect(function()
	CloseDoors()
	TweenLift1:Play()
	TweenLift1.Completed:Connect(function()
        	OpenDoor(Doors[1])
	end)
end)
2 Likes

Ah, yeah makes sense. I thought of using tables but I wasn’t sure how. Thanks for the help! Any idea on what the issue is with the doors?

Door11.CFrame*CFrame.new(0,0,-5) subtracts 5 studs to the door’s current position. So if you’re calling the function multiple times, it will keep moving the door. To prevent this, you can define start/end positions of the doors as variables and use those like Door11.CFrame = CFrame.new(0, 0, 0) or something. Maybe even using a relative offset to a floor part to determine where the door is suppose to be like Door11.CFrame = Door11Wall * CFrame.new(10, 0, -5) since the wall isn’t moving.

2 Likes

Makes sense. Quick question about the earlier code, why did you use two functions for the opendoor?

function OpenDoor(Door)
    Door[1].CFrame = Door[1].CFrame * CFrame.new(0, 0, -5)
    Door[2].CFrame = Door[2].CFrame * CFrame.new(0, 0, 5)
end

function OpenDoors()
    for _,Door in pairs(Doors) do
        OpenDoor(Door)
    end
end

Also, for the lift doors I need them moving in opposite directions, so would I need to tabulate them individually? If not how would I give them individual CFrame values?
e.g

local Doors = {game.Workspace.Door11, game.Workspace.Door12, game.Workspace.Door21, game.Workspace.Door22}

Originally I had

function OpenDoors()
    for _,Door in pairs(Doors) do
        Door[1].CFrame = Door[1].CFrame * CFrame.new(0, 0, -5)
        Door[2].CFrame = Door[2].CFrame * CFrame.new(0, 0, 5)
    end
end

which would’ve worked well but then I realized that after the lift finished moving, only one door would need to be opened, so I created a helper function that I could use in both functions. As for the reason why I created the OpenDoors() function… I don’t know cause you really only needed the CloseDoors() one.

The way I setup the table,
{{game.Workspace.Door11, game.Workspace.Door12}, {game.Workspace.Door21, game.Workspace.Door22}}
each entry has another table in it, which contains the two door parts. OpenDoor() will index into the 1st entry which is the left door (I think), while the 2nd entry is the right door and change the CFrame accordingly.

1 Like

How would I go about getting the individual doors from their respective tables?

You can do Doors[1][1] which would get Door11 or Doors[1][2] which would get Door22.

1 Like

Edited script:

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

local Lift = script.Parent

local Door11 = game.Workspace.Door11
local Door12 = game.Workspace.Door12
local Door21 = game.Workspace.Door21
local Door22 = game.Workspace.Door22
local Door31 = game.Workspace.Door31
local Door32 = game.Workspace.Door32

local CD1 = game.Workspace.Part1.ClickDetector
local CD2 = game.Workspace.Part2.ClickDetector
local CD3 = game.Workspace.Part3.ClickDetector

local Tweenfo = TweenInfo.new(
	3,
	Enum.EasingStyle.Sine,
	Enum.EasingDirection.In,
	0,
	false,
	0
)

local Goals1 = 
{
	Position = Vector3.new(0,0,0)
}

local Goals2 = 
{
	Position = Vector3.new(0,15,0)
}

local Goals3 = 
{
	Position = Vector3.new(0,30,0)
}

local TweenLift1 = TweenService:Create(Lift, Tweenfo, Goals1)

local TweenLift2 = TweenService:Create(Lift, Tweenfo, Goals2)

local TweenLift3 = TweenService:Create(Lift, Tweenfo, Goals3)


local Doors = {{game.Workspace.Door11, game.Workspace.Door12}, {game.Workspace.Door21, game.Workspace.Door22}, {game.Workspace.Door31, game.Workspace.Door32}}

local function CloseDoors()
    for _,Door in pairs(Doors) do
       Door[1][1].CFrame = Door[1][1].CFrame * CFrame.new(0, 0, -5)
       Door[2][1].CFrame = Door[2][1].CFrame * CFrame.new(0, 0, -5)
		Door[3][1].CFrame = Door[3][1].CFrame * CFrame.new(0,0,-5)
		Door[1][2].CFrame = Door[1][2].CFrame * CFrame.new(0, 0, 5)
       Door[2][2].CFrame = Door[2][2].CFrame * CFrame.new(0, 0, 5)
		Door[3][2].CFrame = Door[3][2].CFrame * CFrame.new(0,0,5)
    end
end

local function OpenDoor(Door)
    Door[1][1].CFrame = Door[1][1].CFrame * CFrame.new(0, 0, 5)
    Door[2][1].CFrame = Door[2][1].CFrame * CFrame.new(0, 0, 5)
	Door[3][1].CFrame = Door[3][1].CFrame * CFrame.new(0, 0, 5)
	 Door[1][2].CFrame = Door[1][2].CFrame * CFrame.new(0, 0, -5)
    Door[2][2].CFrame = Door[2][2].CFrame * CFrame.new(0, 0, -5)
	Door[3][2].CFrame = Door[3][2].CFrame * CFrame.new(0, 0, -5)
end

function OpenDoors()
    for _,Door in pairs(Doors) do
        OpenDoor(Door)
    end
end

CD1.MouseClick:Connect(function()
	CloseDoors()
	TweenLift1:Play()
	TweenLift1.Completed:Connect(function()
        	OpenDoor(Doors[1])
	end)
end)

CD2.MouseClick:Connect(function()
	CloseDoors()
	TweenLift2:Play()
	TweenLift2.Completed:Connect(function()
        	OpenDoor(Doors[2])
	end)
end)

CD3.MouseClick:Connect(function()
	CloseDoors()
	TweenLift3:Play()
	TweenLift3.Completed:Connect(function()
        	OpenDoor(Doors[3])
	end)
end)

The output is now throwing the error:
13:48:34.465 - 1 is not a valid member of Part

13:48:34.466 - Stack Begin

13:48:34.467 - Script ‘Workspace.Lift.Script’, Line 52 - function CloseDoors

13:48:34.467 - Script ‘Workspace.Lift.Script’, Line 93

13:48:34.467 - Stack End

Bit of a miscommunication here, you use Doors[1][1] to access Door11 from the Doors array. But in the function CloseDoors(), we’re already iterating over the array, so Door[1] is used to access Door11. In CloseDoors(), we’re closing all the doors by going over the array and setting the 1st and 2nd part of the Door.

1 Like

So how would I access door12 to CFrame it in the opposite direction? Sorry for my ineptitude and thanks for being so patient.

Try my CloseDoors() function as it is when I wrote it, then experiment with how to change it up to fit your needs but it should close the doors correctly.
You can also read up on tables in the wiki since it seems you’re a bit confused on them.

Just spent like 15 mins looking at your code and I think I understand. I think I’m just used to ‘v’ being used where ‘door’ was used, so I didn’t recognise that Door[1] is the first member of each door. I think it makes sense now, unless my reasoning is wrong, in which case it doesn’t make sense.

2 Likes