[SOLVED] Clamp Camera Y Rotation / Limit Camera Rotation / Make player unable to look behind themselves

This is what I’m trying to achieve:

As you can see, the camera is unable to rotate past a certain point; I’m having some troubles with this.

I was able to recreate, and get this to work, but only if the player isn’t looking toward the spot where it breaks (This is a video of it working)

At a certain point, the Y orientation of the camera (in degrees) flips to negative and starts descending:

This is a problem for me, because I’m subtracting and adding onto the current Y rotation to get the min and max for the clamp:

local clamped_Y = math.clamp(math.deg(y), math.deg(old_y) - 35, math.deg(old_y) + 35)

Imagine you are facing 155 degrees, add 35, that’s 190, which is PAST the point at 180 where it flips to -180 and it breaks.

Because the Max is not the “correct” number, and even if it was, the max would be less than min. (which is not good!!)

Hopefully I explained that competently.

Here’s the full code:

local _, old_y = cam_module.camera.CFrame:ToOrientation()

local function clamp_camera()
	local x, y, z = cam_module.camera.CFrame:ToOrientation()
	local clamped_Y = math.clamp(math.deg(y), math.deg(old_y) - 35, math.deg(old_y) + 35)
	cam_module.camera.CFrame = CFrame.new(cam_module.camera.CFrame.Position) * CFrame.fromOrientation(x, math.rad(clamped_Y), z)

And for anyone wondering, below that, I check if the player presses E, if so, I set the old Y again, then bind the “clamp_camera” function to RenderStepped.

I have tried using the code that a user suggested in this post; it did some weird stuff to say the least.

Anyway, is there any fix for this? I would love some guidance on this. Thanks for reading.

Try doing math.abs inf ront of the clamped_Y value because that makes it the value positive so

local clamped_Y = math.abs( math.clamp(math.deg(y), math.deg(old_y) - 35, math.deg(old_y) + 35) )

I’m getting some weird results with that

What does that mean? Is their like flips or does something else happen?

Sometimes it teleports to a seemingly random angle and locks in place, and other times it works. I don’t think both sides being positive will work.

I found this post How to clamp the player's camera rotation on one axis? maybe try tinker with that

If I changed the code that the answer gave on that post to be on the Y axis, the new problem would be that it’s not relative to the current angle of the camera, if I made it relative then I would unfortunately encounter the same issue that I have already

1 Like

I found a solution shortly after posting this, and I’m really happy with how it turned out, so I thought someone might appreciate me posting it.

I found a function in the “BaseCamera” script:
on line 777 that was seemingly exactly what I was looking for.

So I made two number values, and parented them to the “BaseCamera” script,
Then multiplied their values by “-constrainedRotateInput.X” and

Replace the full function on line 777 with this:

local CAMERA_SENS_X = script:WaitForChild("camera_sens_X")
local CAMERA_SENS_Y = script:WaitForChild("camera_sens_Y")

function BaseCamera:CalculateNewLookCFrameFromArg(suppliedLookVector: Vector3?, rotateInput: Vector2): CFrame
	local currLookVector: Vector3 = suppliedLookVector or self:GetCameraLookVector()
	local currPitchAngle = math.asin(currLookVector.Y)
	local yTheta = math.clamp(rotateInput.Y, -MAX_Y + currPitchAngle, -MIN_Y + currPitchAngle)
	local constrainedRotateInput = Vector2.new(rotateInput.X, yTheta)
	local startCFrame = CFrame.new(ZERO_VECTOR3, currLookVector)
	local newLookCFrame = CFrame.Angles(0, -constrainedRotateInput.X*CAMERA_SENS_X.Value, 0) * startCFrame * CFrame.Angles(-constrainedRotateInput.Y*CAMERA_SENS_Y.Value,0,0)
	return newLookCFrame

So now that we can change those values, and the camera sensitivity will change, we can start with the actual limiting of the camera rotation.

Set a variable to a copy of the camera’s CFrame
– EDIT –
I forgot to add, when doing that, remove any X axis rotation so it’s not pointed up or down at all.

local rot_X, rot_Y, rot_Z = camera.CFrame:ToOrientation()
local cframe = CFrame.new(camera.CFrame.Position) * CFrame.fromOrientation(0,rot_Y,rot_Z)
static_camera_CFrame = cframe

Then I binded a function:

RunService:BindToRenderStep("UpdateLoop", Enum.RenderPriority.Camera.Value + 1, function() limit_camera_sens() end)

In that function I compare the copy CFrame’s object space to the camera’s current LookVector, then I get the relative Y angle:

local projected_vector = static_camera_CFrame:VectorToObjectSpace(camera.CFrame.LookVector)
local relative_angle_Y = math.atan2(projected_vector.Z, projected_vector.X) + math.pi/2

Then send “relative_angle_Y” to this function to get a 0 to 1 value with the low number being where you want the camera sensitivity to start reducing, and high being where sensitivity is lowest.

function get_value(number, low, high): number
	local range = high - low
	return math.clamp(1 - (number - low) / range, 0, 1)

Then set your camera sensitivity X value you made earlier to what the “get_value” function returns.

Then you have to reset the camera sensitivity if the player is moving their camera back to the center. There are probably better ways of doing this, but for an example, I check if the “relative_angle_Y” is greater than 0 (if the camera is off to the right), and if the mouse is being moved to the left, I set the sensitivity back to normal.

Then for unbinding it:


And you can set the camera sensitivity values back to normal.

That’s pretty much it, hopefully this helped.

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