How Would I Get A Model to Rotate and Tween at the Same Time?

I gave him my solution just because yours doesn’t work (key elements are missing that should be take in consideration). He can chose what is helpful

Actually ‘THE’ key element is missing in your over complicated solution. Easing that was the question and you didn’t give an answer. And the wealth of knowledge in those completely redundant comments (You get it!). And none of your code actually works without more coding:

	Tween:Play() -- you get it 
	Tween.Completed:Wait()-- you get it 

Tween isn’t even defined, pffft. Mine worked out of the tin!

Ok, I just came back and I am still confused. I think I maybe need more background knowledge of some of the code you’re using, because, while you are explaining it, It’s still kind of hard for me to follow what’s going on.
But, I’m still going to try summarizing the code, and I’m just gonna see if I’m correct on this.

We set the UpDownVector and the UdValue. We then set up some code so that every time the tween changes the Vector position of the object, it gets updated. The RotateFrame gets introduced, and we make a value for the RotateFrame as well, as well as also making sure it gets updated when the rotate frame gets changed by the tweening.
We then make the UpDownTween, consisting of editing the UDvalue,(?) some TweenInfo that only contains one number (?) and having the goal position 100 studs above the current position of the pivot of the Model. (One of the only things I fully understand here) We also do the same thing (not exactly) for the rotation. Both of them say something about being able to adjust the EasingStyles, but I can’t find anything with the EasingStyles mentioned. I may have to add it into the TweenInfo, but I’m so confused that I can’t tell what I’m allowed to put there without breaking everything.

But, that alone doesn’t do anything. No errors, but nothing happening. So, let’s move on to the 2nd Part.

I don’t understand what you mean by render step or frame rate, (I understand what frame rate is, I just don’t understand why I’d want to render it at a specific frame rate) and the only part of this I understand is that we are Pivoting the model to the UpDownVector multiplied by Rotate frame, so I’m going to copy and paste the code at the end and hope It doesn’t create a heck ton of errors.

Alright, It tells me RenderStepped can only be done from a local script. However, I want to do this from a server standpoint.

Because I finally hit an error, I’ll stop tying and let you read this 5 paragraph essay I typed.

Basically, I mainly don’t understand the Vector3 Values and how they affect the Tween.

If you want it to work indefinitely, TweenInfo should be defined like this.

TweenInfo.new(YourTimeRange,Enum.EasingStyle.Circular,Enum.EasingDirection.In,-1,true) 

Ok, but that doesn’t fix the error from popping up, and I still had a question on how Vector3 Values work

You never mentioned any location for this to run from (server or client), or any rotation axis that you wanted to rotate you model over so I used some arbitrary values to show how you can work this.
If you would have said I want to rotate the model around the X,Y, or Z axis then I would have given you an example of this, I chose X (arbitrarily, because I had lack of information to do otherwise). Likewise, you didn’t say in the opening question I want to move my model up and down by 20 studs, so I chose and (here’s that word again) an arbitrary value of 100 in the Y direction.

You can lose the UpDownVector and just use the UdValue.Value in RenderStepped but I thought it would make it easier for you to understand. RenderStepped is required to run the animation over, it’s a continuous event that is fired every 4ms (approximately), without it we won’t be able to see the Tween motion (why? because the Tweens aren’t running on the model they are running on Values, variables, a line of text on a piece of paper, whatever you want to call them). How do we make these Values actually move the model? Well every RenderStepped (~4ms) we move the actual model to the value stored in these Values (the value written on that piece of paper). TweenInfo contains your info (I assumed because you were asking for two different movement styles you had some knowledge about how Tweening works).

TweenInfo defined on an indefinite rotation with Circular easing is defined like this (providing you want EasingDirection.In, but since you haven’t asked for either way, I arbitrarily chose In - maybe my bad!):

TweenInfo.new(5,Enum.EasingStyle.Circular,Enum.EasingDirection.In,-1,true);

Likewise. TweenInfo defined on an indefinite motion with Linear style is defined like this (again with arbitrary -i.e. my choice (arbitrary)- because you didn’t ask, I chose In). I didn’t know how long you wanted this animation to last so I chose 5 seconds because I had no choice, I had to choose something for the code to work.

TweenInfo.new(5,Enum.EasingStyle.Linear,Enum.EasingDirection.In,-1,true);

The Vector3 value is the position of the model (the position of the circular thing you described), the CFrame value is the rotation (of the circular thing you described). You need both if you want to both move the model and rotate it at the same time. I honestly suggest you should read some tutorials, follow some of the guides on the Education website, and it may help you from asking question until you have a good understanding of what a Vector3 is, what a CFrame is, what Local and server Scripts are, the different render mechanisms and stepping of frame rates. If you want this to run on the server then put this code in a Script and not a LocalScript (and change RenderStepped to Heartbeat - again this is fired approximately every 4ms, although at slightly different time to RenderStepped). I hope this helps. I’m always around if you need help with stuff…

here is the script with comments so it might help you understand whats going on

-- get the run service and save it into a variable
local runService = game:GetService("RunService")
-- get the model and save it into a variable
local model = workspace.Model
-- save a vector3 variable this will be where the model moves
local position = Vector3.new(0, 10, -20)
-- this is how high and low in studs we want the model to move from the position variable 
local moveAmount = 5
-- this is how fast we want the model to move up and down
local moveSpeed = 1
-- this is how fast we want to make the model rotate
local rotateSpeed = 1
-- we will use this cframe to rotate the model
local cFrame = CFrame.new()
-- we will use this counter to keep time
local counter = 0

-- every heartbeat call this function (this is called once per frame) it will also tell us the time between each frame so if the game is running at 60 frames per second deltatime will be 0.0166666666666667
runService.Heartbeat:Connect(function(deltaTime)
	-- increment the counter value by the moveSpeed multiplied by deltaTime so that would be 1 * 0.0166666666666667
	counter += moveSpeed * deltaTime
	-- use the sin wave to work out a offset vector3
	local offset = Vector3.new(0, math.sin(counter) * moveAmount, 0)
	-- rotate the cFrame varable we created at the top by rotateSpeed * deltaTime 1 * 0.0166666666666667
	cFrame *= CFrame.fromAxisAngle(Vector3.yAxis, rotateSpeed * deltaTime)
	-- update the models position using the cFrame + position + offset
	model:PivotTo(cFrame + position + offset)
end)

if your not to sure what math.sin is here is what it looks like on a graph

the sine wave goes up to 1 and down to -1 and repeats forever

here are some links that might help

https://developer.roblox.com/en-us/api-reference/event/RunService/Heartbeat

https://developer.roblox.com/en-us/api-reference/datatype/CFrame

https://developer.roblox.com/en-us/api-reference/datatype/Vector3

2 Likes

Nice answer, but he is requesting two different EasingStyles, Linear and Circular. That’s why I did the tweening of 2 variables so the OP could get the effect they wanted. Nice comments too.

but it is Linear and almost Circular like he asked for

but we could do something like this to get more circular waves but I wanted to keep it simple

Hats off, that’s a really nice solution. I recommend the OP choose that answer, I got locked in Tweens because if you ever wanted to change the style (Elastic, Bounce, etc…) it would be easy. If I could choose this as the solution, I would.

i chanched the solution and revamped it, mine does work but its stuttering, i changed it using sine and completely removed the tweening

Nice solution too, the only changes I would make are below.

Use PivotTo() instead so you don’t have to rely on the object being a model (works for parts) and having a PrimaryPart defined.

local PrimaryNormalCF = Model.PrimaryPart.CFrame;

Change to:

local PrimaryNormalCF = Model:GetPivot();

And since Get/SetPrimaryPartCFrame is deprecated

Model:PivotTo(PrimaryNormalCF + Vector3.new(0,math.sin(time())*YSpeed,0))
1 Like

I’m back, sorry It took me so long, I spent 2 hours drawing something and then forgot about this.

Well, although this is simpler, It does have less flexibility. For example, I could try to aim for a bounce EasingStyle, and while it may be replicable, It would be more a lot more complicated. I’ll try this out in case the other methods don’t work, but this is part of the reason why I prefer to use a solution involving EasingStyles.

The reason I didn’t elaborate much on the values was because they weren’t as important, I can tweak those values later.

I do have knowledge on how Tweening works, as I originally Tweened the model it, and the reason I started this post was because I couldn’t rotate while Tweening.

I still couldn’t get the error away, so I copied and pasted the code from the Script and put it on a LocalScript in the Workspace, along with putting a print(“Test”) to check if the code was running.
I still have the original script there in case something goes wrong, I just commented the code out so it doesn’t affect anything.
I ran it, and once again, nothing happened. I got rid of the error message, but I still can’t visibly see anything happen.

I have the code right here in case I did somthing wrong.

Code (No comments)
local Model = game.Workspace.Model;

print("test")

local udValue = Instance.new("Vector3Value");

udValue.Changed:Connect(function(Progress)

	udValue.Value = Progress;
end)


local RotateFrame = CFrame.new();

local rotateValue = Instance.new("CFrameValue");

rotateValue.Changed:Connect(function(Progress)
	RotateFrame = Progress; 
end)


spawn(function()
	
	local tweenUpDown = game.TweenService:Create(udValue,TweenInfo.new(5,Enum.EasingStyle.Circular,Enum.EasingDirection.In,-1,true),{Value=Model:GetPivot().Position+Vector3.new(0,100,0)});
	tweenUpDown:Play();
end)

spawn(function()
	local tweenRotate = game.TweenService:Create(rotateValue,TweenInfo.new(5,Enum.EasingStyle.Linear,Enum.EasingDirection.In,-1,true),{Value=Model:GetPivot()*CFrame.Angles(1,0,0)});
	tweenRotate:Play();
end)

game:GetService("RunService").RenderStepped:Connect(function()

	Model:PivotTo(CFrame.new(udValue.Value)*RotateFrame);

end)
1 Like

Okay, I have to say I am humbled and inspired by the wealth of intelligence of the people that populate these forums, there is knowledge here that is freely available to anyone with a mind that is inquisitive enough to listen and learn from. This is something I tried a while back and was trapped on a couple of things and without the combined inspiration of 5uphi and kalbags I would never have been able to solve this, so thank you, there is so much to learn here and it is a crime to not listen to anyone. We all have our weakness’ it takes real courage to accept them and learn from people that have more knowledge than you at certain things.

This is a solution that adds the ability to Tween the motions with Roblox’s in-built interpolation mechanisms to create a more customisable movement. Achieved by not Tweening the variables that the animations take place over but the timescale the animation is done over (I was close a month or so ago, but it took inspiration from others to realise where I was going wrong).

[Edit] There was a frame skip at the first index because the first value needs inserting into the time table because the steps only get added when nv changes so v1 was never inserted. I’ve updated the code but not the place.

--=================================================================================
local runService = game:GetService("RunService");	-- the function used to animate the part/model
local runFunction = runService.Heartbeat;	-- this is run on the server so we need Heartbeat over RenderStepped
--*** you must rename this to the part/model you want to movel!! ***
local object = workspace["YourModelOrPartName"];	-- this is the path-name of the part/model to tween
local objectOrigin = object:GetPivot().Position;	-- the origin position of the above part/model
local moveVector = Vector3.new(0,5,0);	-- the number of x,y,z studs to move the part/model (
local rotateAxis = Vector3.yAxis;	-- the rotation axis to spin the part/model around, thanks [5uphi]
local rotateSpeed = math.pi*4;	-- must be multiple of pi for complete rotations
local cFrame = CFrame.new();	-- an empty CFrame to apply the changes to

--=================================================================================
-- the range over which to tween the values (a sort of resolution in time steps)
local timeScale = 5;
-- time steps table iterator
local tableIndex = 1;
-- time steps table iterator direction (1= down, -1=up)
local tableDir = 1;
-- start value for time step interpolation
local timeMin = 0;
--end value for time step interpolation
local timeMax = 1;
-- this is our table of time steps going from timeMin->timeMax across timeScale seconds
local timeTable = {}; -- blank table to store our time steps

--=================================================================================
-- this function creates a time step table from v1-v2 using Roblox's in-built
-- interpolation functions defined in Enum.EasingStyle and Enum.EasingDirection
--=================================================================================
local function makeTimeTable(v1 : number,v2 : number,t : number,es : number,ed : number)

	-- this value is Tweened to create the time step values
	local nv = Instance.new("NumberValue");
	-- initialise the value from the supplied input or default to 0
	nv.Value = v1 or 0;

	-- initalise a local blank table to store the time steps, this is returned to our script
	-- because originally I wanted to do separate interpolation methods for rotation and movement
	-- i.e. Linear for movement and Circular for rotation (probably requires Modulating to achieve this)
	local TimeTable={};
	-- insert the first value (v1) into the table since Changed only adds a step when nv changes
	TimeTable[#TimeTable+1] = v1;
	-- make a connection to changes in the nv value (i.e. the time steps)
	nv.Changed:Connect(function(Progress)

		-- everytime the Tween changes the nv value it is sent here
		-- so we can store it in the time steps table
		TimeTable[#TimeTable+1] = Progress;

	end)

	-- define these if they weren't provided in the function inputs
	es = es or Enum.EasingStyle.Linear;
	-- "In" means interp in one direction and in the first half of the Tween
	ed = ed or Enum.EasingDirection.In;

	-- create the TweenInfo, and put a delay in the start because it
	-- doesn't initialise the first few values correctly otherwise (why this happens would be nice to know?)
	local info = TweenInfo.new(t or 5,es,ed,0,false,3);
	local tween = game.TweenService:Create(nv,info,{Value=v2 or 1});

	-- play the tween, wait for it to complete, and destroy it...
	tween:Play();
	tween.Completed:Wait();
	tween:Destroy();

	-- get rid of this locally allocated NumberValue (nv) instance
	-- (always good to do this, regardless of garbage collection methods)
	nv:Destroy();

	-- we can't destroy TweenInfo so set to nil i.e. deallocate
	-- (always good to do this, regardless of garbage collection methods)
	info = nil;

	-- we now have a time step table interpolated with Roblox's in-built methods
	-- infinitely re-usable every time a new method is added, return this to the caller
	return TimeTable;
end

-- Call the above function here so we get a one time initialisation of the time step table
timeTable = makeTimeTable(timeMin,timeMax,timeScale);

--=================================================================================
-- connect the script to a frame stepper (Heartbeat can run on the server, RenderStepped is run on the client)
--=================================================================================

runFunction:Connect(function(deltaTime)

	-- the moveOffset is the time step * our moveVector defined above
	local moveOffset = timeTable[tableIndex]*moveVector;
	-- accumulate the cframe changes in a blank cframe otherwise we may drift
	cFrame = CFrame.fromAxisAngle(rotateAxis,rotateSpeed*timeTable[tableIndex]*tableDir);
	-- pivot the part/model to place and apply the rotation in one go
	object:PivotTo(cFrame + objectOrigin + moveOffset);
	-- increase the time step table iterator index
	tableIndex += tableDir;
	-- check for wrap and change the direction of the time step iterator
	if tableIndex == #timeTable or tableIndex == 1 then
		tableDir *= -1;
	end

end)

--=================================================================================
-- EOF...
--=================================================================================

Here is an example place with all the tweens setup:

Timescale_tween.rbxl (42.5 KB)

And here is a video of them all running:
Thank you people, Roblox, and the Universe…

1 Like

The EasingStyles of the rotation and the movement can be adjusted separately, right?

Not yet, I need to turn this into a ModuleScript and then it will be possible and much easier to achieve, it is the next thing on my list. I did a quick and dirty test using the same method on two tables but the index counts were different, it worked for some combinations of EasingStyle but not all so I had to abandon it until tomorrow.

Ok, but if the EasingStyles can’t be changed seperatly, then the solution above could also be completed by having two different Tweens: One for up and one for down and then playing them on loop.

I’m not sure I understand you, the post above meaning my post? It could be solved with a bit of a hack to work as you want, but not consistently as it stands, and not without some knowledge of how to hack it.

I am currently improving it with the ability to apply Tweening motions to any axis and direction. With the ability to distinguish when the halfway point has been met so we can use a different tween on the upward motion and then a different one on the downward motion, and indeed on the rotation in the first half and the second half, I was only doing this because my original idea (when I tried this a month or so ago had the requirement to do this). Your original post asked for two Tweens being applied separately to rotation and movement, not along the direction of movement (up/down, etc.) or rotation (so this is a feature that is beyond the original scope of your question, although me being me it has to be added). I am making a ModuleScript that will allow any motion to be applied and changed to use a different Tween interpolation during the first half, and the second half, at any point in execution, i.e. on the fly. So we will be able to change it whenever we choose across any direction and across any axis. But it is a work in progress for now.

Well, the thing is, I’m trying to have different EasingStyles for the rotation and the movement. @5uphi had an example of the outcome that I was looking for, but I was looking for it to be done more with tweens.

What I’m saying is that with the example you showed me, the rotation and the movement had the same EasingStyle. However, because of that, I could also just create 2 Tweens. One UpTween, where I make the model rotate 180 degrees and move up, and then a DownTween, where it moves 180 degrees in the same direction and moves down.

The main thing I’m looking for is that the model has a Linear EasingStyle for the rotation and a Circular EasingStyle for the movement. That’s the problem I had from the beginning.

Once again, @5uphi did a good job with the outcome I was looking for, (MoveModel.rbxl (33.7 KB)) but the main problem I had with this was that It used math instead of Tweens. This would work, It just makes it harder to adjust it. I’m sure some other EasingStyles like Bounce or Elastic would be replicatable through this, I just don’t know how to make it work.