There are actually a few ways to tween CFrames, but to keep things simple let's just keep it to what you suggested, linear interpolation (LERP).
The basic math behind lerping is:
3 | return a + ((b - a) * c); |
With this basic equation we can get a value between two points linearly. Now some clarification, linear doesn't mean the way we change c (as I'll explain in a bit), but rather that we essentially get from point a to be in a straight line. From a number standpoint this doesn't make much sense, but once we get into 3D this can become convoluted. Regardless, that's a topic for another time (google SLERP if you dare :P)
Right, so now that we understand the basis of lerping let's make our own CFrame lerp function:
1 | function lerpCf(a, b, c) |
3 | local a, b = { a:components() } , { b:components() } ; |
5 | newCf [ i ] = a [ i ] + ((b [ i ] - a [ i ] ) * c); |
7 | return CFrame.new( unpack (newCf)); |
Now luckily for us, Roblox has a built in lerp method (that I think might be more accurate(?)) so we don't have to have this function in our code. That being said, it's still useful to understand it.
So onto the tween. We have 3 pieces of information. The start CFrame, the end CFrame, and the time. So taking a look at that information and what we need for a lerp what are we missing? -- The c-value our percentage!
The question becomes how do we translate our time into that c-percentage? The answer is to use tick:
01 | function tweenCf(child, property, goal, t) |
02 | local start = child [ property ] ; |
03 | local stime, ctime = tick(), 0 ; |
05 | ctime = (tick() - stime); |
06 | child [ property ] = start:lerp(goal, ctime/t); |
09 | child [ property ] = goal; |
Now as mentioned above, we can also change how we handle the c-value by playing with what are called easing functions. They essentially change how the c-value move. Eg. It might be really fast at the start and slow down at the end, but it'll still add up to t seconds passed.
Here's an example:
01 | function tweenCf(child, property, goal, t, ease) |
02 | local start = child [ property ] ; |
03 | local stime, ctime = tick(), 0 ; |
05 | ctime = (tick() - stime); |
06 | child [ property ] = start:lerp(goal, ease(ctime, 0 , 1 , t)); |
09 | child [ property ] = goal; |
12 | function inOutQuad(t, b, c, d) |
15 | return c / 2 * math.pow(t, 2 ) + b; |
17 | return -c / 2 * ((t - 1 ) * (t - 3 ) - 1 ) + b; |
21 | local part = game.Workspace.Part; |
22 | tweenCf(part, "CFrame" , CFrame.new( 15 , 15 , 15 ) * CFrame.Angles(math.pi/ 4 , math.pi/ 4 , math.pi/ 4 ), 2 , inOutQuad); |
Here's a bit list of easing functions pre-written!
https://github.com/EmmanuelOga/easing/blob/master/lib/easing.lua