Model Lock, A Better Alternative To SetPrimaryPartCFrame

OUTDATED, USE PIVOTTO()!!!

Hello,

SetPrimaryPartCFrame is unreliable, since it causes slight gaps to appear in a model when used. I made a better alternative to do pretty much the same thing, but without gaps. Basically, what this module does is lock all parts in a model to the base, so whenever it moves the other parts move with it.

You can get the module here or by using require(5803034365)

Functions:

ml:Lock(Model,PartToLockTo)
Locks descendants of the model to the desired part, (does not need to be inside the model). If the part you want to lock to is not provided, it will use the primary part of the model. If that is also not present, the function will warn in the output and ignore the request. If the model is already locked, it will unlock it, then relock it to the new part.

ml:Unlock(Model)
Unlocks the model. I included this function just in case it was needed. If the model isn’t locked, the function will warn in the output and ignore the request.

How To Use:

I put together a quick example, showing you how to use this module with a simple door tween. Here, I have all the parts of the door included in a model, with the button being in workspace. The main part of the door is named Base, which will be the part we lock the model to later.
ft5CoqMqEn

This script tweens the door up, then down when the button is clicked. Only tween the part the model is locked to.

local ts = game.TweenService
local door = workspace.Door
local button = workspace.Button.ClickDetector
local opening = false
local ml = require(5803034365)
local tweeninfo = TweenInfo.new(4,Enum.EasingStyle.Linear)

--Since we probably wont be needing to modify this model much, it's best to lock it now
ml:Lock(door,door.Base)
--Yep, this is all we need to do to move our whole model with the base


--Simple opening and closing script
button.MouseClick:Connect(function()
if not opening then
opening = true

--Make sure you only tween the part you locked the model to
local tween = ts:Create(door.Base,tweeninfo,{Position = door.Base.Position + Vector3.new(0,40,0)})
tween:Play()
tween.Completed:Wait()
wait(4)
local tween = ts:Create(door.Base,tweeninfo,{Position = door.Base.Position - Vector3.new(0,40,0)})
tween:Play()
tween.Completed:Wait()


opening = false
end
end)

If done right, this should be the end result:
FL3DTMkK1A

This is a direct comparison between using this module and SetPrimaryPartCFrame. A time lapse of two spinners going for 10 minutes is shown, and then they are examined.
timelapse

If you find any bugs, or have a suggestion, please message me or tell me here.

20 Likes

Nice, this is a big issue for models with lots of parts.

Performance implications though? I would assume that the moving part limit is a lot lower than for the Roblox API. I kind of wish Roblox could adjust this on their end but nice work, I doubt people will reach the performance gap unless they start building wind farms. Maybe that would be a good idea to demonstrate the limitations comparison.

1 Like

The reason :SetPrimaryPartCFrame() loses precision is because it uses the current CFrame offset, allowing you to change the CFrame of individual parts and keep it after calling the method.

So, if your PrimaryPart’s Position is (0,0,0) and you set the position of one of the parts to (10,0,0), after calling :SetPrimaryPartCFrame(), the offset will still be (10,0,0).

With your module, in order to achieve the same behavior, you have to first call .Unlock(), set the CFrame, then call .Lock() again each time you want to move an individual part.

Another thing to note is that it could have been made much more efficient by using welds. Keep them in a container inside the PrimaryPart. Set Part1 property to nil when .Unlock() is called to avoid recreating all of the welds.

3 Likes