How to change camera's CFrame while being affected by CFrame.Angles?

I am attempting to create a menu system that, while in the shop section of the menu, the camera will follow the cursor slightly, and then pressing the X button will return it back to the main menu without the camera following the cursor.

However, when I attempt to press the X button to leave, the camera’s CFrame does not change, and no errors appear.
Please keep note that the shop UI system is based on surface GUIs however I am sure that has nothing to do with it

ShopButton.MouseButton1Click:Connect(function() --SHOP

	PlayButton.Visible = false
	ShopButton.Visible = false
	AchievementsButton.Visible = false
	logo.Visible = false
	--// Variables
	
	local camPart = workspace:WaitForChild("Shop"):WaitForChild("ShopCameraPart")
	local mouse = game:GetService("Players").LocalPlayer:GetMouse()
	cam.CFrame = camPart.CFrame
	--// Move cam
	local maxTilt = 15
	game:GetService("RunService").RenderStepped:Connect(function()
		cam.CFrame = camPart.CFrame * CFrame.Angles(
			math.rad((((mouse.Y - mouse.ViewSizeY / 2) / mouse.ViewSizeY)) * -maxTilt),
			math.rad((((mouse.X - mouse.ViewSizeX / 2) / mouse.ViewSizeX)) * -maxTilt),
			0
		)
	end)
	workspace.Shop:WaitForChild("LeaveButton").SurfaceGui.ImageButton.MouseButton1Click:Connect(function()
		cam.CFrame = Maincamerapart.CFrame 
		PlayButton.Visible = true
		ShopButton.Visible = true
		AchievementsButton.Visible = true
		logo.Visible = true
	end)
1 Like

The issue happening here is that this RenderStepped connection still persists even after pressing “x”, meaning that the camera will still go to camPart and rotate according to the mouse. To fix this, you need to disconnect the RenderStepped connection after the player presses “x”. Here is what it would look like:

local connection = game:GetService("RunService").RenderStepped:Connect(function()
	cam.CFrame = camPart.CFrame * CFrame.Angles(
		math.rad((((mouse.Y - mouse.ViewSizeY / 2) / mouse.ViewSizeY)) * -maxTilt),
		math.rad((((mouse.X - mouse.ViewSizeX / 2) / mouse.ViewSizeX)) * -maxTilt),
		0
	)
end)

workspace.Shop:WaitForChild("LeaveButton").SurfaceGui.ImageButton.MouseButton1Click:Connect(function()
	cam.CFrame = Maincamerapart.CFrame 
	PlayButton.Visible = true
	ShopButton.Visible = true
	AchievementsButton.Visible = true
	logo.Visible = true
	connection:Disconnect() -- disconnects RenderStepped, no longer receives signals
end)

Basically, when you use Instance.Event:Connect(), you are creating a “connection” which calls the function inside when “Event” happens. You can store this connection to a variable as shown above. Connections can then be disconnected if no longer used using connection:Disconnect(), which will make the inside functions no longer be called on the “Event”.

Let me know if you have any questions!

1 Like