Загрузка данных
--========================================================
-- 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)