Update November 2015:
Using PrimaryPart
Since writing this post, ROBLOX has changed a lot in regards to the API. To move a model like requested, you should set the PrimaryPart property of the model to a central part inside the model. This will act as the origin
for the model's movements.
You can then use model:SetPrimaryPartCFrame(cframe)
to set the CFrame of the model. You can also retrieve this property by using model:GetPrimaryPartCFrame()
, although I believe that is just a shortcut method for model.PrimaryPart.CFrame
.
In code, it would look like this:
-- Set PrimaryPart:
MODEL.PrimaryPart = MODEL.SomeCentralPart
...
-- CFrame movement:
local movement = CFrame.new(0, 10, 0)
-- Move the model:
MODEL:SetPrimaryPartCFrame(MODEL:GetPrimaryPartCFrame() * movement)
Option A: Use Model's methods
I think you are making this much more difficult than it needs to be. Whenever you run into an issue like this, be sure to check the current APIs provided. The ROBLOX Model object contains a nifty method called 'TranslateBy' which takes a Vector3 argument to translate the model.
Using MODEL:TranslateBy(Vector3)
is similar to moving a model via CFrame, since it ignores collisions.
Another alternative is MODEL:MoveTo(Vector3)
which moves a whole model to the given Vector3 world position. The downside to this is that it does collide.
One way to get the same MoveTo effect but without collisions can be done with the TranslateBy method:
MODEL:TranslateBy(Vector3Position - MODEL:GetModelCFrame().p)
Option B: Write a custom function to manipulate the model's CFrame
Another alternative would be to manipulate the whole model's CFrame entirely. To do this, you can write a clever function that will move a whole model relative to an 'origin' point. This is similar to moving shapes on a grid given their points and an origin, except in three dimensions. Using ROBLOX's built-in functions, this is much easier though.
A good way to do this would be to write a function that lets you actually assign a CFrame value to a whole model. Another way would be to allow a translation via CFrame too.
Here's an example:
function ModelCFrameAPI(model)
local parts = {} -- Hold all BasePart objects
local cf = {} -- API for CFrame manipulation
do
-- Recurse to get all parts:
local function Scan(parent)
for k,v in pairs(parent:GetChildren()) do
if (v:IsA("BasePart")) then
table.insert(parts, v)
end
Scan(v)
end
end
Scan(model)
end
-- Set the model's CFrame
-- NOTE: 'GetModelCFrame()' will return the model's CFrame
-- based on the given PrimaryPart. If no PrimaryPart is provided
-- (which by default is true), ROBLOX will try to determine
-- the center CFrame of the model and return that.
function cf:SetCFrame(cf)
local originInverse = model:GetModelCFrame():inverse()
for _,v in pairs(parts) do
v.CFrame = (cf * (originInverse * v.CFrame))
end
end
-- Translate the model's CFrame
function cf:TranslateCFrame(deltaCf)
local cf = (model:GetModelCFrame() * deltaCf)
self:SetCFrame(cf)
end
return cf
end
-- Usage:
local myModel = game.Workspace.SOME_MODEL
local myModelCF = ModelCFrameAPI(myModel)
-- Move to 10,10,10 and rotate Y-axis by 180 degrees:
myModelCF:SetCFrame(CFrame.new(10, 10, 10) * CFrame.Angles(0, math.pi, 0))
-- Translate by 30,0,-10 and rotate Y-axis by 90 degrees
myModelCF:TranslateCFrame(CFrame.new(30, 0, -10) * CFrame.Angles(0, math.pi/2, 0))