Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How do you rotate a part as if it were on a hinge?

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.

1 answer

✓ Accepted answer

First of all: Rotation is basically useless for scripts, don't bother using it.

Instead, always use CFrame to control the orientation of parts.


Pretend there's a hinge part

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)

Removing the hinge

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)

Animating

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

This discussion is preserved as it was. New answers, comments, and votes are closed.