How do I make 3 parts rotate around a center without changing their own orientation using TweenService?

Title.

This is basically what I’m looking for. 3 parts rotating 3 studs away from the center part. Their orientation shouldn’t change, only their position to rotate along.
image

All the other solutions I’ve found propose using BodyVelocities, using a PrimaryPart on the Model (which wouldn’t quite work since I’m not looking to change their orientation as well by using the PrimaryPart as a hinge), or use the game’s heartbeat.

I ideally need it to be a TweenService variable so I can easily play, stop, cancel it… etc.

Thank you very much!

3 Likes

Hi! I suppose you can group them as a model, then rotate the model if you want some sort of circular rotation. If you want to rotate each individual piece while rotating the entire, model, you can tag each part then rotate using Collection Service. I hope this helps!

2 Likes

This may be overcomplicating it, but the way I would do it would be to use runService and update their cframes every frame using a script like this:

local rS = game:GetService("RunService")
local CircleCenter = Vector3.new(-18, 0, 22)
local Radius = 3

local function rotate(dT)
	for _, part in game.Workspace.Folder:GetChildren() do
		part.Value.Value += dT * 60
		local x = CircleCenter.X + Radius * math.cos(math.rad(part.Value.Value))
		local z = CircleCenter.Z + Radius * math.sin(math.rad(part.Value.Value))
		part.Position = Vector3.new(x, part.Position.Y, z)
	end
end

rS.Heartbeat:Connect(function(dt) rotate(dt) end)

All i’ve done here is make a folder that has all the parts in it and a intvalue with their starting rotation on the edge of a circle.
image
the example image shows what the folder would look like.

1 Like

Isn’t there a way to transplant that to a Tween? I really don’t want to be overcomplicating the script even more by making it handle when I want it to stop or change.

1 Like

You could, but it would be hard to get the orientations to stay the same while tweening. If it was all in a model you could weld all the parts to a primary one and rotate that, but that would also change their orientations. I am not aware of a weld like feature that doesn’t affect orientation

1 Like

You can’t. The only way that would be possible is if tweens could be controlled by a curve

1 Like

Actually, I think you can do this with beziercurves, but I’m not exactly sure how

Yeah basically, but then I wouldn’t be a tween object

Made you a script that will allow you to orbit parts around a center point, while also keeping them equidistant from one another.

local part1 = script.Parent:WaitForChild("Part1")
local part2 = script.Parent:WaitForChild("Part2")
local part3 = script.Parent:WaitForChild("Part3")
local center = script.Parent:WaitForChild("Center")

local radius = 6 -- Radius of the orbit
local numParts = 3 -- Number of parts to orbit

local angleOffset = math.pi * 2 / numParts -- Angle offset for each part
local rotationSpeed = 2 -- Increase this value to make the rotation faster

local function updateOrbit()
	local time = tick() * rotationSpeed -- Multiply time by rotationSpeed to make it rotate faster
	local angle = time % (math.pi * 2) -- Ensures the angle loops

	local pos1 = center.Position + Vector3.new(math.cos(angle), 0, math.sin(angle)) * radius
	local pos2 = center.Position + Vector3.new(math.cos(angle + angleOffset), 0, math.sin(angle + angleOffset)) * radius
	local pos3 = center.Position + Vector3.new(math.cos(angle + angleOffset * 2), 0, math.sin(angle + angleOffset * 2)) * radius

	part1.Position = pos1
	part2.Position = pos2
	part3.Position = pos3
end

game:GetService("RunService").Heartbeat:Connect(updateOrbit)


Note: In this example I am using a script with RunContext set to client. Depending on your needs this exact set up may work for you.

You can move it around & orbiting parts follow while ignoring the rotation of the center part

4 Likes

Also if you would like for the parts to “face” the center point you can do this:

local part1 = script.Parent:WaitForChild("Part1")
local part2 = script.Parent:WaitForChild("Part2")
local part3 = script.Parent:WaitForChild("Part3")
local center = script.Parent:WaitForChild("Center")

local radius = 6 -- Radius of the orbit
local numParts = 3 -- Number of parts to orbit

local angleOffset = math.pi * 2 / numParts -- Angle offset for each part
local rotationSpeed = 2 -- Increase this value to make the rotation faster

local function updateOrbit()
	local time = tick() * rotationSpeed -- Multiply time by rotationSpeed to make it rotate faster
	local angle = time % (math.pi * 2) -- Ensures the angle loops

	local pos1 = center.Position + Vector3.new(math.cos(angle), 0, math.sin(angle)) * radius
	local pos2 = center.Position + Vector3.new(math.cos(angle + angleOffset), 0, math.sin(angle + angleOffset)) * radius
	local pos3 = center.Position + Vector3.new(math.cos(angle + angleOffset * 2), 0, math.sin(angle + angleOffset * 2)) * radius

	part1.Position = pos1
	part2.Position = pos2
	part3.Position = pos3

	-- Calculate rotation for each part
	local rotation1 = CFrame.new(pos1, center.Position)
	local rotation2 = CFrame.new(pos2, center.Position)
	local rotation3 = CFrame.new(pos3, center.Position)

	-- Apply rotation to each part
	part1.CFrame = rotation1 * CFrame.Angles(0, math.pi / 2, 0) -- Adjust the rotation angle as needed
	part2.CFrame = rotation2 * CFrame.Angles(0, math.pi / 2, 0)
	part3.CFrame = rotation3 * CFrame.Angles(0, math.pi / 2, 0)
end

updateOrbit() -- Run once to set initial positions and rotations

game:GetService("RunService").Heartbeat:Connect(updateOrbit) -- Use Heartbeat instead of Stepped for smoother animation

Model: https://create.roblox.com/store/asset/16772403771/Planetary-Orbit

3 Likes

Furthermore to start/stop you could assign “game:GetService(“RunService”).Heartbeat:Connect(updateOrbit)” to a variable which you connect/disconnect at will.

Also here’s an example that uses a hinge, and requires no code
*I did use code to place the parts around the center equidistant from one-another, but could be done by hand
*You could also delete the secondary cylinder (the one that parts are not welded to), then apply a rotation tween to the model with the cylinder as the primary part.

2 Likes

what about 6 parts? how would i do that since im doing a similar thing.
since i notice you did

	local pos1 = center.Position + Vector3.new(math.cos(angle), 0, math.sin(angle)) * radius
	local pos2 = center.Position + Vector3.new(math.cos(angle + angleOffset), 0, math.sin(angle + angleOffset)) * radius
	local pos3 = center.Position + Vector3.new(math.cos(angle + angleOffset * 2), 0, math.sin(angle + angleOffset * 2)) * radius

how would you add more positions

Made this model that will work for any number of parts. Enjoy :slight_smile:

And, just for fun I also made this one:

5 Likes

Ive ended up just welding parts to the center part then using sleitnicks tween module to rotate it 1440 degrees, appreciate the effort tho man

1 Like

Thank you so much for going so in-depth and making different models for different use cases. I appreciate you a lot!

Furthermore to start/stop you could assign “game:GetService(“RunService”).Heartbeat:Connect(updateOrbit)” to a variable which you connect/disconnect at will.

Also THIS. I didn’t think you could do that with RunService. Again, thank you!

1 Like

Happy to help!
Found it fun to make so kept adding on :smile:

Message me if you need any clarification on anything

Hey, sorry for necroposting. How would you make this work for models?

Since I assume it’s using CFrames, it can be changed to PivotTo() instead of setting the CFrames. Then it will work for models and parts

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.