Before I do continue, I should note: CFrames are comprised of a positional and rotational value. Something that you may find trouble with is running two different tweens on the same part because one can override the other.
In your specific case you should be running one tween where any goals that need to be tweened on a part are all written to one table. That’d mean that CFrame and Orientation, although the former overwrites the latter, should have been in the same goals table for one CFrame.
Thanks for the question though! I think I’ll write up an additional section on this tutorial about using pivots to tween models and its benefits over the SetPrimaryPartCFrame version.
I’m not deeply acquainted with CFrames so finding a point of reference is up in the air. It would require moving to world space, getting a rotation goal and just a lot that I’d prefer not to think about. I primarily had novices in mind while designing this tutorial.
Personally if you really wanted to avoid using a hinge part to serve as your center of rotation and preferred to just work with a different PrimaryPart, you could use pivots as your reference point and then PivotTo. This would require returning to the old method of tweening models primarily because they account for variables inaccessible to the developer outside of Studio (pivot offset specifically).
Pivots would actually make this easier since they themselves can act as your point of reference. It’s ideal to still have a PrimaryPart but this appears in tune with your current problem so I can dive right into showing rotation with a pivot.
I did not save the original model I used in the tutorial so I’ll just bootleg it. Say hello to our new glass door™, a model where the PrimaryPart is set to the bottom of the door.
That blue-outlined white dot that’s appearing at the center of the bottom of the door, or the PrimaryPart, is the pivot. Roblox’s new pivot editor should allow you to redefine where this is positioned and rotated. Pivot points are powerful because they can help determine across where the model should be rotated. You can keep it at the bottom but just move it towards a point you want it to rotate across.
Here I’ve set my pivot to the edge of the door where a hinge part would normally be. This will be where my part rotates around. From there, we need to write a different piece of code that will get the pivot’s current CFrame, angle it and then pivot it to the goal. Since TweenService requires an instance to tween we’ll use a CFrameValue to simulate the change.
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local Panel = workspace.Panel
local function tweenModel(model, tweenInfo, offsetCFrame)
local modelPivot = model:GetPivot()
local steppedConnection
local CFrameValue = Instance.new("CFrameValue")
CFrameValue.Value = modelPivot
steppedConnection = RunService.Stepped:Connect(function ()
model:PivotTo(CFrameValue.Value)
end)
local tween = TweenService:Create(CFrameValue, tweenInfo, {Value = modelPivot * offsetCFrame})
tween.Completed:Connect(function ()
steppedConnection:Disconnect()
CFrameValue:Destroy()
tween:Destroy() -- Avoid memory leak from tween
end)
tween:Play()
end
This function takes three parameters to use:
-
model: Model → The model that you want to tween.
-
tweenInfo: TweenInfo → A TweenInfo object that you want passed for the model tween.
-
offsetCFrame: CFrame → A CFrame that your item should be offset by. You can evaluate CFrames (e.g. CFrame.new * CFrame.Angles), just needs to be one CFrame in the end.
If you wanted this to be reusable, a good fit would be turning this into a ModuleScript and adding return tweenModel
at the end. You can then require it and use it as a function whenever:
local tweenModel = require(path_to_module.TweenModel)
local tweenInfo = TweenInfo.new() -- Use all defaults
tweenModel(model, tweenInfo, CFrame.Angles(0, math.rad(180), 0))
Even if you didn’t want to use it as a ModuleScript and just put the function in your code, the function call would still work the same way. In terms of the offsetCFrame, you just need to describe how you want the door rotated. The function will calculate the pivot’s offset for you itself so that you don’t have to write like, Model:GetPivot() * CFrame
for the last argument. In this code example I’m just passing a CFrame with RX 0, RY rad(180) and RZ 0; the function translates this to “rotate the model 180 degrees (in radians) around the pivot”.
Note that since Studio mode does not simulate physics unless you are in a test mode that spawns a local server you will not be able to test how it looks while in editing mode.
Let me know if you have any questions or if you need further support!