Hello recently I found this script in the toolbox and it works really good, but I don’t understand the code much. Can someone explain the code? Or help simplify the code. Also is this the best code? Is there an easier way or is there any bad practices in this code? Also how can I adjust the settings in the code? Any help is appreciated!
Script:
--by @mvyasu
--March 11 2023
--This script was made for LockFirstPerson
--You can turn this on by setting StarterPlayer.CameraMode to LockFirstPerson
--This will only work if this script is located here:
--StarterPlayer > StarterCharacterScripts
local FIRST_LAST_OFFSET = 2000
local Player = game.Players.LocalPlayer
local PlayerScripts = Player:WaitForChild("PlayerScripts", 10)
local PlayerModule = PlayerScripts and PlayerScripts:WaitForChild("PlayerModule", 10)
local CameraInput = PlayerModule and PlayerModule:FindFirstChild("CameraInput", true)
local getRotation = if CameraInput then require(CameraInput).getRotation else nil
local resetInputForFrameEnd = if CameraInput then require(CameraInput).resetInputForFrameEnd else nil
--this technique requires CameraInput underneath PlayerModule to get the camera input
--otherwise a lot of work would need to be done to replicate the camera input
--if CameraInput changes in the future, this could potentially break
if getRotation==nil then
error("[SimpleCameraDelay]: PlayerModule.CameraModule.CameraInput or CameraInput.getRotation does not exist!")
end
local RunService = game:GetService("RunService")
local Camera = workspace.CurrentCamera
local Character = script.Parent.Parent
local Humanoid = Character:WaitForChild("Humanoid") :: Humanoid
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart") :: BasePart
local function lerp(currentValue: any, goalValue: any, alpha: number)
return currentValue + (goalValue - currentValue) * alpha
end
local function getRotationInputVectorFromCFrame(cframe: CFrame)
local _, _, priorCFrameRotZ = cframe:ToOrientation()
local rotationWithoutZ = cframe * CFrame.Angles(0, 0, -priorCFrameRotZ)
local priorCFrameRotX, priorCFrameRotY = rotationWithoutZ:ToOrientation()
return Vector2.new(priorCFrameRotY, priorCFrameRotX)
end
--currentPosition (and currentRotation depending on what VerticalAngleConstraint is set to) can be insanely large numbers
--because they never loop around. Could this be a problem in the future?
local currentPosition = Camera.CFrame.Position
local currentRotation = getRotationInputVectorFromCFrame(Camera.CFrame)
local targetPosition = currentPosition
local targetRotation = currentRotation
local forceInstantFrameCount = 2
local lastRenderStepCFrame = Camera.CFrame
local cachedCameraInputRotation = Vector2.zero
RunService:BindToRenderStep("CameraDelay_CompareLastRenderStepCFrame", Enum.RenderPriority.First.Value - FIRST_LAST_OFFSET, function()
do --handles setting the rotation input based from a scripted cframe
local startCFrame = Camera.CFrame
local wasCFrameScriptedBeforeFrame = startCFrame~=lastRenderStepCFrame
if wasCFrameScriptedBeforeFrame and Camera.CameraType~=Enum.CameraType.Scriptable then
local scriptedRotation = getRotationInputVectorFromCFrame(startCFrame)
targetRotation = scriptedRotation
currentRotation = targetRotation
forceInstantFrameCount = 2
end
end
--we need to steal the current rotation input from the CameraInput module found in the PlayerModule
--but we need to do it before the CameraModule resets the input, at least for the mouse
--that's why this needs to happen before the CameraModule changes the camera's CFrame
do --handles camera input related stuff
cachedCameraInputRotation = getRotation()
--this will break zooming, but it eliminates the
--camera's position jittering when the custom sensitivity is 0 for whatever reason
local currentCameraSensitivity = script:GetAttribute("CameraSensitivity") or 1
if resetInputForFrameEnd and Player.CameraMode==Enum.CameraMode.LockFirstPerson and currentCameraSensitivity==0 then
--since this the case, this will only be done if the
--player's CameraMode is locked to first person
resetInputForFrameEnd()
end
end
end)
RunService:BindToRenderStep("CameraDelay_AdjustCamera", Enum.RenderPriority.Camera.Value + 1, function(dt: number)
if Camera.CameraType==Enum.CameraType.Scriptable then
forceInstantFrameCount = 2
return
end
local currentVerticalAngleConstraint = script:GetAttribute("VerticalAngleConstraint") or NumberRange.new(-80, 80)
local currentCameraPositionDelay = script:GetAttribute("CameraPositionDelay") or 1
local currentCameraRotationDelay = script:GetAttribute("CameraRotationDelay") or 1
local currentCameraDelayScale = script:GetAttribute("CameraDelayScale") or 1
local currentCameraSensitivity = script:GetAttribute("CameraSensitivity") or 1
local deltaTimeUpscaled = dt * 60
targetPosition = Camera.CFrame.Position
targetRotation += -cachedCameraInputRotation * currentCameraSensitivity
targetRotation = Vector2.new(targetRotation.X, math.clamp(targetRotation.Y, math.rad(currentVerticalAngleConstraint.Min), math.rad(currentVerticalAngleConstraint.Max)))
local positionDelay = math.max(currentCameraPositionDelay * currentCameraDelayScale, 0)
local rotationDelay = math.max(currentCameraRotationDelay * currentCameraDelayScale, 0)
currentPosition = lerp(currentPosition, targetPosition, if positionDelay==0 then 1 else 0.1 * deltaTimeUpscaled * 1/positionDelay)
currentRotation = lerp(currentRotation, targetRotation, if rotationDelay==0 then 1 else 0.1 * deltaTimeUpscaled * 1/rotationDelay)
--for whatever reason, the CFrame for the camera doesn't seem to be set immediately
--in certain circumstances.. so we need to do this for two frames instead of one
if forceInstantFrameCount>0 then
forceInstantFrameCount -= 1
currentPosition = targetPosition
currentRotation = targetRotation
end
Camera.CFrame = CFrame.new(currentPosition) * CFrame.Angles(0, currentRotation.X, 0) * CFrame.Angles(currentRotation.Y, 0, 0)
end)
RunService:BindToRenderStep("CameraDelay_SetLastRenderStepCFrame", Enum.RenderPriority.Last.Value + FIRST_LAST_OFFSET, function()
lastRenderStepCFrame = Camera.CFrame
end)
Thank you.