[SOLVED] Limiting a player's camera rotation

  1. What do you want to achieve? Keep it simple and clear!
    I want to limit a players camera while sitting so they cannot rotate their heads in an unnatural way (looking backwards, looking straight up/down, etc.)

  2. What is the issue? Include screenshots / videos if possible!
    There is no simple way to do this. (either that or I’m just too stupid)

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve looked at just about every DevForum post remotely related to my issue. Each one either didn’t work or wasn’t relevant.

First, I tried using the BaseCamera script to limit the rotation. This worked perfectly for the vertical axis (because up is always up regardless of what direction you’re facing), but when adding a limit for the horizontal axis, the camera would act undesirably; when the camera rotation reached the limit, instead of simply being stopped from moving further, the camera violently jerked back within the accepted range.

In hindsight, this wouldn’t work anyway, since the X rotation limit wouldn’t be relative to the player’s orientation (if the player were to look in the opposite direction, their camera would be locked behind them.)

Then, I found this DevForum post that mentioned calculating the angle between the camera and the player’s HumanoidRootPart, and setting a limit from there. This is the closest thing on this forum related to me issue (that I know of.)

Camera Rotation Limit [SOLVED] - Help and Feedback / Scripting Support - Developer Forum | Roblox

The only issue is the solution didn’t go into detail about anything they suggested, which left me and others confused about what to actually do.

This is what I’ve done so far:

local cameraLimit = RS.RenderStepped:Connect(function()
	local radians = math.acos(math.clamp(camera.CFrame.LookVector.Unit:Dot(HRP.CFrame.LookVector.Unit), -1, 1))
	local degrees = math.deg(radians)
	print(degrees)
end)

This returns the angle difference between the CurrentCamera’s LookVector and my HumanoidRootPart’s LookVector. I’ve determined that I never want this angle to exceed 60 degrees in any direction. The only issue is that I have absolutely no clue how to enforce this limit.

I’ll update if I find a solution, otherwise I’ll just bump this until someone else has any ideas.

3 Likes

I don’t think you even need to get the angle between the look vectors. Imo, you could get the angles needed to get the current camera rotation by doing cam.CFrame:ToEulerAnglesXYZ and clamping the Y angle between 60 and -60, after which you would apply the angles back to the camera cframe with only position.

1 Like

Are you referring to something like this?

local camLimit = RS.RenderStepped:Connect(function()
	local x, y, z = camera.CFrame:ToOrientation()
	local a = camera.CFrame.Position.X --I'm sure this isn't the best way to do this, I just made this quickly
	local b = camera.CFrame.Position.Y
	local c = camera.CFrame.Position.Z
	local xlimit = math.clamp(math.deg(x),-60,60)
	local ylimit = math.clamp(math.deg(y),-60,60)
	local zlimit = math.clamp(math.deg(z),-60,60)
	xlimit = math.rad(xlimit)
	ylimit = math.rad(ylimit)
	zlimit = math.rad(zlimit) --probably isn't necessary
	camera.CFrame = CFrame.new(a,b,c) * CFrame.fromOrientation(xlimit,ylimit,zlimit) 
end)

Something like this would work on a stationary object, but I’m trying to change the players camera. If this is applied to a player’s camera, they would only be able to look in a single direction. I need this limit to stay relative to the player’s orientation.

1 Like

I mean, just set it relative to the character then?

local camera = workspace.CurrentCamera
local HRP = script.Parent:WaitForChild("HumanoidRootPart")

local camLimit = game:GetService("RunService").RenderStepped:Connect(function()
	local CameraCFrame = HRP.CFrame:ToObjectSpace(camera.CFrame)
	local x, y, z = CameraCFrame:ToOrientation()
	local a = CameraCFrame.Position.X --I'm sure this isn't the best way to do this, I just made this quickly
	local b = CameraCFrame.Position.Y
	local c = CameraCFrame.Position.Z
	local xlimit = math.clamp(math.deg(x),-60,60)
	local ylimit = math.clamp(math.deg(y),-60,60)
	local zlimit = math.clamp(math.deg(z),-60,60)
	xlimit = math.rad(xlimit)
	ylimit = math.rad(ylimit)
	zlimit = math.rad(zlimit)
	camera.CFrame = HRP.CFrame:ToWorldSpace(CFrame.new(a,b,c) * CFrame.fromOrientation(xlimit,ylimit,zlimit)) 
end)
1 Like
local camLimit = RS.RenderStepped:Connect(function()
	local x, y, z = camera.CFrame:ToEulerAnglesXYZ()

	local ylimit = math.rad(math.clamp(math.deg(y), -60, 60))

	camera.CFrame = CFrame.new(camera.CFrame.Position) * CFrame.fromEulerAnglesXYZ(xlimit, ylimit,zlimit) 
end)
1 Like

Works at first, but completely freaks out when the player rotates:
robloxapp-20230803-1212063.wmv (2.7 MB)

This looks promising though. Will look further into this!

1 Like

The Y limit isn’t the issue. In my original post I mentioned that I was able to adjust the Y limit smoothly with the BaseCamera script (because up is always up, no matter your orientation). The issue is making the X limit relative to the player

Flip the axis then:

local camLimit = RS.RenderStepped:Connect(function()
	local x, y, z = camera.CFrame:ToOrientation()

	x = math.rad(math.clamp(math.deg(x), -60, 60))

	camera.CFrame = CFrame.new(camera.CFrame.Position) * CFrame.fromOrientation(x, y, z) 
end)

robloxapp-20230803-1219273.wmv (1.1 MB)

RS:BindToRenderStep("CustomCamera", Enum.RenderPriority.Camera.Value + 1, function()
	local x, y, z = camera.CFrame:ToOrientation()

	x = math.rad(math.clamp(math.deg(x), -60, 60))

	camera.CFrame = CFrame.new(camera.CFrame.Position) * CFrame.fromOrientation(x, y, z) 
end)

Same result as previous.

I switched the x back to y (got mixed up earlier, sorry) but the result is still what I explained before. The limit isn’t relative to the player, so it just limits the camera to looking in a single direction.

1 Like

Huh? Wdym by this?

The script you provided limits the camera’s horizontal movement, but only in a single direction. Therefore, if the player were to turn around and face the opposite direction, they wouldn’t be able to see in front of them. An example is linked below
robloxapp-20230803-1309090.wmv (2.0 MB)

I need the camera’s horizontal limit to change depending on the player’s rotation.

1 Like

Update: I’ve gotten this code to semi-work. Thanks to @XSiggeManx for introducing me to ToObectSpace.

local camLimit = RS.RenderStepped:Connect(function()
	local CameraCFrame = HRP.CFrame:ToObjectSpace(camera.CFrame)
	local x, y, z = CameraCFrame:ToOrientation()
	local a = camera.CFrame.Position.X
	local b = camera.CFrame.Position.Y
	local c = camera.CFrame.Position.Z

	local xlimit = math.rad(math.clamp(math.deg(x),-60,60))
	local ylimit = math.rad(math.clamp(math.deg(y),-60,60))
	local zlimit = math.rad(math.clamp(math.deg(z),-60,60))
	camera.CFrame = HRP.CFrame:ToWorldSpace(CFrame.new(a,b,c) * CFrame.fromOrientation(xlimit,ylimit,zlimit))
end)

This will restrict it depending on the player’s rotation, however the camera is stuck at a weird offset from the player very far away. Restricting CameraMaxZoomDistance doesn’t affect this.

robloxapp-20230804-2315204.wmv (2.9 MB)

Just throwing this out there to see if anyone has any ideas while I look into it myself.

Found out the problem. Changing RenderStepped to Stepped or Heartbeat fixes the issue. Unfortunately, this also makes the rotation limit less stable; since the camera is being updated slightly later now, trying to rotate past the limit creates a slight shaking effect.

I think the reason this script didn’t work was because RenderStepped occurs before anything is rendered, including the player model (i.e. the HumanoidRootPart). Therefore, trying to set the camera relative to something that doesn’t exist yet understandably led to strange behavior.

Anyway, here’s the working script:

local camLimit = RS.Stepped:Connect(function()
	local CameraCFrame = HRP.CFrame:ToObjectSpace(camera.CFrame)
	local x, y, z = CameraCFrame:ToOrientation()
	local a = camera.CFrame.Position.X
	local b = camera.CFrame.Position.Y
	local c = camera.CFrame.Position.Z

	local xlimit = math.rad(math.clamp(math.deg(x),-60,60))
	local ylimit = math.rad(math.clamp(math.deg(y),-60,60))
	local zlimit = math.rad(math.clamp(math.deg(z),-60,60))
	camera.CFrame = HRP.CFrame:ToWorldSpace(CFrame.new(a,b,c) * CFrame.fromOrientation(xlimit,ylimit,zlimit))
end)
4 Likes

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