BetterTween | A tweening module that fixes many of the built in tween drawbacks

Introduction

BetterTween is an improved version of a module I made a while ago for a friend. After making the basic framework of BetterTween for said friend I received multiple requests to open source it so I decided to package it up into a easy to use module for public use.

notable features:

Tween to moving object
tween along 3 point Bezier curve
.Touched works mid tween
scrub through tween

features I want to implement:

ability to tween values other then cframe
tween along Bezier curves exceeding 3 points
tween along custom equations

usage

first, download the module here, or get it off github here.

There are 5 main functions and 1 constructor within the module. These are shown below along with definitions:

local BetterTween = require(game.ReplicatedStorage.BetterTween) --requires module.

local Tween1 = BetterTween.new(PartToTween, StartingCF, EndingCF, TweenInfo, Waypoint) --construct new tween. TweenInfo and Waypoint are both optional.
Tween1:Start() --play/start tween
Tween1:Pause() --pause tween
Tween1:Resume() --resume tween
Tween1:Cancel() --abort tween, if you dont plan on resuming a tween use this instead of pause to save resources.
Tween1:Scrub(ScrubPoint) --basically lerp but for a tween. ScrubPoint is a number between 0 and 1, 0 is 0% through the tween and 1 is 100%.

allow me to explain the constructor parameters better. We have 5 parameters, 2 of which are optional.
PartToTween: This is the part you want to actually tween. This is what gets moved throughout the tween.
StartingCF: Starting CFrame for your tween. 99% of the time it will be PartToTween.CFrame.
EndingCF: CFrame you want your part to end at; this can either be a part or a CFrame. If you plan on having a dynamic end position use a part as moving the part will also update the tween trajectory and cause the PartToTween to adjust. If you want a static end point pass a CFrame as that CFrame will not be changed and so the tween trajectory will remain constant.
TweenInfo (optional): this is the TweenInfo you want to use. If no info is specified it will be set to a blank TweenInfo.new().
Waypoint (optional): This is an optional CFrame you can include if you want to tween across a Bezier curve. This acts as the middle point which will modify the trajectory, it does not effect the StartingCF or EndingCF at all.

adding .Touched events and other fun stuff

after creating a new BetterTween you can reference the part you are tweening with (BetterTween).target; you can then use this to set up .Touched events and other cool stuff.

code examples

here are some basic use case examples.

create tween with Bezier curve and dynamic endpoint and then play it

local BetterTween = require(game.ReplicatedStorage.BetterTween)

local Tween1 = BetterTween.new(
	workspace.Part1,
	workspace.Part1.CFrame, 
	workspace.Part2, 
	TweenInfo.new(3,Enum.EasingStyle.Exponential,Enum.EasingDirection.In), 
	workspace.Part3.CFrame
)
Tween1:Start()

create tween, play it, then pause and scrub through it

local BetterTween = require(game.ReplicatedStorage.BetterTween)

local Tween1 = BetterTween.new(
	workspace.Part1,
	workspace.Part1.CFrame, 
	workspace.Part2.CFrame, 
	TweenInfo.new(3,Enum.EasingStyle.Exponential,Enum.EasingDirection.In)
)
coroutine.wrap(function()
	Tween1:Start()
end)()
wait(2.5)
Tween1:Pause()
wait(1)
Tween1:Scrub(0.2)
wait(1)
Tween1:Scrub(0.3)
Tween1:Cancel()

create tween then setup .Touched event for it

local BetterTween = require(game.ReplicatedStorage.BetterTween)

local Tween1 = BetterTween.new(
	workspace.Part1,
	workspace.Part1.CFrame, 
	workspace.Part2.CFrame, 
	TweenInfo.new(3,Enum.EasingStyle.Exponential,Enum.EasingDirection.In)
)

Tween1.target.Touched:Connect(function()
	print("Touched")
end)

Tween1:Start()

putting it all together

local BetterTween = require(game.ReplicatedStorage.BetterTween)

local Tween1 = BetterTween.new(
	workspace.Part1,
	workspace.Part1.CFrame, 
	workspace.Part2, 
	TweenInfo.new(3,Enum.EasingStyle.Exponential,Enum.EasingDirection.In), 
	workspace.Part3.CFrame
)

Tween1.target.Touched:Connect(function()
	print("Touched")
end)

coroutine.wrap(function()
	Tween1:Start()
end)()
wait(1.5)
Tween1:Pause()
wait(2)
Tween1:Resume()
wait(1)
Tween1:Pause()
wait(1)
Tween1:Scrub(0.2)
wait(1)
Tween1:Scrub(0.3)
Tween1:Cancel()

thank you for reading this all if you got this far! Any questions/comments/issues? Feel free to comment!

11 Likes

This is one of those occasional amazing resources that gets posted here. The default tweening service kinda sucks when it comes to curved paths, so yeah I will definitely snatch up this module.

1 Like

Glad to hear it! I was honestly surprised by the lack of advanced tweening modules out, I would have thought that at least one high quality one would have been released by now but I guess not.

Hopefully I can get more curvature types implemented in the future as the basic 3 point Bézier is kinda restrictive. Ideally I could implement some form of interpolation via equations as that would lead to basically limitless curve possibilities however I don’t know how the input would look for that especially considering the fact that you would need an X, Y, and Z equation.

2 Likes

github repo? so we can see the code without have to download it

just made one, here you go. (sorry if I made it wrong or formatted it incorrectly, I rarely use github :face_with_spiral_eyes:)

u should use task.wait as wait and PreSimulation for a newer version of Stepped.

Stepped, Heartbeat and RenderStepped events will be deprecated soon once new 4 events are added to RunService. Here is the updated version:

PreRender: Equivalent of old RenderStepped event. Fires at every frame, after user input is handled and before rendering operation of frame starts. Both PreRender and RenderStepped can be only used on localscripts or modulescripts required by localscripts and fire rate of the event is dependent on clients FPS rate. This is the 1st event that fires, out of 4.

PreAnimation: This is the only truly new event out of the 4 new events. It fires before humanoid animations are applied. This fires after PreRender event.

PreSimulation: Equivalent of old Stepped event. It fires before simulation of physics starts. This is the 3rd event that fires after PreAnimation event.

PostSimulation: Equivalent of old Heartbeat event. It fires after simulation of physics finished. This is the event that fires in last place.

Credit: @BenMactavsin

2 Likes

I have a small question, does it work using beam, it would be interesting!

what beam? #igronethisokjfjdjdjjdeeee