Загрузка данных


--========================================================
-- REALISTIC CAMERA + SPRINT + FATIGUE
-- StarterPlayer > StarterPlayerScripts > LocalScript
--
-- F     = переключение первого / третьего лица
-- CTRL  = бег
--
-- Голова скрыта только локально в первом лице.
-- Остальные игроки продолжают видеть голову.
--========================================================
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
-- НАСТРОЙКИ
local CONFIG = {
    WalkSpeed = 16,
    SprintSpeed = 24,
    WalkFOV = 90,
    SprintFOV = 120,
    FOVSmooth = 6,
    ThirdPersonMinZoom = 8,
    ThirdPersonMaxZoom = 12,
    WalkFrequency = 8,
    SprintFrequency = 11,
    WalkBobX = 0.035,
    WalkBobY = 0.045,
    SprintBobX = 0.055,
    SprintBobY = 0.075,
    WalkRoll = 0.25,
    SprintRoll = 0.5,
    BobSmooth = 6,
    TurnSwayAmount = 0.45,
    TurnSwaySmooth = 8,
    FatigueStart = 90,
    FatigueFull = 120,
    FatigueBobMultiplier = 1.7,
    FatigueFOVReduction = 5,
    DarknessStart = 110,
    MaxDarkness = 0.16,
}
-- СОСТОЯНИЕ
local character
local humanoid
local rootPart
local head
local firstPerson = true
local sprintHeld = false
local sprintTime = 0
local bobTime = 0
local currentFOV = CONFIG.WalkFOV
local bobAmount = 0
local turnSway = 0
local previousYaw
local characterConnections = {}
--========================================================
-- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
--========================================================
local function smooth(current, target, speed, dt)
    local alpha = 1 - math.exp(-speed * dt)
    return current + (target - current) * alpha
end
local function wrapAngle(angle)
    return math.atan2(math.sin(angle), math.cos(angle))
end
local function getYaw(camera)
    local look = camera.CFrame.LookVector
    return math.atan2(-look.X, -look.Z)
end
local function getHorizontalSpeed()
    if not rootPart then
        return 0
    end
    local velocity = rootPart.AssemblyLinearVelocity
    return Vector3.new(
        velocity.X,
        0,
        velocity.Z
    ).Magnitude
end
--========================================================
-- СКРЫТИЕ ГОЛОВЫ ТОЛЬКО ДЛЯ СЕБЯ
--========================================================
local function updateHeadVisibility()
    if not character or not head then
        return
    end
    -- LocalTransparencyModifier действует локально:
    -- другие игроки по-прежнему видят голову.
    head.LocalTransparencyModifier = firstPerson and 1 or 0
    -- Скрываем аксессуары, прикреплённые к голове.
    local headAttachments = {}
    for _, item in ipairs(head:GetChildren()) do
        if item:IsA("Attachment") then
            headAttachments[item.Name] = true
        end
    end
    for _, accessory in ipairs(character:GetChildren()) do
        if accessory:IsA("Accessory") then
            local handle = accessory:FindFirstChild("Handle")
            if handle and handle:IsA("BasePart") then
                local attachedToHead = false
                for _, item in ipairs(handle:GetChildren()) do
                    if item:IsA("Attachment")
                        and headAttachments[item.Name] then
                        attachedToHead = true
                        break
                    end
                end
                if attachedToHead then
                    handle.LocalTransparencyModifier =
                        firstPerson and 1 or 0
                end
            end
        end
    end
end
--========================================================
-- ПЕРЕКЛЮЧЕНИЕ КАМЕРЫ
--========================================================
local function setCameraMode()
    if firstPerson then
        player.CameraMode = Enum.CameraMode.LockFirstPerson
        player.CameraMinZoomDistance = 0.5
        player.CameraMaxZoomDistance = 0.5
    else
        player.CameraMode = Enum.CameraMode.Classic
        player.CameraMinZoomDistance = CONFIG.ThirdPersonMinZoom
        player.CameraMaxZoomDistance = CONFIG.ThirdPersonMaxZoom
    end
    local camera = workspace.CurrentCamera
    if camera and humanoid then
        camera.CameraType = Enum.CameraType.Custom
        camera.CameraSubject = humanoid
    end
    updateHeadVisibility()
end
local function toggleCamera()
    firstPerson = not firstPerson
    setCameraMode()
end
--========================================================
-- ЗАТЕМНЕНИЕ ЭКРАНА
--========================================================
local playerGui = player:WaitForChild("PlayerGui")
local oldGui = playerGui:FindFirstChild("RealisticCameraEffects")
if oldGui then
    oldGui:Destroy()
end
local screenGui = Instance.new("ScreenGui")
screenGui.Name = "RealisticCameraEffects"
screenGui.IgnoreGuiInset = true
screenGui.ResetOnSpawn = false
screenGui.DisplayOrder = 10
screenGui.Parent = playerGui
local darkness = Instance.new("Frame")
darkness.Name = "FatigueDarkness"
darkness.Size = UDim2.fromScale(1, 1)
darkness.Position = UDim2.fromScale(0, 0)
darkness.BackgroundColor3 = Color3.new(0, 0, 0)
darkness.BackgroundTransparency = 1
darkness.BorderSizePixel = 0
darkness.Parent = screenGui
--========================================================
-- НАСТРОЙКА ПЕРСОНАЖА
--========================================================
local function disconnectCharacterConnections()
    for _, connection in ipairs(characterConnections) do
        connection:Disconnect()
    end
    table.clear(characterConnections)
end
local function setupCharacter(newCharacter)
    disconnectCharacterConnections()
    character = newCharacter
    humanoid = character:WaitForChild("Humanoid")
    rootPart = character:WaitForChild("HumanoidRootPart")
    head = character:WaitForChild("Head")
    sprintHeld = false
    sprintTime = 0
    bobTime = 0
    currentFOV = CONFIG.WalkFOV
    bobAmount = 0
    turnSway = 0
    previousYaw = nil
    humanoid.WalkSpeed = CONFIG.WalkSpeed
    setCameraMode()
    table.insert(
        characterConnections,
        character.ChildAdded:Connect(function(item)
            if item:IsA("Accessory") then
                task.defer(updateHeadVisibility)
            end
        end)
    )
    table.insert(
        characterConnections,
        humanoid.Died:Connect(function()
            sprintHeld = false
            sprintTime = 0
            darkness.BackgroundTransparency = 1
        end)
    )
end
player.CharacterAdded:Connect(setupCharacter)
if player.Character then
    task.spawn(setupCharacter, player.Character)
end
--========================================================
-- УПРАВЛЕНИЕ
--========================================================
UserInputService.InputBegan:Connect(function(input, processed)
    if processed then
        return
    end
    if input.KeyCode == Enum.KeyCode.F then
        toggleCamera()
    elseif input.KeyCode == Enum.KeyCode.LeftControl then
        sprintHeld = true
    end
end)
UserInputService.InputEnded:Connect(function(input)
    if input.KeyCode == Enum.KeyCode.LeftControl then
        sprintHeld = false
    end
end)
UserInputService.WindowFocusReleased:Connect(function()
    sprintHeld = false
end)
--========================================================
-- ОБНОВЛЕНИЕ КАМЕРЫ
--========================================================
RunService:BindToRenderStep(
    "RealisticCameraEffects",
    Enum.RenderPriority.Camera.Value + 1,
    function(dt)
        if not character
            or not humanoid
            or not rootPart
            or humanoid.Health <= 0 then
            return
        end
        local camera = workspace.CurrentCamera
        if not camera then
            return
        end
        -- ДВИЖЕНИЕ
        local speed = getHorizontalSpeed()
        local moving =
            humanoid.MoveDirection.Magnitude > 0.05
            and speed > 0.5
        local sprinting = sprintHeld and moving
        if sprinting then
            humanoid.WalkSpeed = CONFIG.SprintSpeed
            sprintTime += dt
        else
            humanoid.WalkSpeed = CONFIG.WalkSpeed
            sprintTime = 0
        end
        -- УСТАЛОСТЬ
        local fatigue = math.clamp(
            (sprintTime - CONFIG.FatigueStart)
                / (CONFIG.FatigueFull - CONFIG.FatigueStart),
            0,
            1
        )
        -- FOV
        local targetFOV = sprinting
            and CONFIG.SprintFOV
            or CONFIG.WalkFOV
        targetFOV -= fatigue * CONFIG.FatigueFOVReduction
        currentFOV = smooth(
            currentFOV,
            targetFOV,
            CONFIG.FOVSmooth,
            dt
        )
        camera.FieldOfView = currentFOV
        -- ЗАТЕМНЕНИЕ ПОСЛЕ 110 СЕКУНД
        local darknessAmount = 0
        if sprintTime > CONFIG.DarknessStart then
            local progress = math.clamp(
                (sprintTime - CONFIG.DarknessStart)
                    / (CONFIG.FatigueFull - CONFIG.DarknessStart),
                0,
                1
            )
            darknessAmount = progress * CONFIG.MaxDarkness
        end
        darkness.BackgroundTransparency = 1 - darknessAmount
        -- ПОКАЧИВАНИЕ КАМЕРЫ
        local targetBob = moving
            and math.clamp(speed / CONFIG.SprintSpeed, 0, 1)
            or 0
        bobAmount = smooth(
            bobAmount,
            targetBob,
            CONFIG.BobSmooth,
            dt
        )
        local frequency = sprinting
            and CONFIG.SprintFrequency
            or CONFIG.WalkFrequency
        local bobX = 0
        local bobY = 0
        local bobRoll = 0
        if bobAmount > 0.001 then
            bobTime += dt * frequency
            local xAmplitude = sprinting
                and CONFIG.SprintBobX
                or CONFIG.WalkBobX
            local yAmplitude = sprinting
                and CONFIG.SprintBobY
                or CONFIG.WalkBobY
            local rollAmplitude = sprinting
                and CONFIG.SprintRoll
                or CONFIG.WalkRoll
            local fatigueMultiplier =
                1 + fatigue * (CONFIG.FatigueBobMultiplier - 1)
            bobX =
                math.cos(bobTime * 0.5)
                * xAmplitude
                * bobAmount
                * fatigueMultiplier
            bobY =
                math.sin(bobTime * 2)
                * yAmplitude
                * bobAmount
                * fatigueMultiplier
            bobRoll =
                math.sin(bobTime)
                * math.rad(rollAmplitude)
                * bobAmount
                * fatigueMultiplier
        end
        -- ИНЕРЦИЯ ПРИ ПОВОРОТАХ
        local yaw = getYaw(camera)
        local yawDelta = 0
        if previousYaw then
            yawDelta = wrapAngle(yaw - previousYaw)
        end
        previousYaw = yaw
        local targetSway = math.clamp(
            -yawDelta * CONFIG.TurnSwayAmount * 60,
            -0.025,
            0.025
        )
        turnSway = smooth(
            turnSway,
            targetSway,
            CONFIG.TurnSwaySmooth,
            dt
        )
        -- ДЫХАНИЕ ПРИ УСТАЛОСТИ
        local breathing =
            math.sin(os.clock() * 2.4)
            * 0.012
            * fatigue
        -- ПРИМЕНЕНИЕ ЭФФЕКТОВ
        local offset = CFrame.new(
            bobX + turnSway,
            bobY + breathing,
            0
        ) * CFrame.Angles(
            0,
            0,
            bobRoll
        )
        -- Добавляем небольшое смещение после стандартной камеры.
        camera.CFrame = camera.CFrame * offset
    end
)
--========================================================
-- СМЕНА CURRENTCAMERA
--========================================================
workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
    local camera = workspace.CurrentCamera
    if camera and humanoid then
        camera.CameraType = Enum.CameraType.Custom
        camera.CameraSubject = humanoid
    end
end)
--========================================================
-- ОЧИСТКА
--========================================================
script.Destroying:Connect(function()
    RunService:UnbindFromRenderStep("RealisticCameraEffects")
    disconnectCharacterConnections()
    if humanoid and humanoid.Parent then
        humanoid.WalkSpeed = CONFIG.WalkSpeed
    end
    player.CameraMode = Enum.CameraMode.Classic
    player.CameraMinZoomDistance = 0.5
    player.CameraMaxZoomDistance = 12
end)