In the game i'm making I want the door to open like an actual door, with one edge staying in place and the rest rotating open. I may be missing something very obvious, but the rotation only rotates it from the center of the part. I intend to make it smooth, and I also need help with this. Whenever i use a for loop, for example:
a=script.Parent for i = 1,1000 do a.Rotation=a.Rotation+Vector3.new(1,1,1) end
It glitches out and stops rotating, so I also need a bit of help with this
I assume it has something to do with CFrame, but I am very new to this section of coding and such (I'm better with GUIs and such)
An example code would be great, wiki links are also appreciated.
First of all: Rotation
is basically useless for scripts, don't bother using it.
Instead, always use CFrame
to control the orientation of parts.
Imagine you have a part representing your hinge.
As the door swings, the hinge turns around its center -- which is easy to accomplish. Visualization as GIF.
If we have a hinge
, to turn it around its center we can just multiply by a "rotation CFrame" which we make with CFrame.Angles
.
hinge.CFrame = hinge.CFrame * CFrame.Angles(0, 1, 0)
Note that CFrame.Angles
uses radians, not degrees. 1 radian is a bit less than 57 degrees; this is so that there are 2pi radians in a full circle (equivalently there are 360 degrees in a circle).
However, we want the door to move with the hinge. To do that, we can measure the placement of the door relative to the hinge, and then move it relative to the new orientation of the hinge.
You can get how b
is relative to a
using relative = a.CFrame:toObjectSpace(b.CFrame)
. If you want to place b
relative to a
, you can use b.CFrame = a.CFrame:toWorldSpace(relative)
.
-- relative to the hinge, where is the door? local relative = hinge.CFrame:toObjectSpace(door.CFrame) -- twist the hinge hinge.CFrame = hinge.CFrame * CFrame.Angles(0, 1, 0) -- re-attach the door to the hinge door.CFrame = hinge.CFrame:toWorldSpace(relative)
You don't necessarily want a hinge part for every door, so ideally that wouldn't be there.
The trick is that you can find the hinge's CFrame relative to the door.
If your door is 5 x 7 x 1 (like the one is in my GIF) you can locate the left edge of the door by multiplying by a translation CFrame created with CFrame.new
. The center of the door is (0, 0, 0)
, so the left edge would be (-2.5, 0, 0)
:
-- locate the hinge on the door local hingeBefore = door.CFrame * CFrame.new(-2.5, 0, 0) -- relative to the hinge, where is the door? local relative = hingeBefore:toObjectSpace(door.CFrame) -- twist the hinge local hingeAfter = hingeBefore * CFrame.Angles(0, 1, 0) -- re-attach the door to the new "hinge" door.CFrame = hingeAfter:toWorldSpace(relative)
We can wrap up this into a nice function like this:
-- swing the door by `angle` degrees function swingDoor(angle) -- locate the hinge on the door local hingeBefore = door.CFrame * CFrame.new(-2.5, 0, 0) -- relative to the hinge, where is the door? local relative = hingeBefore:toObjectSpace(door.CFrame) -- twist the hinge -- CONVERT angle *from* degrees *to* radians here local hingeAfter = hingeBefore * CFrame.Angles(0, math.rad(angle), 0) -- re-attach the door to the new "hinge" door.CFrame = hingeAfter:toWorldSpace(relative) end
And then just call this function repeatedly to animate it opening/closing:
while true do wait(1) for i = 1, 100 do swingDoor(1) wait() end wait(1) for i = 1, 100 do swingDoor(-1) wait() end end