How to loop camera movement

so, i want to make a looping camera movement, how do i make it loops ?, i try to script when the tween finished then it will back to the first cam and tween again from the start but it stops at the end

local function x()
		local y = false
		cam.CFrame = workspace.MainMenuCam.Cam1.CFrame
		local goal = {
			CFrame = workspace.MainMenuCam.Cam2.CFrame
		}
		local pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
		pley:Play()
		pley.Completed:Connect(function()
			cam.CFrame = workspace.MainMenuCam.Cam3.CFrame
			goal = {
				CFrame = workspace.MainMenuCam.Cam4.CFrame
			}
			pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
			pley:Play()
			pley.Completed:Connect(function()
				cam.CFrame = workspace.MainMenuCam.Cam5.CFrame
				goal = {
					CFrame = workspace.MainMenuCam.Cam6.CFrame
				}
				pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
				pley:Play()
				pley.Completed:Connect(function()
					cam.CFrame = workspace.MainMenuCam.Cam7.CFrame
					goal = {
						CFrame = workspace.MainMenuCam.Cam8.CFrame
					}
					pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
					pley:Play()
					pley.Completed:Connect(function()
						cam.CFrame = workspace.MainMenuCam.Cam1.CFrame
						goal = {
							CFrame = workspace.MainMenuCam.Cam2.CFrame
						}
						pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
						pley:Play()
					end)
				end)
			end)
		end)
	end
	x()

It’s only playing once because your only calling your function once. Put the part where you call your function, x(), through a loop.

well in the function you could put a for loop like

        for i=1,10 do
   	local y = false
   	cam.CFrame = workspace.MainMenuCam.Cam1.CFrame
   	local goal = {
   		CFrame = workspace.MainMenuCam.Cam2.CFrame
   	}
   	local pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
   	pley:Play()
   	pley.Completed:Connect(function()
   		cam.CFrame = workspace.MainMenuCam.Cam3.CFrame
   		goal = {
   			CFrame = workspace.MainMenuCam.Cam4.CFrame
   		}
   		pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
   		pley:Play()
   		pley.Completed:Connect(function()
   			cam.CFrame = workspace.MainMenuCam.Cam5.CFrame
   			goal = {
   				CFrame = workspace.MainMenuCam.Cam6.CFrame
   			}
   			pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
   			pley:Play()
   			pley.Completed:Connect(function()
   				cam.CFrame = workspace.MainMenuCam.Cam7.CFrame
   				goal = {
   					CFrame = workspace.MainMenuCam.Cam8.CFrame
   				}
   				pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
   				pley:Play()
   				pley.Completed:Connect(function()
   					cam.CFrame = workspace.MainMenuCam.Cam1.CFrame
   					goal = {
   						CFrame = workspace.MainMenuCam.Cam2.CFrame
   					}
   					pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
   					pley:Play()
   				end)
   			end)
   		end)
   	end)
   end
end
end
x()

which would loop through ten times

but i need to loop it every times the tween reached cam8, how to do it
because i already have script to make a tween loops without using any kind of loop, it looks like this

pley:Play()
pley:Completed():Connect(function()
pley:Play()
end)

is there any way to loop without a kind of loop

Whoa whoa whoa, that’s some really ugly code, why all these nested Connects? You can just :Wait() for them.

Like this
local function x()
	local y = false
	cam.CFrame = workspace.MainMenuCam.Cam1.CFrame
	local goal = {
		CFrame = workspace.MainMenuCam.Cam2.CFrame
	}
	local pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
	pley:Play()
	pley.Completed:Wait() -- wait until pley.Completed is fired
	cam.CFrame = workspace.MainMenuCam.Cam3.CFrame
	goal = {
		CFrame = workspace.MainMenuCam.Cam4.CFrame
	}
	pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
	pley:Play()
	pley.Completed:Wait()
	cam.CFrame = workspace.MainMenuCam.Cam5.CFrame
	goal = {
		CFrame = workspace.MainMenuCam.Cam6.CFrame
	}
	pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
	pley:Play()
	pley.Completed:Wait()
	cam.CFrame = workspace.MainMenuCam.Cam7.CFrame
	goal = {
		CFrame = workspace.MainMenuCam.Cam8.CFrame
	}
	pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
	pley:Play()
	pley.Completed:Wait()
	cam.CFrame = workspace.MainMenuCam.Cam1.CFrame
	goal = {
		CFrame = workspace.MainMenuCam.Cam2.CFrame
	}
	pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), goal)
	pley:Play()
end
x()

Then you can reduce all that repeated code into one loop to go through all the camera points:

Made it a LOT shorter
local cams = workspace.MainMenuCam
local cframesA = {cams.Cam1.CFrame, cams.Cam3.CFrame, cams.Cam5.CFrame, cams.Cam7.CFrame)
local cframesB = {cams.Cam2.CFrame, cams.Cam4.CFrame, cams.Cam6.CFrame, cams.Cam8.CFrame)

local function x()
	for i = 1, #cframesA do
		local cframeA = cframesA[i]
		local cframeB = cframesB[i]
		cam.CFrame = cframeA -- can this line be removed? not sure
		local pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), {CFrame = cframeB}) -- goal was put here because it's short now
		pley:Play()
		pley.Completed:Wait() -- wait until pley.Completed is fired
	end
end
x()

This will still “work only once”, so it goes into a loop:

while true do
	x()
end

The next thing you should do is make it able to be canceled so it doesn’t move your camera. I won’t help with that until you ask for it

thanks for helping, my code is messed up because i keep imagine how the camera should tween, your script is working well. Also i cant figure by my self how to stop the loop when a specified button was pressed

Yeah, for that you will need to break the while true do loop, the for i = … loop, and stop the tween.

You will need to cancel the tween somehow:

The easiest way to do this is to have an “is this cancelled?” upvalue that you can set to true to make the loops stop itself.
And you have to Cancel the current in-progress tween.
It’s very easy to add this, so I’ll do it for you and show exactly what and why I added:

local cams = workspace.MainMenuCam
local cframesA = {cams.Cam1.CFrame, cams.Cam3.CFrame, cams.Cam5.CFrame, cams.Cam7.CFrame)
local cframesB = {cams.Cam2.CFrame, cams.Cam4.CFrame, cams.Cam6.CFrame, cams.Cam8.CFrame)

---- whether the tween is still running. if this is set to false,
---- eventually the loops will notice and stop
local running = false

---- tween variable moved here so that it can be addressed elsewhere in the code, and stopped
local pley

---- Connect to the button that makes it stop running
---- Be sure to make the button variable your button
button.Activated:Connect(function()
	running = false ---- stop the loops
	if pley ~= nil then ---- don't error if tween hasn't started before the button is pressed
		pley:Cancel()
	end
end)

local function x()
	---- the while loop was moved into here
	running = true ---- make the loop not break itself immediately
	while running do ---- as long as running == true, keep repeating
		for i = 1, #cframesA do
			if not running then break end ---- if something set running to false, then stop now
			
			local cframeA = cframesA[i]
			local cframeB = cframesB[i]
			cam.CFrame = cframeA -- can this line be removed? not sure
			
			---- removed the "local" from below so that it sets the local at the top of the script
			pley = ts:Create(workspace.CurrentCamera, TweenInfo.new(8, Enum.EasingStyle.Linear), {CFrame = cframeB}) -- goal was put here because it's short now
			pley:Play()
			pley.Completed:Wait() -- wait until pley.Completed is fired
			---- pley:Completed will also fire as soon as the tween is cancelled
		end
	end
end

x() ---- might be wise to rename the function to startMenuTween() or something

print([[This print will run only after you break the loop.
If you put the connection (from above) below the x(), then the loop will never break,
because the connection to the button to break the loop
will never be made, because it never gets past the infinite loop
To fix it, learn about putting loops in spawn() or a coroutine
so that other code will run while the loop is waiting for something]])