How would I create a custom but user sensitive custom first person camera?

  1. What do you want to achieve? Keep it simple and clear!

I want to achieve the default first person camera-- except it runs from a single script and is sensitive to the user’s settings (Screen size, mouse sensitivity). This is so I can completely customize the camera in a game I’m creating. That would mean locking the mouse in the center with UserInputService and setting the CameraType to Scriptable.

  1. What is the issue? Include screenshots / videos if possible!

I don’t know where to start. I know I can use viewport size, UserInputService.MouseDeltaSensitivity, UserInputService:GetMouseDelta(), and Delta-Time for all of this (I think), except I don’t know how to use them

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

All I’ve done so far is a simple script to test UserInputService:GetMouseDelta(), but that’s where I got stuck.

--Please don't correct this, this was for testing ONLY.
local uis = game:GetService("UserInputService")
game:GetService("RunService").RenderStepped:Connect(function(dt)
	workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable
	uis.MouseBehavior = Enum.MouseBehavior.LockCenter
	local ms1 = uis:GetMouseDelta()
	print(ms1)
end)

Here’s a snippet of code from here:

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)

This is for an “Over-the-Shoulder” type of camera, but it can be modified for first person and/or examined for how it uses Delta.

2 Likes