Загрузка данных
-- LocalScript
-- Положи в: StarterPlayer > StarterPlayerScripts
-- Управление: Shift - бег, V - переключить вид от 1-го лица / обычная камера
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
-- ========= НАСТРОЙКИ =========
local CFG = {
ToggleKey = Enum.KeyCode.V,
SprintKey = Enum.KeyCode.LeftShift,
WalkSpeed = 16,
SprintSpeed = 26,
BaseFOV = 75,
SprintFOV = 88,
FOVSmooth = 8,
-- покачивание головы (в стадах)
WalkBobFreq = 9,
WalkBobAmp = 0.10,
SprintBobFreq = 13,
SprintBobAmp = 0.20,
-- наклон камеры вбок при шаге (в градусах)
WalkRoll = 0.4,
SprintRoll = 1.0,
-- дрожание камеры при беге (в градусах)
SprintShake = 0.25,
Smooth = 10, -- плавность включения/выключения эффектов
LandKick = 0.35, -- "толчок" камеры при приземлении
-- видимость тела
BodyForward = 0.6, -- насколько камера сдвинута вперёд (чтобы верх торса/плечи не мешали)
BodyUp = 0.05, -- небольшой подъём камеры
}
-- типы аксессуаров на голове/шее, которые надо скрывать
local HIDE_ACCESSORY_TYPES = {
Hat = true, Hair = true, Face = true, Neck = true,
Eyebrow = true, Eyelash = true,
}
-- =============================
local humanoid, root
local firstPerson = true
local sprinting = false
local bobTime = 0
local intensity = 0 -- 0..1, плавно растёт при движении
local sprintBlend = 0 -- 0..1, плавно растёт при беге
local landOffset = 0
local function setFirstPerson(state)
firstPerson = state
if state then
player.CameraMode = Enum.CameraMode.LockFirstPerson
else
player.CameraMode = Enum.CameraMode.Classic
-- отодвигаем камеру назад, чтобы выйти из первого лица
player.CameraMaxZoomDistance = 15
player.CameraMinZoomDistance = 10
task.wait()
player.CameraMinZoomDistance = 0.5
if humanoid then
humanoid.CameraOffset = Vector3.zero
end
end
end
local function setSprint(state)
sprinting = state
if humanoid then
humanoid.WalkSpeed = state and CFG.SprintSpeed or CFG.WalkSpeed
end
end
-- кэш частей тела: [часть] = true, если её надо скрыть (голова и аксессуары на голове)
local bodyParts = {}
local function shouldHide(part)
if part.Name == "Head" then
return true
end
local acc = part:FindFirstAncestorWhichIsA("Accessory")
if acc and HIDE_ACCESSORY_TYPES[tostring(acc.AccessoryType):match("%w+$")] then
return true
end
return false
end
local function register(inst)
if inst:IsA("BasePart") then
task.defer(function()
if inst.Parent then
bodyParts[inst] = shouldHide(inst)
end
end)
end
end
local function onCharacter(char)
bodyParts = {}
for _, d in ipairs(char:GetDescendants()) do
if d:IsA("BasePart") then
bodyParts[d] = shouldHide(d)
end
end
char.DescendantAdded:Connect(register)
char.DescendantRemoving:Connect(function(d)
bodyParts[d] = nil
end)
humanoid = char:WaitForChild("Humanoid")
root = char:WaitForChild("HumanoidRootPart")
humanoid.WalkSpeed = CFG.WalkSpeed
sprinting = false
humanoid.StateChanged:Connect(function(_, new)
if new == Enum.HumanoidStateType.Landed then
landOffset = -CFG.LandKick
end
end)
if firstPerson then
player.CameraMode = Enum.CameraMode.LockFirstPerson
end
end
player.CameraMaxZoomDistance = 15
player.CameraMinZoomDistance = 0.5
setFirstPerson(true)
if player.Character then
task.spawn(onCharacter, player.Character)
end
player.CharacterAdded:Connect(onCharacter)
UserInputService.InputBegan:Connect(function(input, processed)
if processed then return end
if input.KeyCode == CFG.ToggleKey then
setFirstPerson(not firstPerson)
elseif input.KeyCode == CFG.SprintKey then
setSprint(true)
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.KeyCode == CFG.SprintKey then
setSprint(false)
end
end)
local function lerp(a, b, t)
return a + (b - a) * t
end
RunService:BindToRenderStep("FirstPersonFX", Enum.RenderPriority.Camera.Value + 1, function(dt)
if not humanoid or not root or humanoid.Health <= 0 then return end
local alpha = 1 - math.exp(-CFG.Smooth * dt)
-- движение по земле?
local vel = root.AssemblyLinearVelocity
local speed = Vector3.new(vel.X, 0, vel.Z).Magnitude
local onGround = humanoid.FloorMaterial ~= Enum.Material.Air
local moving = speed > 1 and onGround
intensity = lerp(intensity, moving and 1 or 0, alpha)
sprintBlend = lerp(sprintBlend, (sprinting and moving) and 1 or 0, alpha)
-- FOV
local targetFOV = lerp(CFG.BaseFOV, CFG.SprintFOV, sprintBlend)
camera.FieldOfView = lerp(camera.FieldOfView, targetFOV, 1 - math.exp(-CFG.FOVSmooth * dt))
-- эффекты только в первом лице
local isFirst = (camera.CFrame.Position - camera.Focus.Position).Magnitude < 1.5
if not isFirst then
humanoid.CameraOffset = Vector3.zero
return
end
-- показываем тело (руки, торс, ноги, инструменты), скрываем голову и её аксессуары
for part, hide in pairs(bodyParts) do
part.LocalTransparencyModifier = hide and 1 or 0
end
-- сдвигаем камеру вперёд по направлению тела: верх торса и плечи остаются позади камеры,
-- а при взгляде вниз видно нижнюю часть торса и ноги
local look = root.CFrame.LookVector
local flat = Vector3.new(look.X, 0, look.Z)
if flat.Magnitude > 0.01 then
camera.CFrame = camera.CFrame + flat.Unit * CFG.BodyForward + Vector3.new(0, CFG.BodyUp, 0)
end
local freq = lerp(CFG.WalkBobFreq, CFG.SprintBobFreq, sprintBlend)
local amp = lerp(CFG.WalkBobAmp, CFG.SprintBobAmp, sprintBlend)
local roll = lerp(CFG.WalkRoll, CFG.SprintRoll, sprintBlend)
bobTime += dt * freq * (speed / CFG.WalkSpeed) * intensity
-- покачивание вверх-вниз и вбок (как шаги)
local bobY = math.sin(bobTime * 2) * amp * 0.5 * intensity
local bobX = math.cos(bobTime) * amp * 0.6 * intensity
-- приземление
landOffset = lerp(landOffset, 0, 1 - math.exp(-8 * dt))
humanoid.CameraOffset = Vector3.new(bobX, bobY + landOffset, 0)
-- наклон + дрожание
local t = os.clock()
local shake = CFG.SprintShake * sprintBlend
local shakeX = math.noise(t * 14, 0.1) * shake
local shakeY = math.noise(t * 14, 7.3) * shake
local shakeZ = math.noise(t * 11, 3.7) * shake
local rollAngle = math.rad(math.cos(bobTime) * roll * intensity + shakeZ)
local pitchAngle = math.rad(shakeX)
local yawAngle = math.rad(shakeY)
camera.CFrame = camera.CFrame * CFrame.Angles(pitchAngle, yawAngle, rollAngle)
end)