local function moveCar(car)
local dest = workspace.Area.Despawn
local carToMove = car
local tween = TweenService:Create(car, TweenInfo.new(4.5, Enum.EasingStyle.Linear, Enum.EasingDirection.Out), {Position = Vector3.new(workspace.Area.Despawn.Position.X, car.Position.Y, workspace.Area.Despawn.Position.Z)})
end
local function spawnCar()
local car = chooseCar()
for i, v in pairs(Spawnables:GetChildren()) do
if v.Name == car then
local clone = v:Clone()
local carInfoClone = carInfo:Clone()
clone.Parent = workspace.SpawnedCars
local newCF = CFrame.new(Vector3.new(workspace.Area:FindFirstChild("Road Spawn").Position.X, workspace.Area:FindFirstChild("Road Spawn").Position.Y + .5, workspace.Area:FindFirstChild("Road Spawn").Position.Z))
moveCar(clone)
clone:PivotTo(newCF)
carInfoClone.Parent = clone
carInfoClone:FindFirstChild("MainFrame").CarName.Text = clone.Name
carInfoClone:FindFirstChild("MainFrame").CarPrice.Text = "$"..tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Price").Value)
carInfoClone:FindFirstChild("MainFrame").CarRarity.Text = tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Rarity").Value)
end
end
end
You will need to end up choosing a part which will be the primary part - you may not need to set it in the model property though.
The way to move a model using tween service is to have each object (except the primary part) unanchored and welded to the primary part. Then, you would use TweenService to adjust the CFrame (NOT Position) of the primary part. If done correctly, the whole model should move along with the primary part.
You can move a Model with 2 methods (there are more but i use these):
Using a PrimaryPart and Welding everything
Using PivotTo calls and doing a CFframe Interpolation, you would need to code the easing styles yourself. Its more computive too.
local styles = {
linear = function(t)
return 1 - (1 - t)^2
end,
easeOutQuad = function(t)
return 1 - (1 - t)^2
end,
}
local function moveModel(model, style, targetCFrame, duration)
local startCFrame = model:GetPivot()
local startTime = tick()
local connection
connection = game:GetService("RunService").Heartbeat:Connect(function()
local t = (tick() - startTime) / duration
if t >= 1 then t = 1 end
local cframe = startCFrame:Lerp(targetCFrame, styles[style](t))
model:PivotTo(cframe)
if t >= 1 then
connection:Disconnect()
end
end)
return connection
end
local function TweenModelToCFrame(model: Model, info: TweenInfo, result: CFrame)
local cframe = Instance.new("CFrameValue") do
cframe.Value = model:GetPivot()
end
cframe:GetPropertyChangedSignal("Value"):Connect(function()
model:PivotTo(cframe.Value)
end)
local tween = TweenService:Create(cframe, info, {Value = result})
tween:Play()
tween.Completed:Wait()
cframe:Destroy()
return true -- ignore, but can be helpful if you want to wait until the tween is done
end
Not sure if its me or not, when I used that method and i applied rotation and positioning really fast or in different times, it makes the parts shift in the model. Also here is the devforum post you are looking for:
I implemented the function into your code, so i think this could work.
local tweenService = game:GetService("TweenService")
local info = TweenInfo.new(4.5, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
local function tweenModel(model, CF)
local CFrameValue = Instance.new("CFrameValue")
CFrameValue.Value = model:GetPrimaryPartCFrame()
CFrameValue:GetPropertyChangedSignal("Value"):Connect(function()
model:SetPrimaryPartCFrame(CFrameValue.Value)
end)
local tween = tweenService:Create(CFrameValue, info, {Value = CF})
tween:Play()
tween.Completed:Connect(function()
CFrameValue:Destroy()
end)
end
local function spawnCar()
local car = chooseCar()
for i, v in pairs(Spawnables:GetChildren()) do
if v.Name == car then
local clone = v:Clone()
local carInfoClone = carInfo:Clone()
clone.Parent = workspace.SpawnedCars
local newCF = CFrame.new(Vector3.new(workspace.Area:FindFirstChild("Road Spawn").Position.X, workspace.Area:FindFirstChild("Road Spawn").Position.Y + .5, workspace.Area:FindFirstChild("Road Spawn").Position.Z))
tweenModel(clone, newCF)
carInfoClone.Parent = clone
carInfoClone:FindFirstChild("MainFrame").CarName.Text = clone.Name
carInfoClone:FindFirstChild("MainFrame").CarPrice.Text = "$"..tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Price").Value)
carInfoClone:FindFirstChild("MainFrame").CarRarity.Text = tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Rarity").Value)
end
end
end
Thank you everyone for the replies!! So for what I understand, I need to make a “hitbox” and weld every part of the model to that hitbox. Then set the primary part to the model and tween it?
This could work but is over engineered and not very efficient as it limits how you can build with the model. PivotTo works like set primary part cframe except without a part and every descendant will follow. Check out @Clxzed and my reply. It should work fine with a cframe value
I personally use this approach, since it works right off the bat without any sort modifications nor limits set on the model you’re tweening.
Tho I rather use Heartbeat or such instead of value.Changed. not sure if it makes that big of a difference, but afaik .Changed doesn’t always fire with repeated property changes and imo just feel odd to use.
I never played the tween in the function, I return it in case you want to connect any completed signals of your own, so you have to manually play the tween. You can change this in the function if you don’t plan on using the tween instance
What exactly are you trying to achieve? A driveable car, or just some cutscene-type thing? Also, just saying “It didn’t work” doesn’t help. That means you did something wrong, in which case you should show us what you did.
My bad, I am trying to make those “Steal a car” type games, and i want to tween the car to the despawn area.
This is the code i used:
local function tweenModel(model, inf, targetCFrame)
local temp = Instance.new("CFrameValue")
temp.Value = model:GetPivot()
local tween = tweenService:Create(temp, inf, {Value = targetCFrame})
tween.Completed:Once(function() temp:Destroy() end)
temp.Changed:Connect(function(newCFrame)
model:PivotTo(newCFrame)
end)
return tween
end
local function spawnCar()
local car = chooseCar()
for i, v in pairs(Spawnables:GetChildren()) do
if v.Name == car then
local clone = v:Clone()
local carInfoClone = carInfo:Clone()
clone.Parent = workspace.SpawnedCars
local newCF = CFrame.new(Vector3.new(workspace.Area:FindFirstChild("Road Spawn").Position.X, workspace.Area:FindFirstChild("Road Spawn").Position.Y + .5, workspace.Area:FindFirstChild("Road Spawn").Position.Z))
tweenModel(clone, info, CFrame.new(Vector3.new(workspace.Area.Despawn.Position.X, workspace.Area:FindFirstChild("Road Spawn").Position.Y + .5, workspace.Area.Despawn.Position.Z)))
clone:PivotTo(newCF)
carInfoClone.Parent = clone
carInfoClone:FindFirstChild("MainFrame").CarName.Text = clone.Name
carInfoClone:FindFirstChild("MainFrame").CarPrice.Text = "$"..tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Price").Value)
carInfoClone:FindFirstChild("MainFrame").CarRarity.Text = tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Rarity").Value)
end
end
end
Change does always fire, infact improper use with immediate signals can crash your game (though this is fixed with the deferred signals update). Using changed also lets you skip an extra read since it’s given in the function (but this is micro optimization so really doesn’t matter). I would actually recommend against using heartbeat though because tweens update after heartbeat and will result in the loop reading the property of the previous frames tween update, this could potentially result in skipping a frame of the tween. However both methods work fine.
Update, I tried the welding method and managed to move something… That something is the billboard gui above the car. It somehow moves that but the model is standing still inside the spawn area.
local function moveCar(car)
if car then
local primaryPart = car.PrimaryPart
local tween = tweenService:Create(primaryPart, info, {Position = Vector3.new(workspace.Area.Despawn.Position.X, workspace.Area.Despawn.Position.Y, workspace.Area.Despawn.Position.Z)})
tween:Play()
end
end
local function spawnCar()
local car = chooseCar()
for i, v in pairs(Spawnables:GetChildren()) do
if v.Name == car then
local clone = v:Clone()
local carInfoClone = carInfo:Clone()
clone.Parent = workspace.SpawnedCars
local newCF = CFrame.new(Vector3.new(workspace.Area:FindFirstChild("Road Spawn").Position.X, workspace.Area:FindFirstChild("Road Spawn").Position.Y + .5, workspace.Area:FindFirstChild("Road Spawn").Position.Z))
clone:PivotTo(newCF)
moveCar(clone)
carInfoClone.Parent = clone
carInfoClone:FindFirstChild("MainFrame").CarName.Text = clone.Name
carInfoClone:FindFirstChild("MainFrame").CarPrice.Text = "$"..tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Price").Value)
carInfoClone:FindFirstChild("MainFrame").CarRarity.Text = tostring(clone:FindFirstChild("CarStats"):FindFirstChild("Rarity").Value)
end
end
end
You have to unachor everything else except for the primarypart. And Weld everything to the primarypart. Also The solution with cframe values, if the tween doesnt finish and you call it again, it shifts the parts inside the model.