one thing that immediately stood out for me was how the camera was moving.
i would love to recreate this effect somehow but im very inexperienced with advanced camera features like this. if anyone could help that would be amazing!
From what I see, I believe there is an invisible part that is at a distance behind the character, and the character’s speed determines that distance. As the speed increases, the part goes further behind the character. The CurrentCamera’s CameraSubject is then set to the part to achieve the effect in the video.
Another way is to set the Humanoid’s CameraOffset dependant on the speed, which could be easier to program.
If you need help programming any of the systems, I can give you some tips.
By modifying the Z axis of the CameraOffset, we can choose how far back to move the camera. Keep in mind you need to store the HumanoidRootPart and Humanoid as variables, and the script must be a LocalScript in order to modify the camera.
The system also looks like it modifies the camera’s FieldOfView, so you may need to add that into the script.
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
-- CONFIG
local MIN_FOV = 70
local MAX_FOV = 115
local MAX_SPEED = 300
local FOV_SMOOTH = 0.15
local TILT_SMOOTH = 0.15
local MAX_TILT = math.rad(10)
local CAMERA_Z_OFFSET_FACTOR = 1 / 20
-- STATE
local isActive = false
local currentFOV = MIN_FOV
local currentTilt = 0
camera.CameraType = Enum.CameraType.Custom
ReplicatedStorage:WaitForChild("SuperSpeedFX").OnClientEvent:Connect(function(state)
isActive = state
if not state then
currentFOV = MIN_FOV
currentTilt = 0
camera.FieldOfView = MIN_FOV
local char = player.Character
local hum = char and char:FindFirstChildOfClass("Humanoid")
if hum then
hum.CameraOffset = Vector3.zero
end
end
end)
RunService.RenderStepped:Connect(function()
if not isActive then return end
local char = player.Character
local humanoid = char and char:FindFirstChildWhichIsA("Humanoid")
local hrp = char and char:FindFirstChild("HumanoidRootPart")
if not humanoid or not hrp then return end
local speed = hrp.AssemblyLinearVelocity.Magnitude
local moveDir = humanoid.MoveDirection
-- FOV
local targetFOV = MIN_FOV + (speed / MAX_SPEED) * (MAX_FOV - MIN_FOV)
currentFOV += (targetFOV - currentFOV) * FOV_SMOOTH
camera.FieldOfView = currentFOV
-- Tilt
local strafe = moveDir:Dot(camera.CFrame.RightVector)
local targetTilt = -strafe * MAX_TILT
currentTilt += (targetTilt - currentTilt) * TILT_SMOOTH
-- Apply tilt
local camPos = camera.CFrame.Position
local camLook = camera.CFrame.LookVector
camera.CFrame = CFrame.new(camPos, camPos + camLook) * CFrame.Angles(0, 0, currentTilt)
humanoid.CameraOffset = Vector3.new(0, 0, speed * CAMERA_Z_OFFSET_FACTOR)
end)
You can increase the divisor to make it smoother, or incorporate tweening instead of directly setting the CameraOffset, since it looks like it’s adjusting too quickly.
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
-- CONFIG
local MIN_FOV = 70
local MAX_FOV = 115
local MAX_SPEED = 300
local FOV_SMOOTH = 0.15
local TILT_SMOOTH = 0.15
local MAX_TILT = math.rad(10)
local CAMERA_Z_OFFSET_FACTOR = 1 / 40
-- STATE
local isActive = false
local currentFOV = MIN_FOV
local currentTilt = 0
camera.CameraType = Enum.CameraType.Custom
ReplicatedStorage:WaitForChild("SuperSpeedFX").OnClientEvent:Connect(function(state)
isActive = state
if not state then
currentFOV = MIN_FOV
currentTilt = 0
camera.FieldOfView = MIN_FOV
local char = player.Character
local hum = char and char:FindFirstChildOfClass("Humanoid")
if hum then
hum.CameraOffset = Vector3.zero
end
end
end)
RunService.RenderStepped:Connect(function()
if not isActive then return end
local char = player.Character
local humanoid = char and char:FindFirstChildWhichIsA("Humanoid")
local hrp = char and char:FindFirstChild("HumanoidRootPart")
if not humanoid or not hrp then return end
local speed = hrp.AssemblyLinearVelocity.Magnitude
local moveDir = humanoid.MoveDirection
-- FOV
local targetFOV = MIN_FOV + (speed / MAX_SPEED) * (MAX_FOV - MIN_FOV)
currentFOV += (targetFOV - currentFOV) * FOV_SMOOTH
camera.FieldOfView = currentFOV
-- Tilt
local strafe = moveDir:Dot(camera.CFrame.RightVector)
local targetTilt = -strafe * MAX_TILT
currentTilt += (targetTilt - currentTilt) * TILT_SMOOTH
-- Apply tilt
local camPos = camera.CFrame.Position
local camLook = camera.CFrame.LookVector
camera.CFrame = CFrame.new(camPos, camPos + camLook) * CFrame.Angles(0, 0, currentTilt)
local currentOffset = humanoid.CameraOffset
local targetOffset = Vector3.new(0, 0, speed * CAMERA_Z_OFFSET_FACTOR)
humanoid.CameraOffset = currentOffset:Lerp(targetOffset, 0.15)
end)
i have tried that but i aint the best at that so it didnt work. could you maybe help. ive tweaked the code a bit and i think im close. there are just some things that arent the best. such as the players character can get too far from the camera and when you run backwards the character gets out of sight like i showed in the video.
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local MIN_FOV = 70
local MAX_FOV = 100
local MAX_SPEED = 300
local FOV_SMOOTH = 0.1
local TILT_SMOOTH = 0.5
local MAX_TILT = math.rad(14)
local CAMERA_Z_OFFSET_FACTOR = 1 / 35
local CAMERA_X_OFFSET = 2
local CAMERA_LAG_SPEED = 0.1
local isActive = false
local currentFOV = MIN_FOV
local currentTilt = 0
local currentCamPos = nil
camera.CameraType = Enum.CameraType.Custom
ReplicatedStorage:WaitForChild("SuperSpeedFX").OnClientEvent:Connect(function(state)
isActive = state
if not state then
currentFOV = MIN_FOV
currentTilt = 0
camera.FieldOfView = MIN_FOV
currentCamPos = nil
local char = player.Character
local hum = char and char:FindFirstChildOfClass("Humanoid")
if hum then
hum.CameraOffset = Vector3.zero
end
end
end)
-- Main camera logic
RunService.RenderStepped:Connect(function(dt)
if not isActive then return end
local char = player.Character
local humanoid = char and char:FindFirstChildWhichIsA("Humanoid")
local hrp = char and char:FindFirstChild("HumanoidRootPart")
if not humanoid or not hrp then return end
local speed = hrp.AssemblyLinearVelocity.Magnitude
local targetFOV = MIN_FOV + (speed / MAX_SPEED) * (MAX_FOV - MIN_FOV)
currentFOV += (targetFOV - currentFOV) * FOV_SMOOTH
camera.FieldOfView = currentFOV
local camRight = camera.CFrame.RightVector
local lateral = hrp.AssemblyLinearVelocity:Dot(camRight)
local targetTilt = -math.clamp(lateral / 30, -1, 1) * MAX_TILT
local tiltDelta = targetTilt - currentTilt
currentTilt += tiltDelta * (TILT_SMOOTH * dt) * 2
local currentOffset = humanoid.CameraOffset
local targetOffset = Vector3.new(CAMERA_X_OFFSET, 0, speed * CAMERA_Z_OFFSET_FACTOR)
humanoid.CameraOffset = currentOffset:Lerp(targetOffset, 0.15)
local desiredCamPos = camera.CFrame.Position
if not currentCamPos then
currentCamPos = desiredCamPos
end
currentCamPos = currentCamPos:Lerp(desiredCamPos, CAMERA_LAG_SPEED)
local camLook = camera.CFrame.LookVector
camera.CFrame = CFrame.new(currentCamPos, currentCamPos + camLook) * CFrame.Angles(0, 0, currentTilt)
end)