A quick note: This is NOT shift lock. You can see from the first example in the DevForum post that the character can turn towards the camera and walk towards the camera for the camera to back up, which isn't possible with shift lock.
https://devforum.roblox.com/t/3rd-person-camera-similar-to-polyguns/385168
NOTE: This will glitch out when you are in roblox studio, so when you press play, and it doesn't work, just stop it and play it again.
I've actually managed to do this w/ help of the people on the devforums. Create 2 local scripts in StarterPlayer> StarterPlayerScripts. Name them what you would like. ( I named the first one CamOffset, and the second one MouseLock.)
The CamOffset Script will make it so you get a shoulder view perspective. The mouse lock makes it so you don't need to right click to look around.
Code in CamOffset:
------------- --- INDEX --- ------------- --Services local userInputService = game:GetService("UserInputService") local runService = game:GetService("RunService") --Player & Character local localPlayer = game:GetService("Players").LocalPlayer --Other local Camera = game:GetService("Workspace").CurrentCamera -------------- --- VALUES --- -------------- local xAngle = 0 local yAngle = 0 local cameraPos = Vector3.new(3.5,0,7.5) ---------------------- --- INITIALIZATION --- ---------------------- wait(1) Camera.CameraType = Enum.CameraType.Scriptable userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter ----------------- --- FUNCTIONS --- ----------------- userInputService.InputChanged:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then xAngle = xAngle-input.Delta.x*0.4 --Clamp the vertical axis so it doesn't go upside down or glitch. yAngle = math.clamp(yAngle-input.Delta.y*0.4,-80,80) end end) runService.RenderStepped:Connect(function() local Character = localPlayer.Character local rootPart = Character:FindFirstChild("HumanoidRootPart") if Character and rootPart then --Set rotated start cframe inside head local startCFrame = CFrame.new((rootPart.CFrame.p + Vector3.new(0,2,0)))*CFrame.Angles(0, math.rad(xAngle), 0)*CFrame.Angles(math.rad(yAngle), 0, 0) --Set camera focus and cframe local cameraCFrame = startCFrame + startCFrame:vectorToWorldSpace(Vector3.new(cameraPos.X,cameraPos.Y,cameraPos.Z)) local cameraFocus = startCFrame + startCFrame:vectorToWorldSpace(Vector3.new(cameraPos.X,cameraPos.Y,-50000)) Camera.CFrame = CFrame.new(cameraCFrame.p,cameraFocus.p) end end)
Code In MouseLock:
local SENSITIVITY = 100 local DISTANCE_Y = 3 local DISTANCE_Z = 12 local BEHAVIOR_LOCK_CENTER = Enum.MouseBehavior.LockCenter local BEHAVIOR_DEFAULT = Enum.MouseBehavior.Default local TYPE_MOUSE_MOVEMENT = Enum.UserInputType.MouseMovement local UserInputService = game:GetService("UserInputService") local Camera = workspace.CurrentCamera local HumanoidRootPart = game:GetService("Players").LocalPlayer.Character.HumanoidRootPart -- Property for changing whether player can move mouse freely or not local IsLocked = false -- X and Y values for camera local X, Y = 0, 0 UserInputService.InputChanged:Connect(function(InputObject) if InputObject.UserInputType == TYPE_MOUSE_MOVEMENT then local Delta = InputObject.Delta X = X + (Delta.Y / SENSITIVITY) Y = math.clamp(Y + (Delta.Y / SENSITIVITY), -1, 1.5) end end) game:GetService("RunService").RenderStepped:Connect(function() if IsLocked then UserInputService.MouseBehavior = BEHAVIOR_LOCK_CENTER else UserInputService.MouseBehavior = BEHAVIOR_DEFAULT end Camera.CoordinateFrame = CFrame.new(HumanoidRootPart.Position) * CFrame.Angles(0, X, 0) * CFrame.Angles(Y, 0, 0) * CFrame.new(0, DISTANCE_Y, DISTANCE_Z) end)
And that should be it.