How to restrict the players camera so they cannot look all the way down

Hello people of devforum, I was wondering if there was a way to stop players from looking directly down (I have looked through devforum and most methods do not work in this situation).

To get an understanding of what I wish to accomplish, this is what happens when I aim all the way down (https://gyazo.com/1b3c690d93a91a10c490d535ed258000.mp4) and I would like to make it so the player cannot aim all the way down.

Sorry if this does not make sense,
I can explain in the comments if you do not understand

Thanks!

2 Likes

You could probably implement some math.clamp() function somewhere to prevent people from looking down, but it depends on how you wrote your camera script. Could you share your camera script?

I’m currently on my phone but my camera script really only consists of setting the camera offset to so it provides an over the shoulder look and also just setting the camera type to “lockcenter”.

I have tried to use math.clamp, but it only seems to work for x movements

Hmmmm…
Well, I guess I’d have to take a look at the script in order for me to provide a more specific solution. Do you think you could post the script later?

Sure, I can do that, thanks for your help so far

1 Like

The CameraOffset property of Humanoid probably isn’t the best way to tackle this problem because it is so limited in terms of what you can do with it and how you can modify it. A better solution would be to update the CFrame of the camera after every frame.

I actually had a similar problem a while back, when I was trying to create a 3rd person shooter game. When studying camera manipulation, I found that Roblox created their own compact (albeit basic) 3rd person over-the-shoulder camera script as a demonstration of camera manipulation.
Here is the code for it:

local Players = game:GetService("Players")
local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local camera = workspace.CurrentCamera
local cameraOffset = Vector3.new(2, 2, 8)
local player = Players.LocalPlayer

player.CharacterAdded:Connect(function(character)

	local humanoid = character:WaitForChild("Humanoid")
	local rootPart = character:WaitForChild("HumanoidRootPart")
	humanoid.AutoRotate = false

	local cameraAngleX = 0
	local cameraAngleY = 0

	local function playerInput(actionName, inputState, inputObject)
		-- Calculate camera/player rotation on input change
		if inputState == Enum.UserInputState.Change then
			cameraAngleX = cameraAngleX - inputObject.Delta.X
			-- Reduce vertical mouse/touch sensitivity and clamp vertical axis
			cameraAngleY = math.clamp(cameraAngleY-inputObject.Delta.Y*0.4, -75, 75)
			-- Rotate root part CFrame by X delta
			rootPart.CFrame = rootPart.CFrame * CFrame.Angles(0, math.rad(-inputObject.Delta.X), 0)
		end
	end
	ContextActionService:BindAction("PlayerInput", playerInput, false, Enum.UserInputType.MouseMovement, Enum.UserInputType.Touch)

	RunService.RenderStepped:Connect(function()
		if camera.CameraType ~= Enum.CameraType.Scriptable then
			camera.CameraType = Enum.CameraType.Scriptable
		end
		local startCFrame = CFrame.new((rootPart.CFrame.Position)) * CFrame.Angles(0, math.rad(cameraAngleX), 0) * CFrame.Angles(math.rad(cameraAngleY), 0, 0)
		local cameraCFrame = startCFrame:ToWorldSpace(CFrame.new(cameraOffset.X, cameraOffset.Y, cameraOffset.Z))
		local cameraFocus = startCFrame:ToWorldSpace(CFrame.new(cameraOffset.X, cameraOffset.Y, -10000))
		camera.CFrame = CFrame.new(cameraCFrame.Position, cameraFocus.Position)
	end)
end)

local function focusControl(actionName, inputState, inputObject)
	-- Lock and hide mouse icon on input began
	if inputState == Enum.UserInputState.Begin then
		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
		UserInputService.MouseIconEnabled = false
		ContextActionService:UnbindAction("FocusControl", focusControl, false, Enum.UserInputType.MouseButton1, Enum.UserInputType.Touch, Enum.UserInputType.Focus)
	end
end
ContextActionService:BindAction("FocusControl", focusControl, false, Enum.UserInputType.MouseButton1, Enum.UserInputType.Touch, Enum.UserInputType.Focus)

Here is the article from which I got this code. None of this was made by me.

You can look at the article for more information, but here are some key parts of it that are probably relevant to your issue.

  1. You’ll notice that the character turns based off of user input rather than on each frame. This system should be more efficient than having the HRP CFrame be updated for every frame. Though, this is a small change from your design, and I believe your implementation of this mechanic would work just fine.
  2. The camera’s CFrame property is set every frame. Hardcoding a camera position is more work, but allows for more flexibility and tinkering. In turn, this allows for you to use math.clamp() to constrain the camera in a reasonable Y-direction range as seen in the code. Essentially, there is a function that updates two cameraAngle variables on userInput (the playerInput function) and a RenderStepped function that just uses that information to constantly set the CFrame of the camera correctly. There is a lot of complex CFrame operations that are difficult to visualize in this code snippet, so if you need help understanding them, please do not hesitate to ask.
  3. The focusControl function is just there to initiate the third person camera. It shouldn’t be relevant to you at all since it seems like you already have a plan for this.

Hopefully, this answers your question. I know there’s a lot in this script I didn’t address, but much of what is done here should be pretty self explanatory. Just remember that the camera’s CFrame is essentially updated every frame. The article should provide some more insight if you’re still confused.

Let me know if you have any further questions.

6 Likes