TweenModelService - Easily tween models

Have you ever tried to tween a model, but found out you couldn’t? That is finally over. I have created something that I call TweenModelService!

Here is a quick demo of me moving a free model building:

First, add a PrimaryPart to your Model.

Then add my Module to your game.
Get as a Lua File: TweenModelService.lua (2.1 KB)
Get as a .rbxm: TweenModelService.rbxm (1.6 KB)
Get as a Free Model: TweenModelService - Roblox

I would recommend putting my Module in ReplciatedStorage, but ServerStorage and ServerScriptService are fine if you dont want to tween models on the Client.

Once you have my module all set up, write this line of code:

local TweenModelService = require(game:GetService("ReplicatedStorage").TweenModelService)

You then can treat it exactly like you would with TweenService.

I created this example place here:
ExamplePlace.rbxl (41.1 KB)

Documentation

TweenModelService

Functions:

:Create(Model, TweenInfo, Dictionary) (ModelTween)

Creates a new ModelTween given the Model whose properties are to be tweened, a TweenInfo and a dictionary of goal property values.

ModelTween:

Properties:

Welds (Array):

An array of WeldConstraints that TweenModelService:Create() uses to make the Tween work.

Functions:


Events:

How does it work?

It welds every part together with WeldConstraints to the PrimaryPart, and moves the PrimaryPart to the goal. Once ModelTween:Destroy() is called, it will clean up the welds for you.

Let me know what you think, or if you found this useful, or if you have an update request.

17 Likes

This is (somewhat) of a clanky way for animating models. I’d actually recommend using AnimationControllers when possible because they’re both pre-baked and already host internal replication

Of course, when that’s not a viable option or you just don’t want to deal with dumb Roblox bugs this module is very well-made for what it’s worth. Good job!

5 Likes

I appreciate the effort, but why would you use an outdated approach? Instead of using welds, just set the pivot of the model using model:PivotTo(cFrame).

1 Like

Using Model:PivotTo() in a loop makes it choppy and not as smooth as this.

1 Like

Have you tried this approach?

local TweenService = game:GetService("TweenService")

local function TweenPivotTo(model, target: CFrame, tweenInfo: TweenInfo)
	local cframeValue = Instance.new("CFrameValue")
	cframeValue.Value = model:GetPivot()
	cframeValue:GetPropertyChangedSignal("Value"):Connect(function()
		model:PivotTo(cframeValue.Value)
	end)
	
	local tween = TweenService:Create(cframeValue, tweenInfo, {
		Value = target
	})
	tween.Completed:Connect(function()
		cframeValue:Destroy()
	end)
	tween:Play()
end

I’m not sure that’s correct. I made a module for tweening PVInstances based on their Pivot points before, and it ended up smooth no matter the framerate. My solution was to use a ghost part, tween that, and then call PVInstance:PivotTo(ghostPart.CFrame) every frame.

It’s far from optimal, but it worked smoothly and consistently, even on clients with unlocked framerates.

Isn’t this just the same as TweenService? You are still asking for the tween info, and have the exact same functions. It’s not easier in any way to use this.

It’s not meant to be easier to use than TweenService. It’s meant for tweening models - which have no properties TweenService can directly interact with.

It uses TweenServive, but it moves models. You can’t move models with TweenService alone.

Guys I think I’m late… but ill try it out!

Just use this:

-- TweenHandler.lua
local TweenHandler = {}

-------------------- Services --------------------
local TweenService = game:GetService("TweenService")
-------------------- Services --------------------

-------------------- Utils --------------------
local function tweenProperties(Object, Length, Style, Direction, Properties)
	local TweenObject = TweenService:Create(
		Object,
		TweenInfo.new(Length, Enum.EasingStyle[Style], Enum.EasingDirection[Direction]),
		Properties
	)

	TweenObject:Play()
	TweenObject.Completed:Connect(function()
		TweenObject:Destroy()
	end)

	return TweenObject
end

local function tweenModelCFrame(Model: Model, Length: number, Style: string, Direction: string, TargetCFrame: CFrame)
	if not Model:IsDescendantOf(workspace) then return end

	local CFrameValue = Instance.new("CFrameValue")
	CFrameValue.Value = Model:GetPivot()

	local TweenObject = TweenService:Create(
		CFrameValue,
		TweenInfo.new(Length, Enum.EasingStyle[Style], Enum.EasingDirection[Direction]),
		{ Value = TargetCFrame }
	)

	local CFrameChangedConnection = CFrameValue:GetPropertyChangedSignal("Value"):Connect(function()
		Model:PivotTo(CFrameValue.Value)
	end)

	TweenObject:Play()
	TweenObject.Completed:Connect(function()
		CFrameChangedConnection:Disconnect()
		CFrameValue:Destroy()
		TweenObject:Destroy()
	end)

	return TweenObject
end
-------------------- Utils --------------------

-------------------- Main --------------------
-- • Object        : Instance  | Model or BasePart
-- • Length        : number    | seconds
-- • Style,Direction : strings | Enum names, e.g. "Sine", "Out"
-- • Properties    : table     | {Property = Value} ; if Model + CFrame -> Pivot tween
function TweenHandler:AutoTween(Object: Instance, Length: number, Style: string, Direction: string, Properties: table)
	-- Model + CFrame path
	if Object:IsA("Model") and Properties.CFrame then
		return tweenModelCFrame(Object, Length, Style, Direction, Properties.CFrame)
	end

	-- Fallback: treat as BasePart (or any tween-able instance)
	return tweenProperties(Object, Length, Style, Direction, Properties)
end
-------------------- Main --------------------

return TweenHandler
2 Likes

this is essentially how TweenModelService works, you just added a wrapper that tweens properties too.

1 Like

@ScriptedHed
@laindecat
@neckbeard_tim
@sayer80

For anyone suggesting PivotTo(), CFraming the rootpart of a welded model is a lot better for performance. The reason is probably that the engine is optimized for moving welded models, whereas moving parts individually is slow. PivotTo() becomes significantly slower when moving models with a lot of unwelded parts, where a welded model doesn’t

(Also, changing the CFrame property or using PivotTo() is what causes a majority of the lag when moving parts around. For the best performance, BulkMoveTo() can be used on the rootpart of a welded model)

This isn’t something that can be found in the documentation, you have to test the performance yourself to figure this out

Also, using PivotTo() can give a smooth result if implemented correctly, but it will consume more resources on the player’s computer

2 Likes

Interesting, thanks a lot

I also thought of another optimization strategy:
What about rigging the Model & playing an animation locally on the client, I e.g. used that for spin / Ufos

1 Like