Tweening a Door Around a Hinge

Edit: in my pursuit for the best doors, I’ve found that there are much betters ways to do this. Is there a case where you might want to do it this way? Maybe, but probably not for a door. For now I would recommend tweening a hinge with a door welded to it on a LocalScript. Good luck! I’ll probably take this down or completely overhaul it someday, and probably just distribute a modulescript that gets the job. For now, here’s the original tutorial:
All the answers I’ve found to the question “tweening a door around a hinge” have been unsatisfactory. They either use a lerp, or tween the hinge itself which is welded to the unanchored door, or some other method, all of which haven’t been ideal solutions because the tweening (or use of TweenService2 or BoatTween) aspect has been crucial – and well, I don’t want unanchored parts. Here are the steps I went on to get this final result:
ezgif-7-fefdec9daf9d

  1. We gotta know what to do. I want to move a door across its hinge with all the TweenInfo goodness of Time and EasingStyle properties. I thought using CFrames was the way to go, and tried out this example for myself. Looks good!
  2. Let’s just change it up a bit so I can use TweenService. I should only need to keep track of the doors open and closed positioning… right? The following code produces the following result:
local door = script.Parent
local hinge = door.Parent.hinge
local tweenService = game:GetService("TweenService")
local tweenInfo = TweenInfo.new()
local offset = hinge.CFrame:Inverse() * door.CFrame
local doorOpen = tweenService:Create(door, tweenInfo, {CFrame = hinge.CFrame * CFrame.Angles(0, math.rad(90), 0) * offset})
local doorClose = tweenService:Create(door, tweenInfo, {CFrame = hinge.CFrame * CFrame.Angles(0, 0, 0) * offset})
wait(3)
doorOpen:Play()
wait(3)
doorClose:Play()

ezgif-7-50aa7deee72c

  1. The door is opening and closing, but definitely not around the hinge. The door needs to rotate on an axis about an angle, and not get translated and reoriented the shortest possible way to the destination. Here’s where I combine TweenService and the Heartbeat methods.
local door = script.Parent
local hinge = door.Parent.hinge
local tweenService = game:GetService("TweenService")
local tweenInfo = TweenInfo.new()
local offset = hinge.CFrame:Inverse() * door.CFrame
local doorOpen = tweenService:Create(door.Angle, tweenInfo, {Value = 90})
local doorClose = tweenService:Create(door.Angle, tweenInfo, {Value = 0})
game:GetService("RunService").Heartbeat:Connect(function(dt)
	door.CFrame = hinge.CFrame * CFrame.Angles(0, math.rad(door.Angle.Value), 0) * offset
end)
wait(3)
doorOpen:Play()
wait(3)
doorClose:Play()

ezgif-7-04f7d327965a
Look at that! It’s exactly like we want it, and it only took an extra three lines of code and an “Angle” NumberValue!
RobloxStudioBeta_s9yJFAyA4a
Obviously in this situation I didn’t want the hinge itself to rotate, but if you’ve gotten here I’m sure you can do it. Additionally, I didn’t make use of custom TweenInfo, opting for the defaults – but the option to give it a whole bunch of properties is now here with this solution to Tweening a Door Around a Hinge. Hope this is useful for some people. Any feedback would be appreciated, too!

31 Likes

Worth noting: parts that are welded to another one are treated as anchored. They derive their spatial coordinates from the part they attach to and only enter independent physics simulation when the weld is severed. In that regard, the whole model gets treated as a single assembly which is really performant if you want to move a model around. You can even use constraints to move a door.

Just wanted to make that known since I did write a tutorial on the latter “unsatisfactory” method you listed in the thread which I do know a lot of other developers had also been following for tweening models before I even wrote it out. To my knowledge, there’s no inherent performance loss or technical problem with doing it, but I can understand wanting to have alternatives! Interesting take by divorcing the hinge from the door so you have a truly static reference point.

Probably now I would encourage the use of pivots to tween models since it uses an internally performant method that caches CFrames. The main point behind the weld method was avoiding SetPrimaryPartCFrame because of the floating point imprecisions and tearing of models but with that fixed pivots are super ideal for moving models around.

9 Likes

Thanks for the reply! Of course using a lerp or weld are great solutions, and the primary reason I went about doing it this way is… sunk cost fallacy. I had a goal to do it this way, and didn’t want to entertain equally good solutions until I had finished with this. I’ll keep pivots in mind for future use!

5 Likes

You can just edit it’s pivot to the hinge and just edit it’s orientation or use a servo motor

7 Likes

Thank you for the tutorial! It works, I have a question though. How would I make the door open slower?

1 Like

for the tweenInfo variable, set it to TweenInfo.new(2). That way, it would be half as fast as the one in this tutorial. You could really do anything above the number 1, like TweenInfo.new(1.5) and the higher the number, the slower the animation.