I want to create a camera system like this:
to make one of my games more realistic. How do I do that?
I’ve tried many things but I have got nothing.
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local CameraSettings = {
Sensitivity = {
X = 0.15,
Y = 0.15
},
Angles = {
MaxUp = 80,
MaxDown = -60
},
Position = {
Height = 1.6,
YOffset = 0.25,
ForwardTilt = {
Enabled = true,
Multiplier = 0.45
}
},
Head = {
Size = Vector3.new(0.5, 0.5, 0.5),
Transparency = 0.5
}
}
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local function normalizeAngle(angle)
while angle > 180 do
angle = angle - 360
end
while angle < -180 do
angle = angle + 360
end
return angle
end
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local AssignCollisionGroupEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("SetupEvents"):WaitForChild("CollisionGroup"):WaitForChild("AssignCollisionGroup")
local function createHead(character)
local existingHead = character:FindFirstChild("CameraHead")
if existingHead then
return existingHead
end
local head = Instance.new("Part")
head.Name = "CameraHead"
head.Anchored = true
head.CanCollide = false -- Ensure no physics interaction
head.Transparency = CameraSettings.Head.Transparency
head.Size = CameraSettings.Head.Size
head.Parent = character
character:FindFirstChild("Torso").Neck.Enabled = false
-- Notify the server to assign the head collision group
AssignCollisionGroupEvent:FireServer(head)
return head
end
local function setupCharacter(character : Model)
local humanoidRootPart : Part = character:WaitForChild("HumanoidRootPart")
local humanoid : Humanoid = character:WaitForChild("Humanoid")
local playerHead : Part = character:WaitForChild("Head") -- The player's physical head
camera.CameraType = Enum.CameraType.Scriptable
local head = createHead(character) -- The CameraHead part
local rotX, rotY = 0, 0
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
local function updateRotation(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
rotX = normalizeAngle(rotX - input.Delta.X * CameraSettings.Sensitivity.X)
rotY = math.clamp(
rotY - input.Delta.Y * CameraSettings.Sensitivity.Y,
CameraSettings.Angles.MaxDown,
CameraSettings.Angles.MaxUp
)
end
end
local function updateCameraAndHead()
if not character.Parent or not humanoidRootPart then return end
-- Calculate base position relative to HumanoidRootPart
local basePosition = humanoidRootPart.Position +
Vector3.new(0, CameraSettings.Position.Height + CameraSettings.Position.YOffset, 0)
-- Apply camera rotation
local rotation = CFrame.fromEulerAnglesYXZ(
math.rad(rotY),
math.rad(rotX),
0
)
-- Calculate forward tilt offset
local tiltOffset = Vector3.new(0, 0, 0)
if CameraSettings.Position.ForwardTilt.Enabled then
local tiltAmount = math.sin(math.rad(rotY)) * CameraSettings.Position.ForwardTilt.Multiplier
tiltOffset = rotation:VectorToWorldSpace(
Vector3.new(0, math.abs(tiltAmount), tiltAmount)
)
end
-- Update CameraHead position and rotation
local headCFrame = CFrame.new(basePosition + tiltOffset) * rotation
head.CFrame = headCFrame
-- Update camera to match head
camera.CFrame = headCFrame
-- Attach player's head to CameraHead without affecting the HumanoidRootPart
playerHead.CFrame = headCFrame
end
local connections = {}
table.insert(connections, UserInputService.InputChanged:Connect(updateRotation))
table.insert(connections, RunService.RenderStepped:Connect(updateCameraAndHead))
table.insert(connections, UserInputService.WindowFocused:Connect(function()
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
end))
local function cleanup()
for _, connection in ipairs(connections) do
connection:Disconnect()
end
head:Destroy()
end
character.AncestryChanged:Connect(function(_, parent)
if not parent then
cleanup()
end
end)
end
player.CharacterAdded:Connect(setupCharacter)
if player.Character then
setupCharacter(player.Character)
end