Загрузка данных
--========================================================
-- REALISTIC CAMERA SYSTEM
-- Расположение: StarterPlayer > StarterPlayerScripts
-- Тип: LocalScript
--
-- F = переключение первого / третьего лица
-- CTRL = бег
--
-- В первом лице тело и аксессуары скрыты локально.
-- Остальные игроки продолжают видеть персонажа.
--
-- FOV: 90 при ходьбе, 120 при беге.
-- Усталость после 90 секунд непрерывного бега.
-- Затемнение к 120 секундам.
--========================================================
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.025,
WalkBobY = 0.035,
SprintBobX = 0.045,
SprintBobY = 0.060,
WalkRoll = 0.2,
SprintRoll = 0.45,
BobSmooth = 7,
TurnSwayAmount = 0.35,
TurnSwaySmooth = 8,
FatigueStart = 90,
FatigueFull = 120,
FatigueBobMultiplier = 1.7,
FatigueFOVReduction = 5,
DarknessStart = 110,
MaxDarkness = 0.16,
}
--========================================================
-- СОСТОЯНИЕ
--========================================================
local character
local humanoid
local rootPart
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 updateBodyVisibility()
if not character then
return
end
for _, object in ipairs(character:GetDescendants()) do
if object:IsA("BasePart") then
-- Не скрываем предметы в руках,
-- если это Tool, экипированный персонажем.
local ancestor = object.Parent
local belongsToTool = false
while ancestor and ancestor ~= character do
if ancestor:IsA("Tool") then
belongsToTool = true
break
end
ancestor = ancestor.Parent
end
if not belongsToTool then
if firstPerson then
object.LocalTransparencyModifier = 1
else
object.LocalTransparencyModifier = 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
updateBodyVisibility()
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")
sprintHeld = false
sprintTime = 0
bobTime = 0
currentFOV = CONFIG.WalkFOV
bobAmount = 0
turnSway = 0
previousYaw = nil
humanoid.WalkSpeed = CONFIG.WalkSpeed
setCameraMode()
table.insert(
characterConnections,
character.DescendantAdded:Connect(function(object)
if object:IsA("BasePart") then
task.defer(updateBodyVisibility)
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
----------------------------------------------------
-- ЗАТЕМНЕНИЕ
----------------------------------------------------
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
----------------------------------------------------
-- ПОВТОРНО ПРИМЕНЯЕМ ЛОКАЛЬНУЮ ВИДИМОСТЬ
----------------------------------------------------
-- Roblox может менять прозрачность частей тела
-- при обновлении стандартной камеры.
updateBodyVisibility()
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)