Camera in viewportFrame sometimes moves to the opposites orientation

You can write your topic however you want, but you need to answer these questions

  1. What do you want to achieve? I want a dummy in a viewpointFrame to rotate according to the x and y position of the mouse. Although that’s working, the dummy sometimes moves 180 degrees. This only happens when the MouseButton1Down event is fired.

  2. What is the issue? Include screenshots / videos if possible!
    Here is a video of the bug.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

This is the script.

local players = game:GetService("Players")
local player = players.LocalPlayer

local viewportFrame = script.Parent
local drag = viewportFrame.Parent.drag
local object = viewportFrame.Dummy

local cameraDistance = 10
local cameraFieldOfView = 50

local rotateConnection = nil

local latestX, latestY, latestZ = nil, nil, nil


local viewportCamera = Instance.new("Camera")
viewportCamera.FieldOfView = cameraFieldOfView
viewportCamera.Parent = viewportFrame
viewportFrame.CurrentCamera = viewportCamera



drag.MouseButton1Down:Connect(function()
	local startX, startY = game.UserInputService:GetMouseLocation().X, game.UserInputService:GetMouseLocation().Y
	
	rotateConnection = game:GetService("RunService").Heartbeat:Connect(function()
		local x, y = game.UserInputService:GetMouseLocation().X, game.UserInputService:GetMouseLocation().Y
		if latestX == nil or latestY == nil then
			viewportCamera.CFrame = CFrame.fromEulerAnglesXYZ(math.rad(y - startY), math.rad(x - startX),  0) * CFrame.new(0, 0, cameraDistance)
		else
			viewportCamera.CFrame = CFrame.fromEulerAnglesXYZ(math.rad(y - startY) + latestX, math.rad(x - startX) + latestY,  0) * CFrame.new(0, 0, cameraDistance)
			print(math.deg(latestX), math.deg(latestY))
		end
	end)
end)



local function disconnectRotation()
	latestX, latestY = Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).X, Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).Y
	print(math.deg(latestX), math.deg(latestY))
	
	if rotateConnection then
		rotateConnection:Disconnect()
	end
end

drag.MouseButton1Up:Connect(disconnectRotation)
drag.MouseLeave:Connect(disconnectRotation)

I think the issue seems to be with the way the rotation is being applied based on the mouse movement.

You could try modifying the calculation of the viewportCamera.CFrame to account for the issue. A possible solution could be to use the math.clamp function to limit the maximum rotation angle to a certain value.

Here’s an updated version of the code:

local players = game:GetService("Players")
local player = players.LocalPlayer

local viewportFrame = script.Parent
local drag = viewportFrame.Parent.drag
local object = viewportFrame.Dummy

local cameraDistance = 10
local cameraFieldOfView = 50

local rotateConnection = nil

local latestX, latestY, latestZ = nil, nil, nil

local maxRotation = math.pi/2

local viewportCamera = Instance.new("Camera")
viewportCamera.FieldOfView = cameraFieldOfView
viewportCamera.Parent = viewportFrame
viewportFrame.CurrentCamera = viewportCamera


drag.MouseButton1Down:Connect(function()
	local startX, startY = game.UserInputService:GetMouseLocation().X, game.UserInputService:GetMouseLocation().Y
	
	rotateConnection = game:GetService("RunService").Heartbeat:Connect(function()
		local x, y = game.UserInputService:GetMouseLocation().X, game.UserInputService:GetMouseLocation().Y
		if latestX == nil or latestY == nil then
			viewportCamera.CFrame = CFrame.fromEulerAnglesXYZ(math.clamp(math.rad(y - startY), -maxRotation, maxRotation), math.clamp(math.rad(x - startX), -maxRotation, maxRotation),  0) * CFrame.new(0, 0, cameraDistance)
		else
			viewportCamera.CFrame = CFrame.fromEulerAnglesXYZ(math.clamp(math.rad(y - startY) + latestX, -maxRotation, maxRotation), math.clamp(math.rad(x - startX) + latestY, -maxRotation, maxRotation),  0) * CFrame.new(0, 0, cameraDistance)
			print(math.deg(latestX), math.deg(latestY))
		end
	end)
end)


local function disconnectRotation()
	latestX, latestY = Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).X, Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).Y
	print(math.deg(latestX), math.deg(latestY))
	
	if rotateConnection then
		rotateConnection:Disconnect()
	end
end

drag.MouseButton1Up:Connect(disconnectRotation)
drag.MouseLeave:Connect(disconnectRotation)

This code uses math.clamp to limit the rotation angle to maxRotation , which is set to math.pi/2 (90 degrees). This should prevent it from happening. Lmk if it works.

1 Like

the script worked with the 90 degree angle, but thats not exactly what i want, because i want to be able to rotate the camera in all angles (like you can see in the video). although sometimes when i let go of mousebutton1 and fire the mouseButton1Down function again. then the camera rotates to the opposite side. I dont know if this makes it clear or not. And thanks for the reply

it turns out that the camera turned on the Z-axis so i set the Z to latestZ instead of 0. which completely fixed the issue.

final code

local players = game:GetService("Players")
local player = players.LocalPlayer

local viewportFrame = script.Parent
local drag = viewportFrame.Parent.drag
local object = viewportFrame.Dummy

local cameraDistance = 10
local cameraFieldOfView = 50

local rotateConnection = nil

local latestX, latestY, latestZ = nil, nil, nil


local viewportCamera = Instance.new("Camera")
viewportCamera.FieldOfView = cameraFieldOfView
viewportCamera.Parent = viewportFrame
viewportFrame.CurrentCamera = viewportCamera


drag.MouseButton1Down:Connect(function()
	local startX, startY = game.UserInputService:GetMouseLocation().X, game.UserInputService:GetMouseLocation().Y

	rotateConnection = game:GetService("RunService").Heartbeat:Connect(function()
		local x, y = game.UserInputService:GetMouseLocation().X, game.UserInputService:GetMouseLocation().Y
		if latestX == nil or latestY == nil then
			viewportCamera.CFrame = CFrame.fromEulerAnglesXYZ(math.rad(y - startY), math.rad(x - startX), 0) * CFrame.new(0, 0, cameraDistance)
		else
			viewportCamera.CFrame = CFrame.fromEulerAnglesXYZ(math.rad(y - startY) + latestX, math.rad(x - startX) + latestY,  latestZ) * CFrame.new(0, 0, cameraDistance)
			print(math.deg(Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).X), math.deg(Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).Y), math.deg(Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).Z))
		end
	end)
end)


local function disconnectRotation()
	latestX, latestY, latestZ = Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).X, Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).Y, Vector3.new(viewportCamera.CFrame:ToEulerAnglesXYZ()).Z
	print(math.deg(latestX), math.deg(latestY))

	if rotateConnection then
		rotateConnection:Disconnect()
	end
end

drag.MouseButton1Up:Connect(disconnectRotation)
drag.MouseLeave:Connect(disconnectRotation)

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