Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

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

Asked by 7 years ago

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

Log in to vote
3
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
7 years ago

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
Ad

Answer this question